Yes, I think it's possible to do so since the IoC container is using reflection class..it knows the caller.
I can't give you exactly how it can be done since it will involve many modifications to the current IoC container depending on how you want it done.
However, I think I have a few workarounds.
Modified function from http://www.neontsunami.com/post/getting-the-controller-and-action-in-laravel-4
function getCurrentController()
{
$routeArray = Str::parseCallback(Route::currentRouteAction(), null);
if (last($routeArray) != null) {
// Remove 'controller' from the controller name.
$controller = str_replace('Controller', '', class_basename(head($routeArray)));
return $controller;
}
return 'closure';
}
App::bind("RepositoryInterface", function($app) {
switch (getCurrentController()) {
case 'Concrete':
$repository = 'Namespace\Repos\RepositoryClass1';
break;
case 'Another':
$repository = 'Namespace\Repos\RepositoryClass2';
break;
default:
throw new InvalidArgumentException("a message");
break;
}
return App::make($repository);
});
depending on your use case, this is really not a good idea since you can't use these repositories in other classes, but i think it gives you an idea at least.
This is almost like...a service location, but I think it probably is okay for a few classes. I rather use this approach than #1 if I were you.
IoC bindings are usually made in service providers, however you can't call Route::currentRouteAction()
from there. It will throw an error because the route isn't defined yet.
When should he make this binding, in a before filter? If you wanted to do 'dynamic bindings' in the service provider it would have to be based on something like the request object, not the route object.
What you bind is being decided well before the script execution reaches the controller, do you really need this kind of dynamic binding? In general, multiple classes can implement single interfaces anyways, that's not a problem.
@AnthonyVipond // Ah, you're right. I only tested it in my routes, but it gives you an idea anyway lol
I don't really think he doesn't understand your last statement. Based on his writing, my best guess is that he's looking for something that you can do in c# something like container.Register<ISocialNetwork, Twitter>("Twitter"); where you bind multiple instances to an interface.
Heh, no worries. Your code wasn't wrong it just couldn't be done in a service provider. You could do something down that line based on the route object within a before filter, but that should probably be avoided at all costs because its adding a lot of complexity.
So I don't think its possible to do what OP wants. The 'caller' will always be App::bind() and while you could bind something conditionally with a closure as the second argument, at least if its in a service provider, any information on the route or controller is not yet known.
Interestingly it seems you can pass an array as the first argument of App::bind() but its just a simple hash of the binding and the alias.
@AnthonyVipond // Totally agree on your point. I didn't even think of using a filter though. I will try out just for fun. Thanks!
Thanks Anthony and Moon, only was a question related with this possibility. I put this sample code with the array in the bind method but I didn't try to use, It was a suggest.
The question is by example, several code give us the sample App where you choose different payment options to implement using the IoC as follow:
$app->bind('PaymentInterface','PaypalConcretePayment');
Or
$app->bind('PaymentInterface','AnotherConcretePayment');
If you want give all user the both options at time?
Thanks for all.
$app->tag(['SpeedReport', 'MemoryReport'], 'reports');
$app->bind('ReportAggregator', function($app)
{
return new ReportAggregator($app->tagged('reports'));
});
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community