Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Refactored argument resolving out of the ControllerResolver
  • Loading branch information
wouterj committed Apr 6, 2015
commit 0743526e2f2b67fe65f9e7802cb8e941de083ffd
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterArgumentResolversPass;

/**
* Bundle.
Expand Down Expand Up @@ -88,6 +89,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new TranslationDumperPass());
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new SerializerPass());
$container->addCompilerPass(new RegisterArgumentResolversPass());

if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<argument type="service" id="service_container" />
<argument type="service" id="controller_resolver" />
<argument type="service" id="request_stack" />
<argument type="service" id="argument_resolver.manager" />
</service>

<service id="request_stack" class="Symfony\Component\HttpFoundation\RequestStack" />
Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
<argument type="service" id="logger" on-invalid="ignore" />
</service>

<service id="argument_resolver.manager" class="Symfony\Component\HttpKernel\Controller\ArgumentResolverManager" />

<service id="argument_resolver.request" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestArgumentResolver">
<tag name="kernel.argument_resolver" />
</service>

<service id="argument_resolver.request_attributes" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributesArgumentResolver">
<tag name="kernel.argument_resolver" />
</service>

<service id="response_listener" class="Symfony\Component\HttpKernel\EventListener\ResponseListener">
<tag name="kernel.event_subscriber" />
<argument>%kernel.charset%</argument>
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/HttpKernel/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ CHANGELOG
3.0.0
-----

* added argument resolvers
* deprecated `Symfony\Component\HttpKernel\Controller\ControllerResolver#getArguments()` and `doGetArguments()`, use argument resolvers instead
* removed `Symfony\Component\HttpKernel\Kernel::init()`
* removed `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle()` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle()`

Expand Down
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)
Copy link
Contributor

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.

Copy link
Member Author

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.

{
$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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use $request->attributes->has($parameter->name) instead?

Copy link
Member Author

Choose a reason for hiding this comment

The 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];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use $request->attributes->get() too

}
}
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();
Copy link
Member

Choose a reason for hiding this comment

The 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i remember correct, normally methods like this are called add since they would logically only contain ArgumentResolverInterface instances.

{
$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
Expand Up @@ -90,6 +90,8 @@ public function getController(Request $request)
* {@inheritdoc}
*
* @api
*
* @deprecated Deprecated since Symfony 2.6, will be removed in Symfony 3.0. Use ArgumentResolvers instead
*/
public function getArguments(Request $request, $controller)
{
Expand All @@ -105,6 +107,9 @@ public function getArguments(Request $request, $controller)
return $this->doGetArguments($request, $controller, $r->getParameters());
}

/**
* @deprecated Deprecated since Symfony 2.6, will be removed in Symfony 3.0. Use ArgumentResolvers instead
*/
protected function doGetArguments(Request $request, $controller, array $parameters)
{
$attributes = $request->attributes->all();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverManager;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
Expand All @@ -39,10 +40,11 @@ class ContainerAwareHttpKernel extends HttpKernel
* @param ContainerInterface $container A ContainerInterface instance
* @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance
* @param RequestStack $requestStack A stack for master/sub requests
* @param ArgumentResolverManager $argumentResolver An ArgumentResolverManager instance
*/
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null)
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null, ArgumentResolverManager $argumentResolver = null)
{
parent::__construct($dispatcher, $controllerResolver, $requestStack);
parent::__construct($dispatcher, $controllerResolver, $requestStack, $argumentResolver);

$this->container = $container;

Expand Down
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;
Copy link
Member

Choose a reason for hiding this comment

The 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)));
}
}
}
Loading