Completed
Push — master ( 146147...1776d4 )
by Neomerx
01:58
created

CoreData::addRoutes()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 9
cts 9
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 9
nc 6
nop 1
crap 4
1
<?php namespace Limoncello\Application\CoreSettings;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use FastRoute\DataGenerator\GroupCountBased as GroupCountBasedGenerator;
20
use Generator;
21
use Limoncello\Contracts\Application\ContainerConfiguratorInterface;
22
use Limoncello\Contracts\Application\MiddlewareInterface;
23
use Limoncello\Contracts\Application\RoutesConfiguratorInterface;
24
use Limoncello\Contracts\Container\ContainerInterface;
25
use Limoncello\Contracts\Provider\ProvidesContainerConfiguratorsInterface;
26
use Limoncello\Contracts\Provider\ProvidesMiddlewareInterface;
27
use Limoncello\Contracts\Provider\ProvidesRouteConfiguratorsInterface;
28
use Limoncello\Contracts\Routing\GroupInterface;
29
use Limoncello\Contracts\Routing\RouterInterface;
30
use Limoncello\Core\Application\BaseCoreData;
31
use Limoncello\Core\Reflection\CheckCallableTrait;
32
use Limoncello\Core\Reflection\ClassIsTrait;
33
use Limoncello\Core\Routing\Dispatcher\GroupCountBased as GroupCountBasedDispatcher;
34
use Limoncello\Core\Routing\Group;
35
use Limoncello\Core\Routing\Router;
36
37
/**
38
 * @package Limoncello\Application
39
 *
40
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
41
 */
