Completed
Push — develop ( 146147...e654c4 )
by Neomerx
02:05
created

Application::createInstanceSettingsProvider()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 19
c 0
b 0
f 0
rs 9.4285
ccs 0
cts 0
cp 0
cc 3
eloc 9
nc 3
nop 0
crap 12
1
<?php namespace Limoncello\Application\Packages\Application;
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 Limoncello\Application\Contracts\Settings\CacheSettingsProviderInterface;
20
use Limoncello\Application\CoreSettings\CoreData;
21
use Limoncello\Application\Settings\CacheSettingsProvider;
22
use Limoncello\Application\Settings\FileSettingsProvider;
23
use Limoncello\Application\Settings\InstanceSettingsProvider;
24
use Limoncello\Container\Container;
25
use Limoncello\Contracts\Application\ApplicationConfigurationInterface as A;
26
use Limoncello\Contracts\Container\ContainerInterface as LimoncelloContainerInterface;
27
use Limoncello\Contracts\Core\SapiInterface;
28
use Limoncello\Contracts\Provider\ProvidesSettingsInterface;
29
use Limoncello\Contracts\Settings\SettingsProviderInterface;
30
use Limoncello\Core\Application\Sapi;
31
use Limoncello\Core\Reflection\ClassIsTrait;
32
use Zend\Diactoros\Response\SapiEmitter;
33
34
/**
35
 * @package Limoncello\Application
36
 *
37
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
38
 */
