Passed
Pull Request — master (#9)
by Pavel
11:27
created

ControllerListener::getConfigurations()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5.3906

Importance

Changes 0
Metric Value
dl 0
loc 20
c 0
b 0
f 0
ccs 12
cts 16
cp 0.75
rs 8.8571
cc 5
eloc 13
nc 5
nop 1
crap 5.3906
1
<?php
2
3
/*
4
 * Copyright (c) 2010-2017 Fabien Potencier
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is furnished
11
 * to do so, subject to t * *he following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in all
14
 * copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 *
24
 */
25
26
namespace Bankiru\Api\Rpc\Listener;
27
28
use Bankiru\Api\Rpc\Event\FilterControllerEvent;
29
use Bankiru\Api\Rpc\RpcEvents;
30
use Doctrine\Common\Annotations\Reader;
31
use Doctrine\Common\Util\ClassUtils;
32
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
33
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
34
35
/**
36
 * Adopted SensioFrameworkExtraBundle Controller listener
37
 *
38
 * The ControllerListener class parses annotation blocks located in
39
 * controller classes.
40
 *
41
 * @author Pavel Batanov <[email protected]>
42
 */
43
final class ControllerListener implements EventSubscriberInterface
44
{
45
    /**
46
     * @var Reader
47
     */
48
    private $reader;
49
50
    /**
51
     * Constructor.
52
     *
53
     * @param Reader $reader An Reader instance
54
     */
55 8
    public function __construct(Reader $reader)
56
    {
57 8
        $this->reader = $reader;
58 8
    }
59
60
    /**
61
     * Modifies the Request object to apply configuration information found in
62
     * controllers annotations like the template to render or HTTP caching
63
     * configuration.
64
     *
65
     * @param FilterControllerEvent $event A FilterControllerEvent instance
66
     */
67 8
    public function onKernelController(FilterControllerEvent $event)
68
    {
69 8
        $controller = $event->getController();
70
71 8
        if (!is_array($controller) && method_exists($controller, '__invoke')) {
72
            $controller = [$controller, '__invoke'];
73
        }
74
75 8
        if (!is_array($controller)) {
76
            return;
77
        }
78
79
        $className =
80 8
            class_exists('Doctrine\Common\Util\ClassUtils')
81 8
                ? ClassUtils::getClass($controller[0])
82 8
                : get_class($controller[0]);
83
84 8
        $object = new \ReflectionClass($className);
85 8
        $method = $object->getMethod($controller[1]);
86
87 8
        $classConfigurations  = $this->getConfigurations($this->reader->getClassAnnotations($object));
88 8
        $methodConfigurations = $this->getConfigurations($this->reader->getMethodAnnotations($method));
89
90 8
        $configurations = [];
91 8
        foreach (array_merge(array_keys($classConfigurations), array_keys($methodConfigurations)) as $key) {
92 2
            if (!array_key_exists($key, $classConfigurations)) {
93 2
                $configurations[$key] = $methodConfigurations[$key];
94 2
            } elseif (!array_key_exists($key, $methodConfigurations)) {
95
                $configurations[$key] = $classConfigurations[$key];
96
            } else {
97
                if (is_array($classConfigurations[$key])) {
98
                    if (!is_array($methodConfigurations[$key])) {
99
                        throw new \UnexpectedValueException(
100
                            'Configurations should both be an array or both not be an array'
101
                        );
102
                    }
103
                    $configurations[$key] = array_merge($classConfigurations[$key], $methodConfigurations[$key]);
104
                } else {
105
                    // method configuration overrides class configuration
106
                    $configurations[$key] = $methodConfigurations[$key];
107
                }
108
            }
109 8
        }
110
111 8
        $request = $event->getRequest();
112 8
        foreach ($configurations as $key => $attributes) {
113 2
            $request->getAttributes()->set($key, $attributes);
114 8
        }
115 8
    }
116
117 1
    public static function getSubscribedEvents()
118
    {
119
        return [
120 1
            RpcEvents::CONTROLLER => ['onKernelController', 255],
121 1
        ];
122
    }
123
124 8
    protected function getConfigurations(array $annotations)
125
    {
126 8
        $configurations = [];
127 8
        foreach ($annotations as $configuration) {
128 8
            if ($configuration instanceof ConfigurationInterface) {
129 2
                $index = '_' . $configuration->getAliasName();
130 2
                if ($configuration->allowArray()) {
131
                    $configurations[$index][] = $configuration;
132 2
                } elseif (!isset($configurations[$index])) {
133 2
                    $configurations[$index] = $configuration;
134 2
                } else {
135
                    throw new \LogicException(
136
                        sprintf('Multiple "%s" annotations are not allowed.', $configuration->getAliasName())
137
                    );
138
                }
139 2
            }
140 8
        }
141
142 8
        return $configurations;
143
    }
144
}
145