Improved DX for the ArgumentResolver

This commit is contained in:
Iltar van der Berg 2016-04-01 08:34:22 +02:00 committed by Iltar van der Berg
parent f29bf4cd4a
commit 1bf80c92ee
12 changed files with 105 additions and 37 deletions

View File

@ -24,19 +24,19 @@
<argument type="collection" />
</service>
<service id="argument_value_resolver.argument_from_attribute" class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\ArgumentFromAttributeResolver" public="false">
<service id="argument_resolver.request_attribute" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver" public="false">
<tag name="controller_argument.value_resolver" priority="100" />
</service>
<service id="argument_value_resolver.argument_is_request" class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\RequestResolver" public="false">
<service id="argument_resolver.request" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver" public="false">
<tag name="controller_argument.value_resolver" priority="50" />
</service>
<service id="argument_value_resolver.default_argument_value" class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\DefaultArgumentValueResolver" public="false">
<service id="argument_resolver.default" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver" public="false">
<tag name="controller_argument.value_resolver" priority="-100" />
</service>
<service id="argument_value_resolver.variadic_argument_from_attribute" class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\VariadicArgumentValueResolver" public="false">
<service id="argument_resolver.variadic" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver" public="false">
<tag name="controller_argument.value_resolver" priority="-150" />
</service>

View File

@ -12,6 +12,11 @@
namespace Symfony\Component\HttpKernel\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
/**
@ -30,8 +35,13 @@ final class ArgumentResolver implements ArgumentResolverInterface
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, array $argumentValueResolvers = array())
{
$this->argumentMetadataFactory = $argumentMetadataFactory;
$this->argumentValueResolvers = $argumentValueResolvers;
$this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory();
$this->argumentValueResolvers = $argumentValueResolvers ?: array(
new RequestAttributeValueResolver(),
new RequestValueResolver(),
new DefaultValueResolver(),
new VariadicValueResolver(),
);
}
/**

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Controller\ArgumentValueResolver;
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class DefaultArgumentValueResolver implements ArgumentValueResolverInterface
final class DefaultValueResolver implements ArgumentValueResolverInterface
{
/**
* {@inheritdoc}

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Controller\ArgumentValueResolver;
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class ArgumentFromAttributeResolver implements ArgumentValueResolverInterface
final class RequestAttributeValueResolver implements ArgumentValueResolverInterface
{
/**
* {@inheritdoc}

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Controller\ArgumentValueResolver;
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@ -20,14 +20,14 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class RequestResolver implements ArgumentValueResolverInterface
final class RequestValueResolver implements ArgumentValueResolverInterface
{
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
{
return $argument->getType() === Request::class || is_subclass_of(Request::class, $argument->getType());
return $argument->getType() === Request::class || is_subclass_of($argument->getType(), Request::class);
}
/**

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Controller\ArgumentValueResolver;
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class VariadicArgumentValueResolver implements ArgumentValueResolverInterface
final class VariadicValueResolver implements ArgumentValueResolverInterface
{
/**
* {@inheritdoc}

View File

@ -87,12 +87,16 @@ class ArgumentMetadata
/**
* Returns the default value of the argument.
*
* Make sure to call {@see self::hasDefaultValue()} first to see if a default value is possible.
* @throws \LogicException if no default value is present; {@see self::hasDefaultValue()}
*
* @return mixed
*/
public function getDefaultValue()
{
if (!$this->hasDefaultValue) {
throw new \LogicException(sprintf('Argument $%s does not have a default value. Use %s::hasDefaultValue() to avoid this exception.', $this->name, __CLASS__));
}
return $this->defaultValue;
}
}

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\HttpKernel;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@ -47,7 +48,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface
$this->argumentResolver = $argumentResolver;
if (null === $this->argumentResolver) {
@trigger_error(sprintf('As of 3.1 an %s is used to resolve arguments. In 4.0 the $argumentResolver becomes mandatory and the %s can no longer be used to resolve arguments.', ArgumentResolverInterface::class, ControllerResolverInterface::class), E_USER_DEPRECATED);
@trigger_error(sprintf('As of 3.1 an %s is used to resolve arguments. In 4.0 the $argumentResolver becomes the %s if no other is provided instead of using the $resolver argument.', ArgumentResolverInterface::class, ArgumentResolver::class), E_USER_DEPRECATED);
// fallback in case of deprecations
$this->argumentResolver = $resolver;
}