39
class Application extends \Limoncello\Core\Application\Application
0 ignored issues
show
Bug introduced by
There is one abstract method createSettingsProvider in this class; you could implement it, or declare this class as abstract.
Loading history...
40
{
41
    use ClassIsTrait;
42
43
    /**
44
     * @var string
45
     */
46
    private $settingsPath;
47
48
    /**
49
     * @var callable|string|null
50
     */
51
    private $settingCacheMethod;
52
53
    /**
54
     * @var array|null
55
     */
56
    private $applicationSettings = null;
57
58
    /**
59 2
     * @var CacheSettingsProviderInterface|null
60
     */
61
    private $cacheSettingsProvider = null;
62
63
    /**
64 2
     * @param string                     $settingsPath
65
     * @param string|array|callable|null $settingCacheMethod
66 2
     * @param SapiInterface|null         $sapi
67 2
     */
68
    public function __construct(string $settingsPath, $settingCacheMethod = null, SapiInterface $sapi = null)
69 2
    {
70
        // The reason we do not use `callable` for the input parameter is that at the moment
71
        // of calling the callable might not exist. Therefore when created it will pass
72
        // `is_callable` check and will be used for getting the cached data.
73
        assert(is_null($settingCacheMethod) || is_string($settingCacheMethod) || is_array($settingCacheMethod));
74
75
        $this->settingsPath       = $settingsPath;
76
        $this->settingCacheMethod = $settingCacheMethod;
77
78
        $this->setSapi($sapi ?? new Sapi(new SapiEmitter()));
79
    }
80
81
    /**
82
     * @inheritdoc
83 2
     */
84
    protected function getCoreData(): array
85 2
    {
86
        return $this->getCacheSettingsProvider()->getCoreData();
87 2
    }
88 2
89 2
    /**
90
     * Get container from application. If `method` and `path` are specified the container will be configured
91 2
     * not only with global container configurators but with route's one as well.
92
     *
93 2
     * @param string|null $method
94 2
     * @param string|null $path
95 2
     *
96
     * @return LimoncelloContainerInterface
97
     *
98
     * @SuppressWarnings(PHPMD.StaticAccess)
99 2
     */
100 2
    public function createContainer(string $method = null, string $path = null): LimoncelloContainerInterface
101
    {
102 2
        $container = $this->createContainerInstance();
103
104
        $settingsProvider = $this->getCacheSettingsProvider();
105
        $container->offsetSet(SettingsProviderInterface::class, $settingsProvider);
106
        $container->offsetSet(CacheSettingsProviderInterface::class, $settingsProvider);
107
108
        $routeConfigurators = [];
109
        $coreData           = $this->getCoreData();
110 2
        if (empty($method) === false && empty($path) === false) {
111
            list(, , , , , $routeConfigurators) = $this->initRouter($coreData)->match($method, $path);
112 2
        }
113 2
114 1
        // configure container
115 1
        assert(!empty($coreData));
116
        $globalConfigurators = CoreData::getGlobalConfiguratorsFromData($coreData);
117 1
        $this->configureContainer($container, $globalConfigurators, $routeConfigurators);
118
119
        return $container;
120 2
    }
121
122
    /**
123
     * @return LimoncelloContainerInterface
124
     */
125
    protected function createContainerInstance(): LimoncelloContainerInterface
126 1
    {
127
        return new Container();
128
    }
129 1
130
    /**
131
     * @return string
132 1
     */
133 1
    protected function getSettingsPath(): string
134 1
    {
135
        return $this->settingsPath;
136 1
    }
137 1
138
    /**
139
     * @return callable|string|null
140
     */
141
    protected function getSettingCacheMethod()
142 1
    {
143 1
        return $this->settingCacheMethod;
144 1
    }
145
146 1
    /**
147
     * @return CacheSettingsProviderInterface
148 1
     */
149
    private function getCacheSettingsProvider(): CacheSettingsProviderInterface
150
    {
151
        if ($this->cacheSettingsProvider === null) {
152
            $provider = new CacheSettingsProvider();
153
154 2
            if (is_callable($method = $this->getSettingCacheMethod()) === true) {
155
                $data = call_user_func($method);
156 2
                $provider->unserialize($data);
157
            } else {
158
                $appSettings    = $this->getApplicationSettings();
159
                $coreData       = new CoreData(
160
                    $appSettings[A::KEY_ROUTES_PATH],
161
                    $appSettings[A::KEY_CONTAINER_CONFIGURATORS_PATH],
162 1
                    $appSettings[A::KEY_PROVIDER_CLASSES]
163
                );
164 1
165
                $provider->setInstanceSettings($coreData, $this->createInstanceSettingsProvider());
166
            }
167
168
            $this->cacheSettingsProvider = $provider;
169
        }
170 2
171
        return $this->cacheSettingsProvider;
172 2
    }
173
174
    /**
175
     * @return array
176
     */
177
    private function getApplicationSettings(): array
178
    {
179
        if ($this->applicationSettings === null) {
180
            $classes = iterator_to_array(static::selectClasses($this->getSettingsPath(), A::class));
181
            assert(
182
                count($classes) > 0,
183
                'Settings path must contain a class implementing ApplicationConfigurationInterface.'
184
            );
185
            assert(
186
                count($classes) === 1,
187
                'Settings path must contain only one class implementing ApplicationConfigurationInterface.'
188
            );
189
            $class    = reset($classes);
190
            $instance = new $class();
191
            assert($instance instanceof A);
0 ignored issues
show
Bug introduced by
The class Limoncello\Contracts\App...nConfigurationInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
192
193
            $this->applicationSettings = $instance->get();
194
        }
195
196
        return $this->applicationSettings;
197
    }
198
199
    /**
200
     * @return InstanceSettingsProvider
201
     */
202
    private function createInstanceSettingsProvider(): InstanceSettingsProvider
203
    {
204
        $applicationSettings = $this->getApplicationSettings();
205
206
        // Load all settings from path specified
207
        $provider = (new FileSettingsProvider($applicationSettings))->load($this->getSettingsPath());
208
209
        // Application settings have a list of providers which might have additional settings to load
210
        $providerClasses = $applicationSettings[A::KEY_PROVIDER_CLASSES];
211
        $selectedClasses = $this->selectClassImplements($providerClasses, ProvidesSettingsInterface::class);
212
        foreach ($selectedClasses as $providerClass) {
213
            /** @var ProvidesSettingsInterface $providerClass */
214
            foreach ($providerClass::getSettings() as $setting) {
215
                $provider->register($setting);
216
            }
217
        }
218
219
        return $provider;
220
    }
221
}
222