-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[WIP] Refactored argument resolving out of the ControllerResolver #11457
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; | ||
|
||
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Resolves arguments typehinting for the Request object. | ||
* | ||
* @author Wouter J <[email protected]> | ||
*/ | ||
class RequestArgumentResolver implements ArgumentResolverInterface | ||
{ | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function accepts(Request $request, \ReflectionParameter $parameter) | ||
{ | ||
$class = $parameter->getClass(); | ||
|
||
return $class && $class->isInstance($request); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function resolve(Request $request, \ReflectionParameter $parameter) | ||
{ | ||
return $request; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; | ||
|
||
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Resolves arguments which names are equal to the name of a request attribute. | ||
* | ||
* @author Wouter J <[email protected]> | ||
*/ | ||
class RequestAttributesArgumentResolver implements ArgumentResolverInterface | ||
{ | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function accepts(Request $request, \ReflectionParameter $parameter) | ||
{ | ||
return array_key_exists($parameter->name, $request->attributes->all()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I copied it from the ControllerResolver, but it indeed looks like a nicer method. If there are no drawbacks, I'll change it. Thanks! |
||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function resolve(Request $request, \ReflectionParameter $parameter) | ||
{ | ||
$attributes = $request->attributes->all(); | ||
|
||
return $attributes[$parameter->name]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should use |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\HttpKernel\Controller; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* An ArgumentResolverInterface implementation resolves the arguments of | ||
* controllers. | ||
* | ||
* @author Wouter J <[email protected]> | ||
*/ | ||
interface ArgumentResolverInterface | ||
{ | ||
/** | ||
* Checks if the current parameter can be resolved by this argument | ||
* resolver. | ||
* | ||
* @param Request $request | ||
* @param \ReflectionParameter $parameter | ||
* | ||
* @return Boolean | ||
*/ | ||
public function accepts(Request $request, \ReflectionParameter $parameter); | ||
|
||
/** | ||
* Resolves the current parameter into an argument. | ||
* | ||
* @param Request $request | ||
* @param \ReflectionParameter $parameter | ||
* | ||
* @return mixed The resolved argument | ||
*/ | ||
public function resolve(Request $request, \ReflectionParameter $parameter); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\HttpKernel\Controller; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* The ArgumentResolverManager chains over the registered argument resolvers to | ||
* resolve all controller arguments. | ||
* | ||
* @author Wouter J <[email protected]> | ||
*/ | ||
class ArgumentResolverManager | ||
{ | ||
/** | ||
* @var ArgumentResolverInterface[] | ||
*/ | ||
protected $resolvers = array(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be private |
||
|
||
/** | ||
* Adds an argument resolver. | ||
* | ||
* @param ArgumentResolverInterface $resolver | ||
*/ | ||
public function addResolver(ArgumentResolverInterface $resolver) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If i remember correct, normally methods like this are called |
||
{ | ||
$this->resolvers[] = $resolver; | ||
} | ||
|
||
/** | ||
* Returns the arguments to pass to the controller. | ||
* | ||
* @param Request $request A Request instance | ||
* @param callable $controller A PHP callable | ||
* | ||
* @return array an array of arguments to pass to the controller | ||
* | ||
* @throws \RuntimeException When a parameter cannot be resolved | ||
*/ | ||
public function getArguments(Request $request, $controller) | ||
{ | ||
if (is_array($controller)) { | ||
$controllerReflection = new \ReflectionMethod($controller[0], $controller[1]); | ||
} elseif (is_object($controller) && !$controller instanceof \Closure) { | ||
$controllerReflection = new \ReflectionObject($controller); | ||
$controllerReflection = $controllerReflection->getMethod('__invoke'); | ||
} else { | ||
$controllerReflection = new \ReflectionFunction($controller); | ||
} | ||
|
||
$parameters = $controllerReflection->getParameters(); | ||
$arguments = array(); | ||
|
||
foreach ($parameters as $parameter) { | ||
foreach ($this->resolvers as $argumentResolver) { | ||
if ($argumentResolver->accepts($request, $parameter)) { | ||
$arguments[] = $argumentResolver->resolve($request, $parameter); | ||
continue 2; | ||
} | ||
} | ||
|
||
if ($parameter->isDefaultValueAvailable()) { | ||
$arguments[] = $parameter->getDefaultValue(); | ||
} else { | ||
if (is_array($controller)) { | ||
$repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]); | ||
} elseif (is_object($controller)) { | ||
$repr = get_class($controller); | ||
} else { | ||
$repr = $controller; | ||
} | ||
|
||
throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value and none of the argument resolvers could resolve its value).', $repr, $parameter->name)); | ||
} | ||
} | ||
|
||
return $arguments; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\HttpKernel\DependencyInjection; | ||
|
||
use Symfony\Component\DependencyInjection\Reference; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
|
||
/** | ||
* Compiler pass to register argument resolvers. | ||
* | ||
* @author Wouter J <[email protected]> | ||
*/ | ||
class RegisterArgumentResolversPass implements CompilerPassInterface | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
protected $managerService; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $resolverTag; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be private properties |
||
|
||
public function __construct($managerService = 'argument_resolver.manager', $resolverTag = 'kernel.argument_resolver') | ||
{ | ||
$this->managerService = $managerService; | ||
$this->resolverTag = $resolverTag; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function process(ContainerBuilder $container) | ||
{ | ||
if (!$container->hasDefinition($this->managerService) && !$container->hasAlias($this->managerService)) { | ||
return; | ||
} | ||
|
||
$definition = $container->findDefinition($this->managerService); | ||
|
||
foreach ($container->findTaggedServiceIds($this->resolverTag) as $id => $resolvers) { | ||
$definition->addMethodCall('addResolver', array(new Reference($id))); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually methods like this named
supports
in the Symfony codebase.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SensioFrameworkExtraBundle, which did have this feature previously, used
supports
. We tried to stick as much as possible to the SensioFrameworkExtraBundle API, so the migration will be easy.