Support the ongoing development of Laravel.io →
IOC Architecture
Last updated 2 years ago.
0

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.

  1. A Hack !!!

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.

  1. Return a factory instead of a single class and let the controller get what they want.

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.

Last updated 2 years ago.
0

@moon0326

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.

@codeAtBusiness

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.

Last updated 2 years ago.
0

@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.

Last updated 2 years ago.
0

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.

Last updated 2 years ago.
0

@AnthonyVipond // Totally agree on your point. I didn't even think of using a filter though. I will try out just for fun. Thanks!

Last updated 2 years ago.
0

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.

Last updated 2 years ago.
0
$app->tag(['SpeedReport', 'MemoryReport'], 'reports');

$app->bind('ReportAggregator', function($app)
{
    return new ReportAggregator($app->tagged('reports'));
});

http://laravel.com/docs/5.0/container#tagging

Last updated 8 years ago.
0

Sign in to participate in this thread!

Eventy

Your banner here too?

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.