ServiceParamConverter::apply()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 2
1
<?php
2
3
namespace Zalas\Bundle\ParamConverterBundle\Request\ParamConverter;
4
5
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
6
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
7
use Symfony\Component\DependencyInjection\ContainerInterface;
8
use Symfony\Component\HttpFoundation\Request;
9
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
10
11
class ServiceParamConverter implements ParamConverterInterface
12
{
13
    /**
14
     * @var ContainerInterface
15
     */
16
    private $container;
17
18
    /**
19
     * @param ContainerInterface $container
20
     */
21
    public function __construct(ContainerInterface $container)
22
    {
23
        $this->container = $container;
24
    }
25
26
    /**
27
     * @param Request        $request
28
     * @param ParamConverter $configuration
29
     *
30
     * @return bool
31
     */
32
    public function apply(Request $request, ParamConverter $configuration)
33
    {
34
        $object = $this->callService($request, $configuration);
35
36
        $class = $configuration->getClass();
37
        if ($object instanceof $class) {
38
            $request->attributes->set($configuration->getName(), $object);
39
40
            return true;
41
        }
42
43
        if ($configuration->isOptional()) {
44
            return false;
45
        }
46
47
        throw new NotFoundHttpException(sprintf('Object of class "%s" not found.', $class));
48
    }
49
50
    /**
51
     * @param ParamConverter $configuration
52
     *
53
     * @return bool
54
     */
55
    public function supports(ParamConverter $configuration)
56
    {
57
        $options = $configuration->getOptions();
58
59
        return !empty($options['service']) && !empty($options['method']);
60
    }
61
62
    /**
63
     * @param Request        $request
64
     * @param ParamConverter $configuration
65
     *
66
     * @return mixed
67
     */
68
    private function callService(Request $request, ParamConverter $configuration)
69
    {
70
        $options = $configuration->getOptions();
71
        $callable = $this->getCallable($options);
72
73
        return call_user_func_array($callable, $this->extractArguments($request, $options));
74
    }
75
76
    /**
77
     * @param Request $request
78
     * @param array   $options
79
     *
80
     * @return array
81
     */
82
    private function extractArguments(Request $request, array $options)
83
    {
84
        $arguments = isset($options['arguments']) && is_array($options['arguments']) ? $options['arguments'] : [];
85
86
        return array_map(
87
            function ($argument) use ($request) {
88
                return $request->attributes->get($argument);
89
            },
90
            $arguments
91
        );
92
    }
93
94
    /**
95
     * @param array $options
96
     *
97
     * @return array
98
     */
99
    private function getCallable(array $options)
100
    {
101
        $serviceId = $options['service'];
102
        $method = $options['method'];
103
        $service = $this->container->get($serviceId);
104
        $callable = [$service, $method];
105
106
        if (!is_callable($callable)) {
107
            throw new \InvalidArgumentException(sprintf(
108
                'The param converter is configured to use a non existent method "%s::%s()" on the "%s" service.',
109
                get_class($service), $method, $serviceId
110
            ));
111
        }
112
113
        return $callable;
114
    }
115
}
116