├── .gitignore ├── src └── Knp │ └── Rad │ └── ResourceResolver │ ├── ParserContainer.php │ ├── Parser.php │ ├── CasterContainer.php │ ├── ParameterCaster.php │ ├── Event │ ├── ResourceEvent.php │ ├── ResourceResolvedEvent.php │ ├── ResourceEvent │ │ └── ResourceEvent.php │ └── ResourceResolvedEvent │ │ ├── ResourceResolvedEvent.php │ │ └── BeforeResourceResolvedEvent.php │ ├── Events.php │ ├── DependencyInjection │ ├── ResourceResolverExtension.php │ └── Compiler │ │ ├── ParserRegistrationPass.php │ │ └── ParameterCasterRegistrationPass.php │ ├── ResourceContainer.php │ ├── ParameterCaster │ ├── ResourceCaster.php │ ├── ServiceCaster.php │ ├── ArrayCaster.php │ └── VariableCaster.php │ ├── Bundle │ └── ResourceResolverBundle.php │ ├── ResourceResolver.php │ ├── RoutingNormalizer.php │ ├── ResourceContainer │ ├── ResourceContainer.php │ └── DispatcherProxyContainer.php │ ├── Resources │ └── config │ │ └── services.xml │ └── EventListener │ └── ResourcesListener.php ├── .travis.yml ├── .php_cs ├── composer.json ├── LICENSE ├── spec └── Knp │ └── Rad │ └── ResourceResolver │ ├── ParameterCaster │ ├── ArrayCasterSpec.php │ ├── ResourceCasterSpec.php │ ├── VariableCasterSpec.php │ └── ServiceCasterSpec.php │ ├── ResourceContainer │ ├── DispatcherProxyContainerSpec.php │ └── ResourceContainerSpec.php │ ├── ResourceResolverSpec.php │ ├── RoutingNormalizerSpec.php │ └── EventListener │ └── ResourcesListenerSpec.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | bin 3 | composer.lock 4 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ParserContainer.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 5 | ->exclude('vendor') 6 | ; 7 | 8 | return Symfony\CS\Config\Config::create() 9 | ->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL) 10 | ->fixers([ 11 | 'align_double_arrow', 12 | 'align_equals', 13 | 'newline_after_open_tag', 14 | 'ordered_use', 15 | 'phpdoc_order', 16 | 'phpspec', 17 | ]) 18 | ->addCustomFixer(new PedroTroller\CS\Fixer\Contrib\PhpspecFixer()) 19 | ->finder($finder) 20 | ; 21 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Event/ResourceResolvedEvent.php: -------------------------------------------------------------------------------- 1 | load('services.xml'); 19 | } 20 | 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public function getAlias() 25 | { 26 | return 'knp_rad_resource_resolver'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ResourceContainer.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('knp_rad_resource_resolver.parser_container') as $registryId => $registryTags) { 17 | $registry = $container->getDefinition($registryId); 18 | 19 | foreach ($container->findTaggedServiceIds('knp_rad_resource_resolver.parser') as $parserId => $parserTags) { 20 | $registry->addMethodCall('addParser', [new Reference($parserId)]); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "knplabs/rad-resource-resolver", 3 | "description": "A routing resource resolver based on conventions", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "KNP Labs", 8 | "email": "hello@knplabs.com" 9 | } 10 | ], 11 | "require": { 12 | "php": "~7.0", 13 | "symfony/config": "~2.8 || ~3.0", 14 | "symfony/dependency-injection": "~2.8 || ~3.0", 15 | "symfony/event-dispatcher": "~2.8 || ~3.0", 16 | "symfony/http-foundation": "~2.8 || ~3.0", 17 | "symfony/http-kernel": "~2.8 || ~3.0", 18 | "symfony/routing": "~2.8 || ~3.0" 19 | }, 20 | "require-dev": { 21 | "pedrotroller/php-cs-custom-fixer": "~1.2.1", 22 | "phpspec/phpspec": "~2.4", 23 | "phpspec/prophecy": "~1.6" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Knp\\Rad\\ResourceResolver\\": "src/Knp/Rad/ResourceResolver" 28 | } 29 | }, 30 | "config": { 31 | "bin-dir": "bin" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ParameterCaster/ResourceCaster.php: -------------------------------------------------------------------------------- 1 | container = $container; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function supports($value) 27 | { 28 | if (false === is_string($value)) { 29 | return false; 30 | } 31 | 32 | return 1 === preg_match('/^\&[a-zA-Z_]+/', $value); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function cast($value) 39 | { 40 | return $this->container->getResource(substr($value, 1)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/DependencyInjection/Compiler/ParameterCasterRegistrationPass.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('knp_rad_resource_resolver.parameter_caster_container') as $registryId => $registryTags) { 17 | $registry = $container->getDefinition($registryId); 18 | 19 | foreach ($container->findTaggedServiceIds('knp_rad_resource_resolver.parameter_caster') as $parameterCasterId => $parameterCasterTags) { 20 | $registry->addMethodCall('addParameterCaster', [new Reference($parameterCasterId)]); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Bundle/ResourceResolverBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new ParameterCasterRegistrationPass()); 19 | $container->addCompilerPass(new ParserRegistrationPass()); 20 | } 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function getContainerExtension() 26 | { 27 | if (null === $this->extension) { 28 | $this->extension = new ResourceResolverExtension(); 29 | } 30 | 31 | return $this->extension; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 KNP Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ParameterCaster/ArrayCasterSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType('Knp\Rad\ResourceResolver\ParameterCaster\ArrayCaster'); 14 | } 15 | 16 | function it_resolves_array(ParameterCaster $c1, ParameterCaster $c2, $service) 17 | { 18 | $c1->supports(Argument::any())->willReturn(false); 19 | $c1->supports('$var')->willReturn(true); 20 | $c1->cast('$var')->willReturn('result'); 21 | 22 | $c2->supports(Argument::any())->willReturn(false); 23 | $c2->supports('@service')->willReturn(true); 24 | $c2->cast('@service')->willReturn($service); 25 | 26 | $this->addParameterCaster($c1); 27 | $this->addParameterCaster($c2); 28 | 29 | $array = ['$var', '@service', 'toto']; 30 | 31 | $this->cast($array)->shouldReturn(['result', $service, 'toto']); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ParameterCaster/ServiceCaster.php: -------------------------------------------------------------------------------- 1 | container = $container; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function supports($value) 27 | { 28 | if (false === is_string($value)) { 29 | return false; 30 | } 31 | 32 | return 1 === preg_match('/^@(\w|\.)+/', $value); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function cast($value) 39 | { 40 | $service = $this->container->get(substr($value, 1), ContainerInterface::NULL_ON_INVALID_REFERENCE); 41 | 42 | return null !== $service ? $service : $value; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ParameterCaster/ArrayCaster.php: -------------------------------------------------------------------------------- 1 | $value) { 29 | foreach ($this->parameterCasters as $caster) { 30 | if ($caster->supports($value)) { 31 | $value = $caster->cast($value); 32 | continue; 33 | } 34 | } 35 | 36 | $array[$key] = $value; 37 | } 38 | 39 | return $array; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function addParameterCaster(ParameterCaster $parameterCaster) 46 | { 47 | $this->parameterCasters[] = $parameterCaster; 48 | 49 | return $this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Event/ResourceEvent/ResourceEvent.php: -------------------------------------------------------------------------------- 1 | resourceName = $resourceName; 33 | $this->resource = $resource; 34 | $this->container = $container; 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function getName() 41 | { 42 | return $this->resourceName; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function getResource() 49 | { 50 | return $this->resource; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function getContainer() 57 | { 58 | return $this->container; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Event/ResourceResolvedEvent/ResourceResolvedEvent.php: -------------------------------------------------------------------------------- 1 | event = $event; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function getResource() 27 | { 28 | return $this->event->getResource(); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function getServiceId() 35 | { 36 | return $this->event->getServiceId(); 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function getService() 43 | { 44 | return $this->event->getService(); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function getMethod() 51 | { 52 | return $this->event->getMethod(); 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function getArguments() 59 | { 60 | return $this->event->getArguments(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ParameterCaster/ResourceCasterSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($container); 13 | } 14 | 15 | function it_is_initializable() 16 | { 17 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ParameterCaster\ResourceCaster'); 18 | } 19 | 20 | function it_supports_resource_strings() 21 | { 22 | $this->supports('&my_resource')->shouldReturn(true); 23 | $this->supports('&foo_bar')->shouldReturn(true); 24 | $this->supports('foo_bar')->shouldReturn(false); 25 | $this->supports('foo_&bar')->shouldReturn(false); 26 | $this->supports('foo_bar&')->shouldReturn(false); 27 | $this->supports('&')->shouldReturn(false); 28 | } 29 | 30 | function it_casts_a_resource_string_in_resource($resource, $resource2, $container) 31 | { 32 | $container 33 | ->getResource('my_resource') 34 | ->willReturn($resource) 35 | ; 36 | 37 | $container 38 | ->getResource('my_resource2') 39 | ->willReturn($resource2) 40 | ; 41 | 42 | $this->cast('&my_resource')->shouldReturn($resource); 43 | $this->cast('&my_resource2')->shouldReturn($resource2); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ParameterCaster/VariableCaster.php: -------------------------------------------------------------------------------- 1 | requestStack = $requestStack; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function supports($value) 27 | { 28 | if (false === is_string($value)) { 29 | return false; 30 | } 31 | 32 | return 1 === preg_match('/^\$[a-zA-Z_]+/', $value); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function cast($value) 39 | { 40 | $routeParameters = $this->getRequest()->attributes->get('_route_params'); 41 | 42 | foreach ($routeParameters as $routeParameter => $routevalue) { 43 | if (substr($value, 1) === $routeParameter) { 44 | return $routevalue; 45 | } 46 | } 47 | 48 | return $value; 49 | } 50 | 51 | /** 52 | * @return \Symfony\Component\HttpFoundation\Request|null 53 | */ 54 | private function getRequest() 55 | { 56 | return $this->requestStack->getCurrentRequest(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ResourceContainer/DispatcherProxyContainerSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($container, $dispatcher); 16 | } 17 | 18 | function it_is_initializable() 19 | { 20 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ResourceContainer\DispatcherProxyContainer'); 21 | } 22 | 23 | function it_dispatch_an_event_when_a_resource_is_added($container, $dispatcher, $resource) 24 | { 25 | $dispatcher 26 | ->dispatch(Events::RESOURCES_ADDED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceEvent\ResourceEvent')) 27 | ->shouldBeCalled() 28 | ; 29 | $container->addResource('key', $resource)->shouldBeCalled(); 30 | 31 | $this->addResource('key', $resource); 32 | } 33 | 34 | function it_dispatch_an_event_when_a_resource_is_removed($container, $dispatcher, $resource) 35 | { 36 | $dispatcher 37 | ->dispatch(Events::RESOURCES_REMOVED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceEvent\ResourceEvent')) 38 | ->shouldBeCalled() 39 | ; 40 | $container->removeResource('key')->shouldBeCalled(); 41 | $container->getResource('key')->willReturn($resource); 42 | 43 | $this->removeResource('key'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ParameterCaster/VariableCasterSpec.php: -------------------------------------------------------------------------------- 1 | getCurrentRequest()->willReturn($request); 15 | $this->beConstructedWith($requestStack); 16 | } 17 | 18 | function it_is_initializable() 19 | { 20 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ParameterCaster\VariableCaster'); 21 | } 22 | 23 | function it_supports_variable_strings() 24 | { 25 | $this->supports('12309')->shouldReturn(false); 26 | $this->supports(123509)->shouldReturn(false); 27 | $this->supports(false)->shouldReturn(false); 28 | $this->supports('$unprst')->shouldReturn(true); 29 | $this->supports('$09erst')->shouldReturn(false); 30 | $this->supports('nrustenrute')->shouldReturn(false); 31 | } 32 | 33 | function it_casts_variable_string_in_string($request, ParameterBag $attributes) 34 | { 35 | $request->attributes = $attributes; 36 | 37 | $attributes 38 | ->get('_route_params') 39 | ->willReturn([ 40 | 'foo' => 18098, 41 | 'bar' => true, 42 | 'xyz' => 'value', 43 | ]) 44 | ; 45 | 46 | $this->cast('$foo')->shouldReturn(18098); 47 | $this->cast('$bar')->shouldReturn(true); 48 | $this->cast('$xyz')->shouldReturn('value'); 49 | $this->cast('$test')->shouldReturn('$test'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ResourceResolver.php: -------------------------------------------------------------------------------- 1 | container = $container; 30 | $this->dispatcher = $dispatcher; 31 | } 32 | 33 | /** 34 | * @param string $serviceId 35 | * @param string $methodName 36 | * @param array $arguments 37 | * 38 | * @return mixed 39 | */ 40 | public function resolveResource($serviceId, $methodName, array $arguments) 41 | { 42 | try { 43 | $service = $this->container->get($serviceId); 44 | } catch (ServiceNotFoundException $e) { 45 | throw $e; 46 | } 47 | 48 | $event = new BeforeResourceResolvedEvent($serviceId, $service, $methodName, $arguments); 49 | 50 | if (null !== $this->dispatcher) { 51 | $this->dispatcher->dispatch(Events::BEFORE_RESOURCE_RESOLVED, $event); 52 | } 53 | 54 | if (null === $event->getResource()) { 55 | $callable = $methodName ? [$service, $methodName] : $service; 56 | $resource = call_user_func_array($callable, $arguments); 57 | $event->setResource($resource); 58 | } 59 | 60 | if (null !== $this->dispatcher) { 61 | $this->dispatcher->dispatch(Events::RESOURCE_RESOLVED, new ResourceResolvedEvent($event)); 62 | } 63 | 64 | return $event->getResource(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Event/ResourceResolvedEvent/BeforeResourceResolvedEvent.php: -------------------------------------------------------------------------------- 1 | serviceId = $serviceId; 44 | $this->service = $service; 45 | $this->method = $method; 46 | $this->arguments = $arguments; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function getResource() 53 | { 54 | return $this->resource; 55 | } 56 | 57 | /** 58 | * @param mixed $resource 59 | * 60 | * @return BeforeResourceResolvedEvent 61 | */ 62 | public function setResource($resource) 63 | { 64 | $this->resource = $resource; 65 | 66 | if (null !== $resource) { 67 | $this->stopPropagation(); 68 | } 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | */ 76 | public function getServiceId() 77 | { 78 | return $this->serviceId; 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | public function getService() 85 | { 86 | return $this->service; 87 | } 88 | 89 | /** 90 | * {@inheritdoc} 91 | */ 92 | public function getMethod() 93 | { 94 | return $this->method; 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function getArguments() 101 | { 102 | return $this->arguments; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ParameterCaster/ServiceCasterSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($container); 16 | } 17 | 18 | function it_is_initializable(ContainerInterface $container) 19 | { 20 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ParameterCaster\ServiceCaster'); 21 | } 22 | 23 | function it_supports_service_strings() 24 | { 25 | $this->supports('@my_service')->shouldReturn(true); 26 | $this->supports('@foo_bar')->shouldReturn(true); 27 | $this->supports('foo_bar')->shouldReturn(false); 28 | $this->supports('foo_@bar')->shouldReturn(false); 29 | $this->supports('foo_bar@')->shouldReturn(false); 30 | $this->supports('@')->shouldReturn(false); 31 | } 32 | 33 | function it_casts_a_service_string_in_service( 34 | RequestStack $requestStack, 35 | RequestDataCollector $requestDataCollector, 36 | DumpListener $dumpListener, 37 | $container 38 | ) { 39 | $container 40 | ->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE) 41 | ->willReturn($requestStack) 42 | ; 43 | 44 | $container 45 | ->get('data_collector.request', ContainerInterface::NULL_ON_INVALID_REFERENCE) 46 | ->willReturn($requestDataCollector) 47 | ; 48 | 49 | $container 50 | ->get('debug.dump_listener', ContainerInterface::NULL_ON_INVALID_REFERENCE) 51 | ->willReturn($dumpListener) 52 | ; 53 | 54 | $container 55 | ->get('foo_bar', ContainerInterface::NULL_ON_INVALID_REFERENCE) 56 | ->willReturn('@foo_bar') 57 | ; 58 | 59 | $this->cast('@request_stack')->shouldReturn($requestStack); 60 | $this->cast('@data_collector.request')->shouldReturn($requestDataCollector); 61 | $this->cast('@debug.dump_listener')->shouldReturn($dumpListener); 62 | $this->cast('@foo_bar')->shouldReturn('@foo_bar'); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/RoutingNormalizer.php: -------------------------------------------------------------------------------- 1 | normalizeString($declaration); 18 | } 19 | 20 | // Normalize numerically indexed array 21 | if (array_keys($declaration) === array_keys(array_values($declaration))) { 22 | return $this->normalizeArray($declaration); 23 | } 24 | 25 | if (isset($declaration['arguments']) && !is_array($declaration['arguments'])) { 26 | throw new \InvalidArgumentException('The "arguments" parameter should be an array of arguments.'); 27 | } 28 | 29 | // Adds default value to associative array 30 | return array_merge(['method' => null, 'required' => true, 'arguments' => []], $declaration); 31 | } 32 | 33 | private function normalizeString($declaration) 34 | { 35 | $service = $declaration; 36 | $method = null; 37 | 38 | if (strpos($declaration, ':') !== false) { 39 | list($service, $method) = explode(':', $declaration); 40 | } 41 | 42 | return [ 43 | 'service' => $service, 44 | 'method' => $method, 45 | 'arguments' => [], 46 | 'required' => true, 47 | ]; 48 | } 49 | 50 | private function normalizeArray($declaration) 51 | { 52 | if (isset($declaration[1]) && !is_array($declaration[1])) { 53 | throw new \InvalidArgumentException('The second argument for a resource configuration, when expressed with a numerically indexed array, should be an array of arguments.'); 54 | } 55 | 56 | $service = $declaration[0]; 57 | $method = null; 58 | 59 | if (false !== strpos($declaration[0], ':')) { 60 | list($service, $method) = explode(':', $declaration[0]); 61 | } 62 | 63 | return [ 64 | 'service' => $service, 65 | 'method' => $method, 66 | 'arguments' => isset($declaration[1]) ? $declaration[1] : [], 67 | 'required' => isset($declaration[2]) ? (bool) $declaration[2] : true, 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ResourceContainer/ResourceContainerSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith([ 12 | 'resource1' => $resource1, 13 | 'resource3' => $resource3, 14 | ]); 15 | } 16 | 17 | function it_is_initializable() 18 | { 19 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ResourceContainer\ResourceContainer'); 20 | } 21 | 22 | function it_returns_resources($resource1, $resource3) 23 | { 24 | $this->getResources()->shouldReturn([ 25 | 'resource1' => $resource1, 26 | 'resource3' => $resource3, 27 | ]); 28 | } 29 | 30 | function it_receives_new_resources($resource1, $resource2, $resource3) 31 | { 32 | $this->addResource('resource2', $resource2); 33 | 34 | $this->getResources()->shouldReturn([ 35 | 'resource1' => $resource1, 36 | 'resource3' => $resource3, 37 | 'resource2' => $resource2, 38 | ]); 39 | } 40 | 41 | function it_can_replace_a_resource($resource1, $resource2) 42 | { 43 | $this->addResource('resource3', $resource2); 44 | 45 | $this->getResources()->shouldReturn([ 46 | 'resource1' => $resource1, 47 | 'resource3' => $resource2, 48 | ]); 49 | } 50 | 51 | function it_removes_a_resource($resource1) 52 | { 53 | $this->removeResource('resource3'); 54 | 55 | $this->getResources()->shouldReturn([ 56 | 'resource1' => $resource1, 57 | ]); 58 | } 59 | 60 | function it_says_if_resource_exists() 61 | { 62 | $this->hasResource('resource1')->shouldReturn(true); 63 | $this->hasResource('resource3')->shouldReturn(true); 64 | $this->hasResource('resource2')->shouldReturn(false); 65 | } 66 | 67 | function it_fails_when_an_unexisting_resource_is_asked() 68 | { 69 | $this 70 | ->shouldThrow(new \DomainException('Resource "no" not found, "resource1", "resource3" available.')) 71 | ->duringGetResource('no') 72 | ; 73 | 74 | $this 75 | ->shouldThrow(new \DomainException('Resource "no" not found, "resource1", "resource3" available.')) 76 | ->duringRemoveResource('no') 77 | ; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ResourceContainer/ResourceContainer.php: -------------------------------------------------------------------------------- 1 | resources = $resources; 20 | } 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function getResources() 26 | { 27 | return $this->resources; 28 | } 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public function getResource($key) 34 | { 35 | $this->resourceExistsOrException($key); 36 | 37 | return $this->resources[$key]; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function hasResource($key) 44 | { 45 | return array_key_exists($key, $this->resources); 46 | } 47 | 48 | /** 49 | * {@inheritdoc} 50 | */ 51 | public function addResource($key, $resource) 52 | { 53 | $this->resources[$key] = $resource; 54 | 55 | return $this; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function removeResource($key) 62 | { 63 | $this->resourceExistsOrException($key); 64 | 65 | unset($this->resources[$key]); 66 | 67 | return $this; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public function offsetExists($offset) 74 | { 75 | return $this->hasResource($offset); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function offsetGet($offset) 82 | { 83 | return $this->getResource($offset); 84 | } 85 | 86 | /** 87 | * {@inheritdoc} 88 | */ 89 | public function offsetSet($offset, $value) 90 | { 91 | return $this->addResource($offset, $value); 92 | } 93 | 94 | /** 95 | * {@inheritdoc} 96 | */ 97 | public function offsetUnset($offset) 98 | { 99 | return $this->removeResource($offset); 100 | } 101 | 102 | private function resourceExistsOrException($key) 103 | { 104 | if (false === $this->hasResource($key)) { 105 | throw new \DomainException(sprintf( 106 | 'Resource "%s" not found, "%s" available.', 107 | $key, 108 | implode('", "', array_keys($this->resources)) 109 | )); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/ResourceContainer/DispatcherProxyContainer.php: -------------------------------------------------------------------------------- 1 | wrapped = $wrapped; 25 | $this->dispatcher = $dispatcher; 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public function getResources() 32 | { 33 | return $this->wrapped->getResources(); 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function getResource($key) 40 | { 41 | return $this->wrapped->getResource($key); 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function hasResource($key) 48 | { 49 | return $this->wrapped->hasResource($key); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function addResource($key, $resource) 56 | { 57 | $this->wrapped->addResource($key, $resource); 58 | 59 | $this 60 | ->dispatcher 61 | ->dispatch(Events::RESOURCES_ADDED, new ResourceEvent($key, $resource, $this->wrapped)) 62 | ; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * {@inheritdoc} 69 | */ 70 | public function removeResource($key) 71 | { 72 | $resource = $this->getResource($key); 73 | $this->wrapped->removeResource($key); 74 | 75 | $this 76 | ->dispatcher 77 | ->dispatch(Events::RESOURCES_REMOVED, new ResourceEvent($key, $resource, $this->wrapped)) 78 | ; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | */ 86 | public function offsetExists($offset) 87 | { 88 | return $this->hasResource($offset); 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | public function offsetGet($offset) 95 | { 96 | return $this->getResource($offset); 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | */ 102 | public function offsetSet($offset, $value) 103 | { 104 | return $this->addResource($offset, $value); 105 | } 106 | 107 | /** 108 | * {@inheritdoc} 109 | */ 110 | public function offsetUnset($offset) 111 | { 112 | return $this->removeResource($offset); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/ResourceResolverSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($container); 17 | } 18 | 19 | function it_is_initializable() 20 | { 21 | $this->shouldHaveType('Knp\Rad\ResourceResolver\ResourceResolver'); 22 | } 23 | 24 | function it_resolves_a_resource($container, Route $route, $reference) 25 | { 26 | $container->get('app.my.route')->willReturn($route); 27 | $route->setOption('"myFirstParameter"', true)->willReturn($reference); 28 | 29 | $this 30 | ->resolveResource('app.my.route', 'setOption', ['"myFirstParameter"', true]) 31 | ->shouldReturn($reference) 32 | ; 33 | } 34 | 35 | function it_resolves_a_resource_from_an_invokable(Invokable $invokable, $container, $reference) 36 | { 37 | $container->get('app.my.invokable')->willReturn($invokable); 38 | $invokable->__invoke()->willReturn($reference); 39 | 40 | $this->resolveResource('app.my.invokable', null, [])->shouldReturn($reference); 41 | } 42 | 43 | function it_dispatches_an_event_when_a_resource_is_resolved($container, EventDispatcherInterface $dispatcher, Route $route) 44 | { 45 | $this->beConstructedWith($container, $dispatcher); 46 | 47 | $container->get('app.my.route')->willReturn($route); 48 | $dispatcher 49 | ->dispatch(Events::BEFORE_RESOURCE_RESOLVED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceResolvedEvent\BeforeResourceResolvedEvent')) 50 | ->shouldBeCalled() 51 | ; 52 | $dispatcher 53 | ->dispatch(Events::RESOURCE_RESOLVED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceResolvedEvent\ResourceResolvedEvent')) 54 | ->shouldBeCalled() 55 | ; 56 | 57 | $this->resolveResource('app.my.route', 'setOption', ['"myFirstParameter"', true]); 58 | } 59 | 60 | function it_doesnt_resolve_resource_if_listener_does($container, EventDispatcherInterface $dispatcher, Route $route) 61 | { 62 | $result = 'toto'; 63 | $this->beConstructedWith($container, $dispatcher); 64 | 65 | $dispatcher 66 | ->dispatch(Events::BEFORE_RESOURCE_RESOLVED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceResolvedEvent\BeforeResourceResolvedEvent')) 67 | ->shouldBeCalled() 68 | ->will(function ($args) use ($result) { 69 | list($name, $event) = $args; 70 | $event->setResource($result); 71 | }) 72 | ; 73 | $dispatcher->dispatch(Events::RESOURCE_RESOLVED, Argument::type('Knp\Rad\ResourceResolver\Event\ResourceResolvedEvent\ResourceResolvedEvent'))->shouldBeCalled(); 74 | $route->setOption(Argument::cetera())->shouldNotBeCalled(); 75 | 76 | $this->resolveResource('@app.my.route', 'setOption', ['"myFirstParameter"', true])->shouldReturn($result); 77 | } 78 | } 79 | 80 | class Invokable 81 | { 82 | public function __invoke() 83 | { 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/RoutingNormalizerSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType('Knp\Rad\ResourceResolver\RoutingNormalizer'); 12 | } 13 | 14 | function it_normalizes_string_without_method() 15 | { 16 | $this->normalizeDeclaration('app.http.resource_provider.user_membership')->shouldReturn([ 17 | 'service' => 'app.http.resource_provider.user_membership', 18 | 'method' => null, 19 | 'arguments' => [], 20 | 'required' => true, 21 | ]); 22 | } 23 | 24 | function it_normalizes_string_with_method() 25 | { 26 | $this->normalizeDeclaration('app.repository.article_repository:getNewestArticle')->shouldReturn([ 27 | 'service' => 'app.repository.article_repository', 28 | 'method' => 'getNewestArticle', 29 | 'arguments' => [], 30 | 'required' => true, 31 | ]); 32 | } 33 | 34 | function it_adds_default_value_to_array() 35 | { 36 | $this->normalizeDeclaration([ 37 | 'service' => 'app_article_repository', 38 | ])->shouldBeLike([ 39 | 'service' => 'app_article_repository', 40 | 'method' => null, 41 | 'arguments' => [], 42 | 'required' => true, 43 | ]); 44 | } 45 | 46 | function it_does_nothing_for_an_array_already_normalized() 47 | { 48 | $this->normalizeDeclaration([ 49 | 'service' => 'app_product_repository', 50 | 'method' => 'findAllSoldBy', 51 | 'arguments' => ['$productId'], 52 | 'required' => false, 53 | ])->shouldBeLike([ 54 | 'service' => 'app_product_repository', 55 | 'method' => 'findAllSoldBy', 56 | 'arguments' => ['$productId'], 57 | 'required' => false, 58 | ]); 59 | } 60 | 61 | function it_normalizes_array_without_arguments() 62 | { 63 | $this->normalizeDeclaration(['app.repository.product:findNewest'])->shouldBeLike([ 64 | 'service' => 'app.repository.product', 65 | 'method' => 'findNewest', 66 | 'arguments' => [], 67 | 'required' => true, 68 | ]); 69 | } 70 | 71 | function it_throws_an_exception_if_arguments_are_not_an_array_for_associative_array_declaration() 72 | { 73 | $this->shouldThrow('InvalidArgumentException')->duringNormalizeDeclaration([ 74 | 'service' => 'app.repository.products', 75 | 'method' => 'findAll', 76 | 'arguments' => 'invalid', 77 | 'required' => true, 78 | ]); 79 | } 80 | 81 | function it_throws_an_exception_if_arguments_are_not_an_array_for_numerically_indexed_array_declaration() 82 | { 83 | $this->shouldThrow('InvalidArgumentException')->duringNormalizeDeclaration([ 84 | 'app.repository.products:findAll', 85 | 'invalid', 86 | true, 87 | ]); 88 | } 89 | 90 | function it_normalizes_invokable_in_array() 91 | { 92 | $this->normalizeDeclaration(['app.repository.bestOffers', ['$productId']])->shouldBeLike([ 93 | 'service' => 'app.repository.bestOffers', 94 | 'method' => null, 95 | 'arguments' => ['$productId'], 96 | 'required' => true, 97 | ]); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/Knp/Rad/ResourceResolver/EventListener/ResourcesListener.php: -------------------------------------------------------------------------------- 1 | resolver = $resolver; 31 | $this->container = $container; 32 | $this->parsers = []; 33 | $this->parameterCasters = []; 34 | $this->normalizer = $normalizer; 35 | } 36 | 37 | public function resolveResources(FilterControllerEvent $event) 38 | { 39 | $request = $event->getRequest(); 40 | 41 | $resources = []; 42 | foreach ($request->attributes->get('_resources', []) as $resourceKey => $resourceValue) { 43 | $resourceValue = $this->parse($resourceValue) ?: $resourceValue; 44 | $resources[$resourceKey] = $resourceValue; 45 | } 46 | 47 | foreach ($resources as $resourceKey => $resourceDetails) { 48 | $resourceDetails = $this->normalizer->normalizeDeclaration($resourceDetails); 49 | $parameters = []; 50 | 51 | foreach ($resourceDetails['arguments'] as $parameter) { 52 | $parameter = $this->castParameter($parameter) ?: $parameter; 53 | $parameters[] = $parameter; 54 | } 55 | 56 | $resource = $this 57 | ->resolver 58 | ->resolveResource( 59 | $resourceDetails['service'], 60 | $resourceDetails['method'], 61 | $parameters 62 | ) 63 | ; 64 | 65 | if (false !== $resourceDetails['required'] && null === $resource) { 66 | throw new NotFoundHttpException(sprintf('The resource %s could not be found', $resourceKey)); 67 | } 68 | 69 | $request->attributes->set($resourceKey, $resource); 70 | 71 | $this->container->addResource($resourceKey, $resource); 72 | } 73 | 74 | return $event; 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function addParser(Parser $parser) 81 | { 82 | $this->parsers[] = $parser; 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | public function addParameterCaster(ParameterCaster $parameterCaster) 91 | { 92 | $this->parameterCasters[] = $parameterCaster; 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * @return null|array 99 | */ 100 | private function parse($resourceDetails) 101 | { 102 | foreach ($this->parsers as $parser) { 103 | if (true === $parser->supports($resourceDetails)) { 104 | return $parser->parse($resourceDetails); 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * @return mixed 111 | */ 112 | private function castParameter($parameter) 113 | { 114 | foreach ($this->parameterCasters as $parameterCaster) { 115 | if (true === $parameterCaster->supports($parameter)) { 116 | return $parameterCaster->cast($parameter); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | Unfortunately we decided to not maintain this project anymore ([see why](https://knplabs.com/en/blog/news-for-our-foss-projects-maintenance)). 3 | If you want to mark another package as a replacement for this one please send an email to [hello@knplabs.com](mailto:hello@knplabs.com). 4 | 5 | # Knp Rad Resource Resolver 6 | 7 | [![Build Status](https://travis-ci.org/KnpLabs/rad-resource-resolver.svg?branch=master)](https://travis-ci.org/KnpLabs/rad-resource-resolver) 8 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/KnpLabs/rad-resource-resolver/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/KnpLabs/rad-resource-resolver/?branch=master) 9 | [![Latest Stable Version](https://poser.pugx.org/knplabs/rad-resource-resolver/v/stable)](https://packagist.org/packages/knplabs/rad-resource-resolver) [![Total Downloads](https://poser.pugx.org/knplabs/rad-resource-resolver/downloads)](https://packagist.org/packages/knplabs/rad-resource-resolver) [![Latest Unstable Version](https://poser.pugx.org/knplabs/rad-resource-resolver/v/unstable)](https://packagist.org/packages/knplabs/rad-resource-resolver) [![License](https://poser.pugx.org/knplabs/rad-resource-resolver/license)](https://packagist.org/packages/knplabs/rad-resource-resolver) 10 | 11 | # Official maintainers: 12 | 13 | * [@Einenlum](https://github.com/Einenlum) 14 | 15 | ## Why using it? 16 | Tired of doing the same things again and again in your controllers, like transforming a URL value in an object? 17 | Don't want to use ParamConverter Annotations? 18 | 19 | This Resource Resolver is for you. 20 | 21 | ## Installation 22 | 23 | With composer : 24 | 25 | ```bash 26 | $ composer require knplabs/rad-resource-resolver 27 | ``` 28 | 29 | If you are using symfony2 you can update your `app/AppKernel.php` file: 30 | 31 | ```php 32 | public function registerBundles() 33 | { 34 | $bundles = array( 35 | // bundles here ... 36 | new Knp\Rad\ResourceResolver\Bundle\ResourceResolverBundle(), 37 | ); 38 | } 39 | ``` 40 | 41 | ## How to use it? 42 | 43 | In a yaml routing file, it could look like this : 44 | 45 | ```yaml 46 | users_show: 47 | path: /users/{id} 48 | defaults: 49 | _resources: 50 | user: 51 | service: my.user.repository 52 | method: find 53 | arguments: [$id] 54 | # This will automatically resolve the resource to give you a $user object in your request attributes 55 | ``` 56 | 57 | ```yaml 58 | countries_cities_buildings_index: 59 | path: /countries/{countryId}/cities/{citySlug}/buildings 60 | defaults: 61 | _resources: 62 | buildings: 63 | service: app.building.repository 64 | method: findByCountryAndCityAndActivity 65 | arguments: [$countryId, $citySlug, "School"] 66 | # You will have a $buildings variable in your request attributes 67 | ``` 68 | 69 | Every `key` under `_resources` will be return as a `$key` converted value in your request attributes. 70 | 71 | However, you can use more concise ways to express your resources configuration : 72 | 73 | ```yaml 74 | product_show: 75 | path: /product/{slug} 76 | defaults: 77 | _resources: 78 | product: [ "my.repository.product:findBySlug", [ $slug ] ] 79 | bestSellers: "my.repository.seller:findBestSellers" 80 | # Supports invokable 81 | bestOffers: "my.repository.bestOffers" 82 | comments: ["my.repository.randomComments"] 83 | # Invokable with arguments 84 | relatedProducts: ["my.repository.relatedProducts", [10]] 85 | 86 | ``` 87 | 88 | ## Optional Resources 89 | 90 | By default, the Rad Resource Resolver throws a `Symfony\Component\HttpKernel\Exception\NotFoundHttpException` if the resource was not found. You can override this behavior by adding the `required` option to false: 91 | 92 | ```yaml 93 | _resources: 94 | buildings: 95 | service: app.building.repository 96 | method: findByCountryAndCityAndActivity 97 | arguments: [$countryId, $citySlug, "School"] 98 | required: false 99 | ``` 100 | 101 | ## Available resource resolving arguments 102 | 103 | - URL variables: you have to use the `$` prefix. For example, if your URL is `/products/{products}/` you can access to `product` value by using `$product`. 104 | - Services: you can use the `@` prefix (ex: @doctrine) 105 | - Previously resolved resources: you can use the `&` prefix (ex: `&user` will return the `user` resource) 106 | 107 | ## How does it work? 108 | 109 | A `ResourcesListener` listens to `kernel.controller` event and resolves automatically all resources in `_resources`. 110 | The component uses `ParameterCaster` objects to catch different argument types and `Parser` objects to resolve _resources locations syntax. 111 | 112 | This means you can easily add your own `ParameterCasters` and `Parsers` to change the syntax used by the component. 113 | 114 | To add your own `ParameterCaster`, just tag it with `knp_rad_resource_resolver.parameter_caster`. 115 | The tag to add a `Parser` is `knp_rad_resource_resolver.parser`. 116 | 117 | # Events 118 | 119 | All events are listed [here](./src/Knp/Rad/ResourceResolver/Events.php). 120 | 121 | ## How can I hook resource resolution ? 122 | 123 | There is two events : 124 | 125 | - knp_rad_resource_resolver.before_resource_resolved: dispatched before the resolution. You can set the resource before the resolution. 126 | - knp_rad_resource_resolver.resource_resolved: dispatched after the resolution. 127 | 128 | ## How can I get all resolved resources ? 129 | 130 | There is a service alias named `knp_rad_resource_resolver.resource_container` where you can get all resolved resources. You can also listen to the event `knp_rad_resource_resolver.resource.added` and be notified when a resource is added to the container. 131 | 132 | ## License 133 | This project is published under MIT License. Feel free to contribute. 134 | 135 | -------------------------------------------------------------------------------- /spec/Knp/Rad/ResourceResolver/EventListener/ResourcesListenerSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($resolver, $container, $normalizer); 27 | $this->addParser($customSyntaxParser); 28 | $this->addParameterCaster($variableCaster); 29 | } 30 | 31 | function it_is_initializable() 32 | { 33 | $this->shouldHaveType('Knp\Rad\ResourceResolver\EventListener\ResourcesListener'); 34 | } 35 | 36 | function it_resolves_resources( 37 | FilterControllerEvent $event, 38 | Request $request, 39 | ParameterBag $parameterBag, 40 | GenericEvent $genericEvent1, 41 | $resolver, 42 | $customSyntaxParser, 43 | $variableCaster, 44 | $container, 45 | $normalizer 46 | ) { 47 | $event->getRequest()->willReturn($request); 48 | $request->attributes = $parameterBag; 49 | $customPath = '@app_user_repository::myMethod("myFirstParameter", $id, false)'; 50 | $resources = ['user' => $customPath]; 51 | 52 | $parameterBag->get('_resources', [])->willReturn($resources); 53 | 54 | $customSyntaxParser->supports($customPath)->willReturn(true); 55 | $customSyntaxParser->parse($customPath)->willReturn($declaration = [ 56 | 'service' => 'app_user_repository', 57 | 'method' => 'myMethod', 58 | 'arguments' => ['myFirstParameter', '$id'], 59 | 'required' => false, 60 | ]); 61 | 62 | $normalizer->normalizeDeclaration($declaration)->willReturn($declaration); 63 | 64 | $variableCaster->supports('myFirstParameter')->willReturn(false); 65 | $variableCaster->supports('$id')->willReturn(true); 66 | $variableCaster->cast('$id')->willReturn(240); 67 | 68 | $resolver 69 | ->resolveResource('app_user_repository', 'myMethod', ['myFirstParameter', 240]) 70 | ->willReturn($genericEvent1) 71 | ; 72 | 73 | $parameterBag->set('user', $genericEvent1)->shouldBeCalled(); 74 | $container->addResource('user', $genericEvent1)->shouldBeCalled(); 75 | 76 | $this->resolveResources($event); 77 | } 78 | 79 | function it_does_nothing_if_there_is_no_resource_to_resolve( 80 | FilterControllerEvent $event, 81 | Request $request, 82 | ParameterBag $parameterBag, 83 | $resolver 84 | ) { 85 | $event->getRequest()->willReturn($request); 86 | $request->attributes = $parameterBag; 87 | $parameterBag->get('_resources', [])->willReturn([]); 88 | 89 | $resolver->resolveResource(Argument::cetera())->shouldNotBeCalled(); 90 | 91 | $this->resolveResources($event); 92 | } 93 | 94 | function it_throws_a_not_found_exception_if_the_resource_could_not_be_found( 95 | FilterControllerEvent $event, 96 | Request $request, 97 | ParameterBag $parameterBag, 98 | $resolver, 99 | $customSyntaxParser, 100 | $normalizer 101 | ) { 102 | $event->getRequest()->willReturn($request); 103 | $request->attributes = $parameterBag; 104 | $customPath = '@app_user_repository::myMethod("myFirstParameter")'; 105 | 106 | $resources = [ 107 | 'user' => $customPath, 108 | ]; 109 | 110 | $parameterBag->get('_resources', [])->willReturn($resources); 111 | 112 | $customSyntaxParser->supports($customPath)->willReturn(true); 113 | $customSyntaxParser->parse($customPath)->willReturn($declaration = [ 114 | 'service' => 'app_user_repository', 115 | 'method' => 'myMethod', 116 | 'arguments' => ['myFirstParameter'], 117 | ]); 118 | $normalizer->normalizeDeclaration($declaration)->willReturn([ 119 | 'service' => 'app_user_repository', 120 | 'method' => 'myMethod', 121 | 'arguments' => ['myFirstParameter'], 122 | 'required' => true, 123 | ]); 124 | 125 | $resolver 126 | ->resolveResource('app_user_repository', 'myMethod', ['myFirstParameter']) 127 | ->willReturn(null) 128 | ; 129 | 130 | $this 131 | ->shouldThrow('Symfony\Component\HttpKernel\Exception\NotFoundHttpException') 132 | ->during('resolveResources', [$event]) 133 | ; 134 | } 135 | 136 | function it_does_not_throw_exception_if_required_is_set_to_false( 137 | FilterControllerEvent $event, 138 | Request $request, 139 | ParameterBag $parameterBag, 140 | $resolver, 141 | $customSyntaxParser, 142 | $container, 143 | $normalizer 144 | ) { 145 | $event->getRequest()->willReturn($request); 146 | $request->attributes = $parameterBag; 147 | $customPath = '@app_user_repository::myMethod("myFirstParameter")'; 148 | 149 | $resources = [ 150 | 'user' => $customPath, 151 | ]; 152 | 153 | $parameterBag->get('_resources', [])->willReturn($resources); 154 | 155 | $customSyntaxParser->supports($customPath)->willReturn(true); 156 | $customSyntaxParser->parse($customPath)->willReturn($declaration = [ 157 | 'service' => 'app_user_repository', 158 | 'method' => 'myMethod', 159 | 'arguments' => ['myFirstParameter'], 160 | 'required' => false, 161 | ]); 162 | $normalizer->normalizeDeclaration($declaration)->willReturn($declaration); 163 | 164 | $resolver 165 | ->resolveResource('app_user_repository', 'myMethod', ['myFirstParameter']) 166 | ->willReturn(null) 167 | ; 168 | 169 | $parameterBag->set('user', null)->shouldBeCalled(); 170 | $container->addResource('user', null)->shouldBeCalled(); 171 | 172 | $this->resolveResources($event); 173 | } 174 | } 175 | --------------------------------------------------------------------------------