-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.0] Added contextual binding on methods test #8906
Conversation
Hmm, I don't think I ever intended it to really work on methods, although it is an interesting use case. |
I've come across a situation where I feel like it would be the cleanest way to handle things: http://stackoverflow.com/questions/30477611/laravel-5-0-application-structure Perhaps there's a better way of handling that specific scenario, but I still feel like it could be useful. If it was an easy change then it would be great to have. |
Going to close this as it was never really an intended use case. |
@taylorotwell Common use case would be now with laravel 5.1 where are self handling jobs. This Example wont work, because there is no Contextual binding for methods:
|
@taylorotwell I agree with @ddctd143 that as self-handling jobs are now pushed as the norm it should be possible to do contextual dependency injection into the handle method. The current setup is strange because one type of binding works while another doesn't. It's not expected behavior as a user. The same sentiment can be found here #6177 |
Yes I can definitely see a use case there. How hard is it to get the contextual binding to work at a method level? |
@taylorotwell My understanding of the internals of Illuminate/Container isn't good enough to give you a straight answer on that. However, I can outline two types of behavior, the first being what might be the expected behavior now and the second probably being more complex to implement but a feature for the future. 1 Class based method contextual binding: i.e, A class is bound to a particular concrete implementation and methods on that class are all given the same injection if they ask for it.
MyClass@method(MyServiceInterface $myService) gets MyService injected. This is more or less as we understand the current binding system. To enable this I assume the Container needs to be modified so that it checks the contextual binding map for a method's parent class when it resolves the dependencies for that method. 2 Class@method based method contextual binding: i.e, A Class@method is bound to a particular concrete implementation and that specific method is given that dependency when it asks for it.
This would allow another method on a particular class to have the same dependency hinted but get a different implementation. More of an edge use case than the first but not beyond the realms of imagination. |
@taylorotwell @Shkeats I may be a little out of my league here but would it make sense to provide something like Container.php public function withContext($context, $callback)
{
$this->buildStack[] = $context;
$value = $this->call($callback);
array_pop($this->buildStack);
return $value;
} Then anywhere that should support contextual method binding could wrap their calls. examples Container.php protected function getMethodDependencies($callback, array $parameters = [])
{
$dependencies = [];
$reflector = $this->getCallReflector($callback);
$this->withContext($reflector->class, function () use ($reflector) {
foreach ($reflector->getParameters() as $parameter) {
$this->addDependencyForCallParameter($parameter, $parameters, $dependencies);
}
})
return array_merge($dependencies, $parameters);
} RouteDependencyResolverTrait.php protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
{
if (! method_exists($instance, $method)) {
return $parameters;
}
return $this->container
->withContext(get_class($instance), function () use ($instance, $method) {
$this->resolveMethodDependencies(
$parameters, new ReflectionMethod($instance, $method)
)
});
} |
Not working on 5.1.46 |
This feature could be useful for contextual binding in the handle method of jobs. @taylorotwell |
Contextual binding per method initialization can make an implementation explicit and cognitively clear. I had the intention to fraction my requests implementation into few contracts, each per action type: UpdateRequestContract, SearchRequestContract, SomeGenericActionRequestContract then inject implementation per controller method, expl.: DiscountController@search(SearchRequestContract) -> give(DiscountSearchRequest::class) ... |
Contextual binding does not work on methods, only constructor functions.
I've added a (currently failing) test that checks that this works. (At least, I think that's what it's testing, I don't fully understand the
Container
class, so apologies if the test is wrong/stupid.)