CoreData   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 202
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 10
dl 0
loc 202
ccs 61
cts 61
cp 1
rs 10
c 0
b 0
f 0

12 Methods

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