Completed
Push — develop ( e59301...62c23a )
by Neomerx
06:30
created

Application::getCacheSettingsProvider()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 0
cts 15
cp 0
rs 9.52
c 0
b 0
f 0
cc 3
nc 3
nop 0
crap 12
1
<?php namespace Limoncello\Application\Packages\Application;
2
3
/**
4
 * Copyright 2015-2018 [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 Limoncello\Application\CoreSettings\CoreData;
20
use Limoncello\Application\Settings\CacheSettingsProvider;
21
use Limoncello\Application\Settings\FileSettingsProvider;
22
use Limoncello\Application\Settings\InstanceSettingsProvider;
23
use Limoncello\Container\Container;
24
use Limoncello\Contracts\Application\ApplicationConfigurationInterface as A;
25
use Limoncello\Contracts\Application\CacheSettingsProviderInterface;
26
use Limoncello\Contracts\Container\ContainerInterface as LimoncelloContainerInterface;
27
use Limoncello\Contracts\Core\SapiInterface;
28
use Limoncello\Contracts\Provider\ProvidesSettingsInterface;
29
use Limoncello\Contracts\Routing\RouterInterface;
30
use Limoncello\Contracts\Settings\SettingsProviderInterface;
31
use Limoncello\Core\Application\Sapi;
32
use Limoncello\Core\Reflection\ClassIsTrait;
33
use Zend\Diactoros\Response\SapiEmitter;
34
35
/**
36
 * @package Limoncello\Application
37
 *
38
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
39
 */