View File

@ -12,12 +12,13 @@
namespace Symfony\Component\HttpKernel\Tests\Controller;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\ArgumentFromAttributeResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\DefaultArgumentValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\RequestResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\VariadicArgumentValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ExtendingRequest;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController;
use Symfony\Component\HttpFoundation\Request;
@ -30,15 +31,21 @@ class ArgumentResolverTest extends \PHPUnit_Framework_TestCase
{
$factory = new ArgumentMetadataFactory();
$argumentValueResolvers = array(
new ArgumentFromAttributeResolver(),
new VariadicArgumentValueResolver(),
new RequestResolver(),
new DefaultArgumentValueResolver(),
new RequestAttributeValueResolver(),
new RequestValueResolver(),
new DefaultValueResolver(),
new VariadicValueResolver(),
);
self::$resolver = new ArgumentResolver($factory, $argumentValueResolvers);
}
public function testDefaultState()
{
$this->assertEquals(self::$resolver, new ArgumentResolver());
$this->assertNotEquals(self::$resolver, new ArgumentResolver(null, array(new RequestAttributeValueResolver())));
}
public function testGetArguments()
{
$request = Request::create('/');
@ -140,6 +147,14 @@ class ArgumentResolverTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array($request), self::$resolver->getArguments($request, $controller), '->getArguments() injects the request');
}
public function testGetArgumentsInjectsExtendingRequest()
{
$request = ExtendingRequest::create('/');
$controller = array(new self(), 'controllerWithExtendingRequest');
$this->assertEquals(array($request), self::$resolver->getArguments($request, $controller), '->getArguments() injects the request when extended');
}
/**
* @requires PHP 5.6
*/
@ -210,6 +225,10 @@ class ArgumentResolverTest extends \PHPUnit_Framework_TestCase
protected function controllerWithRequest(Request $request)
{
}
protected function controllerWithExtendingRequest(ExtendingRequest $request)
{
}
}
function controller_function($foo, $foobar)

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\ControllerMetadata;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
class ArgumentMetadataTest extends \PHPUnit_Framework_TestCase
{
public function testDefaultValueAvailable()
{
$argument = new ArgumentMetadata('foo', 'string', false, true, 'default value');
$this->assertTrue($argument->hasDefaultValue());
$this->assertSame('default value', $argument->getDefaultValue());
}
/**
* @expectedException \LogicException
*/
public function testDefaultValueUnavailable()
{
$argument = new ArgumentMetadata('foo', 'string', false, false, null);
$this->assertFalse($argument->hasDefaultValue());
$argument->getDefaultValue();
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
use Symfony\Component\HttpFoundation\Request;
class ExtendingRequest extends Request
{
}

View File

@ -13,13 +13,8 @@ namespace Symfony\Component\HttpKernel\Tests\Fragment;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\ArgumentFromAttributeResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\DefaultArgumentValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\RequestResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\VariadicArgumentValueResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
use Symfony\Component\HttpKernel\KernelEvents;
@ -91,14 +86,8 @@ class InlineFragmentRendererTest extends \PHPUnit_Framework_TestCase
return new Response($object1->getBar());
}))
;
$argumentValueResolvers = array(
new ArgumentFromAttributeResolver(),
new VariadicArgumentValueResolver(),
new RequestResolver(),
new DefaultArgumentValueResolver(),
);
$kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack(), new ArgumentResolver(new ArgumentMetadataFactory(), $argumentValueResolvers));
$kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack(), new ArgumentResolver());
$renderer = new InlineFragmentRenderer($kernel);
$response = $renderer->render(new ControllerReference('main_controller', array('object' => new \stdClass(), 'object1' => new Bar()), array()), Request::create('/'));