ServiceValueResolver::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 *
5
 * (c) Yaroslav Honcharuk <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Yarhon\RouteGuardBundle\Controller\ArgumentResolver;
12
13
use Psr\Container\ContainerInterface;
14
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
15
use Symfony\Component\DependencyInjection\ServiceLocator;
16
use Symfony\Component\DependencyInjection\Exception\RuntimeException as ContainerRuntimeException;
17
use Yarhon\RouteGuardBundle\Exception\RuntimeException;
18
19
/**
20
 * Returns a service used as controller argument.
21
 *
22
 * @author Yaroslav Honcharuk <[email protected]>
23
 * @author Nicolas Grekas <[email protected]>
24
 */
25
final class ServiceValueResolver implements ArgumentValueResolverInterface
26
{
27
    private $container;
28
29 17
    public function __construct(ContainerInterface $container)
30
    {
31 17
        $this->container = $container;
32 17
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37 8
    public function supports(ArgumentResolverContextInterface $context, ArgumentMetadata $argument)
38
    {
39 8
        $controller = $context->getControllerName();
40 8
        $controller = ltrim($controller, '\\');
41
42 8
        if (!$serviceLocator = $this->getServiceLocator($controller)) {
43 6
            return false;
44
        }
45
46 2
        return $serviceLocator->has($argument->getName());
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52 2
    public function resolve(ArgumentResolverContextInterface $context, ArgumentMetadata $argument)
53
    {
54 2
        $controller = $context->getControllerName();
55 2
        $controller = ltrim($controller, '\\');
56 2
        $serviceLocator = $this->getServiceLocator($controller);
57
58
        try {
59 2
            return $serviceLocator->get($argument->getName());
60 1
        } catch (ContainerRuntimeException $e) {
61 1
            $message = $this->transformExceptionMessage($e->getMessage(), $controller, $argument->getName());
62 1
            throw new RuntimeException($message, 0, $e);
63
        }
64
    }
65
66
    /**
67
     * @param string $originalMessage
68
     * @param string $controller
69
     * @param string $argument
70
     *
71
     * @return string
72
     */
73 1
    private function transformExceptionMessage($originalMessage, $controller, $argument)
74
    {
75 1
        $what = sprintf('argument $%s of "%s()"', $argument, $controller);
76 1
        $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $originalMessage);
77
78 1
        if ($originalMessage === $message) {
79 1
            $message = sprintf('Cannot resolve %s: %s', $what, $message);
80
        }
81
82 1
        return $message;
83
    }
84
85
    /**
86
     * @param string $controller
87
     *
88
     * @return ServiceLocator|null
89
     */
90 10
    private function getServiceLocator($controller)
91
    {
92 10
        if ($this->container->has($controller)) {
93 4
            return $this->container->get($controller);
94
        }
95
96
        // Before Symfony 4.1 controller service locators used class:method naming
97
        // See \Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass
98 6
        $controller = str_replace('::', ':', $controller);
99
100 6
        if ($this->container->has($controller)) {
101 1
            return $this->container->get($controller);
102
        }
103
104 5
        return null;
105
    }
106
}
107