40
class Application extends \Limoncello\Core\Application\Application
41
{
42
    use ClassIsTrait;
43
44
    /**
45
     * @var string
46
     */
47
    private $settingsPath;
48
49
    /**
50
     * @var callable|string|null
51
     */
52
    private $settingCacheMethod;
53
54
    /**
55
     * @var CacheSettingsProviderInterface|null
56
     */
57
    private $cacheSettingsProvider = null;
58
59
    /**
60
     * @param string                     $settingsPath
61
     * @param string|array|callable|null $settingCacheMethod
62
     * @param SapiInterface|null         $sapi
63
     */
64
    public function __construct(string $settingsPath, $settingCacheMethod = null, SapiInterface $sapi = null)
65
    {
66
        // The reason we do not use `callable` for the input parameter is that at the moment
67
        // of calling the callable might not exist. Therefore when created it will pass
68
        // `is_callable` check and will be used for getting the cached data.
69
        assert(is_null($settingCacheMethod) || is_string($settingCacheMethod) || is_array($settingCacheMethod));
70
71
        $this->settingsPath       = $settingsPath;
72
        $this->settingCacheMethod = $settingCacheMethod;
73
74
        $this->setSapi($sapi ?? new Sapi(new SapiEmitter()));
0 ignored issues
show
Documentation introduced by
new \Zend\Diactoros\Response\SapiEmitter() is of type object<Zend\Diactoros\Response\SapiEmitter>, but the function expects a object<Zend\HttpHandlerR...itter\EmitterInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The class Zend\Diactoros\Response\SapiEmitter has been deprecated with message: since 1.8.0. The package zendframework/zend-httphandlerrunner now provides this functionality.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
75
    }
76
77
    /**
78
     * @inheritdoc
79
     */
80
    protected function getCoreData(): array
81
    {
82
        return $this->getCacheSettingsProvider()->getCoreData();
83
    }
84
85
    /**
86
     * Get container from application. If `method` and `path` are specified the container will be configured
87
     * not only with global container configurators but with route's one as well.
88
     *
89
     * @param string|null $method
90
     * @param string|null $path
91
     *
92
     * @return LimoncelloContainerInterface
93
     *
94
     * @SuppressWarnings(PHPMD.StaticAccess)
95
     */
96
    public function createContainer(string $method = null, string $path = null): LimoncelloContainerInterface
97
    {
98
        $container = $this->createContainerInstance();
99
100
        $routeConfigurators = [];
101
        $coreData           = $this->getCoreData();
102
        if (empty($method) === false && empty($path) === false) {
103
            list(, , , , , $routeConfigurators) = $this->initRouter($coreData)->match($method, $path);
104
        }
105
106
        // configure container
107
        assert(!empty($coreData));
108
        $globalConfigurators = CoreData::getGlobalConfiguratorsFromData($coreData);
109
        $this->configureContainer($container, $globalConfigurators, $routeConfigurators);
110
111
        return $container;
112
    }
113
114
    /**
115
     * @return LimoncelloContainerInterface
116
     */
117
    protected function createContainerInstance(): LimoncelloContainerInterface
118
    {
119
        $container = new Container();
120
121
        $settingsProvider = $this->getCacheSettingsProvider();
122
        $container->offsetSet(SettingsProviderInterface::class, $settingsProvider);
123
        $container->offsetSet(CacheSettingsProviderInterface::class, $settingsProvider);
124
        $container->offsetSet(RouterInterface::class, $this->getRouter());
125
126
        return $container;
127
    }
128
129
    /**
130
     * @return string
131
     */
132
    protected function getSettingsPath(): string
133
    {
134
        return $this->settingsPath;
135
    }
136
137
    /**
138
     * @return callable|string|null
139
     */
140
    protected function getSettingCacheMethod()
141
    {
142
        return $this->settingCacheMethod;
143
    }
144
145
    /**
146
     * @return CacheSettingsProviderInterface
147
     *
148
     * @SuppressWarnings(PHPMD.ElseExpression)
149
     */
150
    private function getCacheSettingsProvider(): CacheSettingsProviderInterface
151
    {
152
        if ($this->cacheSettingsProvider === null) {
153
            $provider = new CacheSettingsProvider();
154
155
            if (is_callable($method = $this->getSettingCacheMethod()) === true) {
156
                $data = call_user_func($method);
157
                $provider->unserialize($data);
158
            } else {
159
                $appConfig = $this->createApplicationConfiguration();
160
                $appData   = $appConfig->get();
161
                $coreData  = new CoreData(
162
                    $appData[A::KEY_ROUTES_PATH],
163
                    $appData[A::KEY_CONTAINER_CONFIGURATORS_PATH],
164
                    $appData[A::KEY_PROVIDER_CLASSES]
165
                );
166
167
                $provider->setInstanceSettings($appConfig, $coreData, $this->createInstanceSettingsProvider($appData));
168
            }
169
170
            $this->cacheSettingsProvider = $provider;
171
        }
172
173
        return $this->cacheSettingsProvider;
174
    }
175
176
    /**
177
     * @return A
178
     */
179
    private function createApplicationConfiguration(): A
180
    {
181
        $classes = iterator_to_array(static::selectClasses($this->getSettingsPath(), A::class));
182
        assert(
183
            count($classes) > 0,
184
            'Settings path must contain a class implementing ApplicationConfigurationInterface.'
185
        );
186
        assert(
187
            count($classes) === 1,
188
            'Settings path must contain only one class implementing ApplicationConfigurationInterface.'
189
        );
190
        $class    = reset($classes);
191
        $instance = new $class();
192
        assert($instance instanceof A);
193
194
        return $instance;
195
    }
196
197
    /**
198
     * @param array $applicationData
199
     *
200
     * @return InstanceSettingsProvider
201
     */
202
    private function createInstanceSettingsProvider(array $applicationData): InstanceSettingsProvider
203
    {
204
        // Load all settings from path specified
205
        $provider = (new FileSettingsProvider($applicationData))->load($this->getSettingsPath());
206
207
        // Application settings have a list of providers which might have additional settings to load
208
        $providerClasses = $applicationData[A::KEY_PROVIDER_CLASSES];
209
        $selectedClasses = $this->selectClassImplements($providerClasses, ProvidesSettingsInterface::class);
210
        foreach ($selectedClasses as $providerClass) {
211
            /** @var ProvidesSettingsInterface $providerClass */
212
            foreach ($providerClass::getSettings() as $setting) {
213
                $provider->register($setting);
214
            }
215
        }
216
217
        return $provider;
218
    }
219
}
220