42
class CoreData extends BaseCoreData
43
{
44
    use ClassIsTrait, CheckCallableTrait;
45
46
    /**
47
     * @var string
48
     */
49
    private $routesPath;
50
51
    /**
52
     * @var string
53
     */
54
    private $configuratorsPath;
55
56
    /**
57
     * @var string[]
58
     */
59
    private $providerClasses;
60
61
    /**
62
     * @param string   $routesPath
63
     * @param string   $configuratorsPath
64
     * @param string[] $providerClasses
65
     */
66 7
    public function __construct(string $routesPath, string $configuratorsPath, array $providerClasses)
67
    {
68 7
        $this->routesPath        = $routesPath;
69 7
        $this->configuratorsPath = $configuratorsPath;
70 7
        $this->providerClasses   = $providerClasses;
71
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76 7
    public function get(): array
77
    {
78 7
        list ($generatorClass, $dispatcherClass) = $this->getGeneratorAndDispatcherClasses();
79
80
        $routesData = $this
81 7
            ->createRouter($generatorClass, $dispatcherClass)
82 7
            ->getCachedRoutes($this->addRoutes($this->createGroup()));
83
84 7
        $globalConfigurators = iterator_to_array($this->getGlobalContainerConfigurators(), false);
85 7
        $globalMiddleware    = iterator_to_array($this->getGlobalMiddleWareHandlers(), false);
86
87
        return [
88 7
            static::KEY_ROUTER_PARAMS                  => [
89 7
                static::KEY_ROUTER_PARAMS__GENERATOR  => $generatorClass,
90 7
                static::KEY_ROUTER_PARAMS__DISPATCHER => $dispatcherClass,
91
            ],
92 7
            static::KEY_ROUTES_DATA                    => $routesData,
93 7
            static::KEY_GLOBAL_CONTAINER_CONFIGURATORS => $globalConfigurators,
94 7
            static::KEY_GLOBAL_MIDDLEWARE              => $globalMiddleware,
95
        ];
96
    }
97
98
    /**
99
     * @return array
100
     */
101 7
    protected function getGeneratorAndDispatcherClasses(): array
102
    {
103 7
        return [GroupCountBasedGenerator::class, GroupCountBasedDispatcher::class];
104
    }
105
106
    /**
107
     * @return Generator
108
     */
109 7
    protected function getGlobalContainerConfigurators(): Generator
110
    {
111 7
        $interfaceName = ContainerConfiguratorInterface::class;
112 7
        foreach ($this->selectClasses($this->getConfiguratorsPath(), $interfaceName) as $configuratorClass) {
113 7
            $configurator = [$configuratorClass, ContainerConfiguratorInterface::CONTAINER_METHOD_NAME];
114 7
            assert($this->isValidContainerConfigurator($configurator) === true);
115 7
            yield $configurator;
116
        }
117
118 7
        $interfaceName = ProvidesContainerConfiguratorsInterface::class;
119 7
        foreach ($this->selectClassImplements($this->getProviderClasses(), $interfaceName) as $providerClass) {
120
            /** @var ProvidesContainerConfiguratorsInterface $providerClass */
121 7
            foreach ($providerClass::getContainerConfigurators() as $configuratorClass) {
122 7
                $configurator = [$configuratorClass, ContainerConfiguratorInterface::CONTAINER_METHOD_NAME];
123 7
                assert($this->isValidContainerConfigurator($configurator) === true);
124 7
                yield $configurator;
125
            }
126
        }
127
    }
128
129
    /**
130
     * @param GroupInterface $group
131
     *
132
     * @return GroupInterface
133
     */
134 7
    protected function addRoutes(GroupInterface $group): GroupInterface
135
    {
136 7
        $interfaceName = RoutesConfiguratorInterface::class;
137 7
        foreach ($this->selectClasses($this->getRoutesPath(), $interfaceName) as $routesConfClass) {
138
            /** @var RoutesConfiguratorInterface $routesConfClass */
139 7
            $routesConfClass::configureRoutes($group);
140
        }
141
142 7
        $interfaceName = ProvidesRouteConfiguratorsInterface::class;
143 7
        foreach ($this->selectClassImplements($this->getProviderClasses(), $interfaceName) as $providerClass) {
144
            /** @var ProvidesRouteConfiguratorsInterface $providerClass */
145 7
            foreach ($providerClass::getRouteConfigurators() as $routesConfClass) {
146
                /** @var RoutesConfiguratorInterface $routesConfClass */
147 7
                $routesConfClass::configureRoutes($group);
148
            }
149
        }
150
151 7
        return $group;
152
    }
153
154
    /**
155
     * @return Generator
156
     */
157 7
    protected function getGlobalMiddleWareHandlers(): Generator
158
    {
159
        // select global middleware from routes
160 7
        foreach ($this->selectClasses($this->getRoutesPath(), RoutesConfiguratorInterface::class) as $selectClass) {
161
            /** @var RoutesConfiguratorInterface $selectClass */
162 7
            foreach ($selectClass::getMiddleware() as $middlewareClass) {
163 7
                $handler = [$middlewareClass, MiddlewareInterface::MIDDLEWARE_METHOD_NAME];
164 7
                yield $handler;
165
            }
166
        }
167
168
        // select global middleware from providers
169 7
        $interfaceName = ProvidesMiddlewareInterface::class;
170 7
        foreach ($this->selectClassImplements($this->getProviderClasses(), $interfaceName) as $providerClass) {
171
            /** @var ProvidesMiddlewareInterface $providerClass */
172 7
            foreach ($providerClass::getMiddleware() as $middlewareClass) {
173 7
                $handler = [$middlewareClass, MiddlewareInterface::MIDDLEWARE_METHOD_NAME];
174 7
                yield $handler;
175
            }
176
        }
177
    }
178
179
    /**
180
     * @return GroupInterface
181
     */
182 7
    protected function createGroup(): GroupInterface
183
    {
184 7
        return new Group();
185
    }
186
187
    /**
188
     * @param string $generatorClass
189
     * @param string $dispatcherClass
190
     *
191
     * @return RouterInterface
192
     */
193 7
    protected function createRouter(string $generatorClass, string $dispatcherClass): RouterInterface
194
    {
195 7
        return new Router($generatorClass, $dispatcherClass);
196
    }
197
198
    /**
199
     * @return string
200
     */
201 7
    protected function getConfiguratorsPath(): string
202
    {
203 7
        return $this->configuratorsPath;
204
    }
205
206
    /**
207
     * @return string[]
208
     */
209 7
    protected function getProviderClasses(): array
210
    {
211 7
        return $this->providerClasses;
212
    }
213
214
    /**
215
     * @return string
216
     */
217 7
    protected function getRoutesPath(): string
218
    {
219 7
        return $this->routesPath;
220
    }
221
222
    /**
223
     * @param string|array|callable $mightBeConfigurator
224
     *
225
     * @return bool
226
     */
227 7
    private function isValidContainerConfigurator($mightBeConfigurator): bool
228
    {
229 7
        return $this->checkPublicStaticCallable($mightBeConfigurator, [ContainerInterface::class]);
230
    }
231
}
232