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

Router::getMatcher()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 4.3121

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 19
cts 26
cp 0.7308
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 19
nc 3
nop 0
crap 4.3121
1
<?php
2
3
namespace Bankiru\Api\Rpc\Routing;
4
5
use Symfony\Component\Config\ConfigCacheFactory;
6
use Symfony\Component\Config\ConfigCacheFactoryInterface;
7
use Symfony\Component\Config\ConfigCacheInterface;
8
use Symfony\Component\Config\Resource\FileResource;
9
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
10
11
final class Router implements MethodMatcher, WarmableInterface
12
{
13
    /** @var MethodCollectionLoader */
14
    private $loader;
15
    /** @var MethodCollection */
16
    private $collection;
17
    /** @var MethodMatcher */
18
    private $matcher;
19
    /**
20
     * @var string
21
     */
22
    private $name;
23
    /** @var ConfigCacheFactoryInterface */
24
    private $configCacheFactory;
25
    private $options = [];
26
27
    /**
28
     * Router constructor.
29
     *
30
     * @param MethodCollectionLoader $loader
31
     * @param string                 $name
32
     * @param array                  $options
33
     */
34 11
    public function __construct(MethodCollectionLoader $loader, $name, array $options = [])
35
    {
36 11
        $this->loader = $loader;
37 11
        $this->name   = $name;
38 11
        $this->setOptions($options);
39 11
    }
40
41
    /**
42
     * @return MethodCollection
43 11
     */
44 2
    public function getMethodCollection()
45 11
    {
46 2
        if (null === $this->collection) {
47 13
            $this->collection = $this->loader->loadCollection();
48 13
        }
49 11
50 13
        return $this->collection;
51
    }
52
53
    /** {@inheritdoc} */
54 9
    public function match($method)
55 1
    {
56 9
        return $this->getMatcher()->match($method);
57 1
    }
58 1
59 1
    /**
60 1
     * Warms up the cache.
61 1
     *
62
     * @param string $cacheDir The cache directory
63 1
     */
64
    public function warmUp($cacheDir)
65
    {
66
        $currentDir = $this->getOption('cache_dir');
67
68
        // force cache generation
69
        $this->setOption('cache_dir', $cacheDir);
70
71
        $this->getMatcher();
72
        $this->setOption('cache_dir', $currentDir);
73
    }
74
75
    /**
76
     * Sets an option.
77
     *
78
     * @param string $key   The key
79
     * @param mixed  $value The value
80
     *
81
     * @throws \InvalidArgumentException
82
     */
83
    public function setOption($key, $value)
84
    {
85
        $this->validateOption($key);
86
87
        $this->options[$key] = $value;
88
    }
89
90
    /**
91
     * Gets an option value.
92 1
     *
93
     * @param string $key The key
94 1
     *
95 1
     * @return mixed The value
96 1
     *
97 1
     * @throws \InvalidArgumentException
98
     */
99 1
    public function getOption($key)
100
    {
101 1
        if (!array_key_exists($key, $this->options)) {
102
            throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
103 1
        }
104 1
105
        return $this->options[$key];
106 1
    }
107 1
108
    /**
109 1
     * Sets options.
110 1
     *
111
     * Available options:
112 1
     *
113 1
     *   * cache_dir:              The cache directory (or null to disable caching)
114 1
     *   * debug:                  Whether to enable debugging or not (false by default)
115 1
     *
116 1
     * @param array $options An array of options
117 1
     *
118 1
     * @throws \InvalidArgumentException When unsupported option is provided
119 1
     */
120 11
    public function setOptions(array $options)
121
    {
122 11
        $this->options = [
123 11
            'cache_dir'           => null,
124 11
            'debug'               => false,
125 11
            'matcher_cache_class' => ucfirst($this->name) . 'MethodMatcher',
126
        ];
127
128
        // check option names and live merge, if errors are encountered Exception will be thrown
129 11
        $invalid = [];
130 11
        foreach ($options as $key => $value) {
131 11
            if (array_key_exists($key, $this->options)) {
132 12
                $this->options[$key] = $value;
133 11
            } else {
134 1
                $invalid[] = $key;
135
            }
136 11
        }
137
138 11
        if (!empty($invalid)) {
139
            throw new \InvalidArgumentException(
140
                sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid))
141
            );
142 1
        }
143 11
    }
144
145
    /**
146 1
     * @return MethodMatcher
147
     */
148 10
    private function getMatcher()
149
    {
150 9
        if (null !== $this->matcher) {
151
            return $this->matcher;
152
        }
153
154 9
        if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
155
            $this->matcher = new CollectionMatcher($this->getMethodCollection());
156
157
            return $this->matcher;
158
        }
159
160 9
        $cache = $this->getConfigCacheFactory()->cache(
161 9
            $this->options['cache_dir'] . '/rpc/' . $this->options['matcher_cache_class'] . '.php',
162 1
            function (ConfigCacheInterface $cache) {
163 1
                $dumper = new MatcherDumper();
164
165
                $options = [
166 1
                    'class' => $this->options['matcher_cache_class'],
167 1
                ];
168
169 1
                $resources   = $this->getMethodCollection()->getResources();
170 1
                $refl        = new \ReflectionClass(MatcherDumper::class);
171 1
                $resources[] = new FileResource($refl->getFileName());
172
173 1
                $cache->write($dumper->dump($this->getMethodCollection(), $options), $resources);
174 2
            }
175 9
        );
176 1
177 9
        require_once $cache->getPath();
178
179 9
        $this->matcher = new $this->options['matcher_cache_class']($cache);
180
181 9
        return $this->matcher;
182
    }
183
184
    /**
185
     * Provides the ConfigCache factory implementation, falling back to a
186
     * default implementation if necessary.
187
     *
188
     * @return ConfigCacheFactoryInterface $configCacheFactory
189
     */
190 9
    private function getConfigCacheFactory()
191
    {
192 9
        if (null === $this->configCacheFactory) {
193 9
            $this->configCacheFactory = new ConfigCacheFactory(true);
194 9
        }
195
196 9
        return $this->configCacheFactory;
197
    }
198
199
    /**
200
     * @param $key
201
     */
202
    private function validateOption($key)
203
    {
204
        if (!array_key_exists($key, $this->options)) {
205
            throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
206
        }
207
    }
208
}
209