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

Application::createApplicationConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 12
cts 12
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 12
nc 1
nop 0
crap 1
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\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\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 CacheSettingsProviderInterface|null
55
     */
56
    private $cacheSettingsProvider = null;
57
58
    /**
59
     * @param string                     $settingsPath
60
     * @param string|array|callable|null $settingCacheMethod
61
     * @param SapiInterface|null         $sapi
62
     */
63 2
    public function __construct(string $settingsPath, $settingCacheMethod = null, SapiInterface $sapi = null)
64
    {
65
        // The reason we do not use `callable` for the input parameter is that at the moment
66
        // of calling the callable might not exist. Therefore when created it will pass
67
        // `is_callable` check and will be used for getting the cached data.
68 2
        assert(is_null($settingCacheMethod) || is_string($settingCacheMethod) || is_array($settingCacheMethod));
69
70 2
        $this->settingsPath       = $settingsPath;
71 2
        $this->settingCacheMethod = $settingCacheMethod;
72
73 2
        $this->setSapi($sapi ?? new Sapi(new SapiEmitter()));
74
    }
75
76
    /**
77
     * @inheritdoc
78
     */
79 2
    protected function getCoreData(): array
80
    {
81 2
        return $this->getCacheSettingsProvider()->getCoreData();
82
    }
83
84
    /**
85
     * Get container from application. If `method` and `path` are specified the container will be configured
86
     * not only with global container configurators but with route's one as well.
87
     *
88
     * @param string|null $method
89
     * @param string|null $path
90
     *
91
     * @return LimoncelloContainerInterface
92
     *
93
     * @SuppressWarnings(PHPMD.StaticAccess)
94
     */
95 2
    public function createContainer(string $method = null, string $path = null): LimoncelloContainerInterface
96
    {
97 2
        $container = $this->createContainerInstance();
98
99 2
        $routeConfigurators = [];
100 2
        $coreData           = $this->getCoreData();
101 2
        if (empty($method) === false && empty($path) === false) {
102 2
            list(, , , , , $routeConfigurators) = $this->initRouter($coreData)->match($method, $path);
103
        }
104
105
        // configure container
106 2
        assert(!empty($coreData));
107 2
        $globalConfigurators = CoreData::getGlobalConfiguratorsFromData($coreData);
108 2
        $this->configureContainer($container, $globalConfigurators, $routeConfigurators);
109
110 2
        return $container;
111
    }
112
113
    /**
114
     * @return LimoncelloContainerInterface
115
     */
116 2
    protected function createContainerInstance(): LimoncelloContainerInterface
117
    {
118 2
        $container = new Container();
119
120 2
        $settingsProvider = $this->getCacheSettingsProvider();
121 2
        $container->offsetSet(SettingsProviderInterface::class, $settingsProvider);
122 2
        $container->offsetSet(CacheSettingsProviderInterface::class, $settingsProvider);
123
124 2
        return $container;
125
    }
126
127
    /**
128
     * @return string
129
     */
130 1
    protected function getSettingsPath(): string
131
    {
132 1
        return $this->settingsPath;
133
    }
134
135
    /**
136
     * @return callable|string|null
137
     */
138 2
    protected function getSettingCacheMethod()
139
    {
140 2
        return $this->settingCacheMethod;
141
    }
142
143
    /**
144
     * @return CacheSettingsProviderInterface
145
     *
146
     * @SuppressWarnings(PHPMD.ElseExpression)
147
     */
148 2
    private function getCacheSettingsProvider(): CacheSettingsProviderInterface
149
    {
150 2
        if ($this->cacheSettingsProvider === null) {
151 2
            $provider = new CacheSettingsProvider();
152
153 2
            if (is_callable($method = $this->getSettingCacheMethod()) === true) {
154 1
                $data = call_user_func($method);
155 1
                $provider->unserialize($data);
156
            } else {
157 1
                $appConfig = $this->createApplicationConfiguration();
158 1
                $appData   = $appConfig->get();
159 1
                $coreData  = new CoreData(
160 1
                    $appData[A::KEY_ROUTES_PATH],
161 1
                    $appData[A::KEY_CONTAINER_CONFIGURATORS_PATH],
162 1
                    $appData[A::KEY_PROVIDER_CLASSES]
163
                );
164
165 1
                $provider->setInstanceSettings($appConfig, $coreData, $this->createInstanceSettingsProvider($appData));
166
            }
167
168 2
            $this->cacheSettingsProvider = $provider;
169
        }
170
171 2
        return $this->cacheSettingsProvider;
172
    }
173
174
    /**
175
     * @return A
176
     */
177 1
    private function createApplicationConfiguration(): A
178
    {
179 1
        $classes = iterator_to_array(static::selectClasses($this->getSettingsPath(), A::class));
180 1
        assert(
181 1
            count($classes) > 0,
182 1
            'Settings path must contain a class implementing ApplicationConfigurationInterface.'
183
        );
184 1
        assert(
185 1
            count($classes) === 1,
186 1
            'Settings path must contain only one class implementing ApplicationConfigurationInterface.'
187
        );
188 1
        $class    = reset($classes);
189 1
        $instance = new $class();
190 1
        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...
191
192 1
        return $instance;
193
    }
194
195
    /**
196
     * @param array $applicationData
197
     *
198
     * @return InstanceSettingsProvider
199
     */
200 1
    private function createInstanceSettingsProvider(array $applicationData): InstanceSettingsProvider
201
    {
202
        // Load all settings from path specified
203 1
        $provider = (new FileSettingsProvider($applicationData))->load($this->getSettingsPath());
204
205
        // Application settings have a list of providers which might have additional settings to load
206 1
        $providerClasses = $applicationData[A::KEY_PROVIDER_CLASSES];
207 1
        $selectedClasses = $this->selectClassImplements($providerClasses, ProvidesSettingsInterface::class);
208 1
        foreach ($selectedClasses as $providerClass) {
209
            /** @var ProvidesSettingsInterface $providerClass */
210 1
            foreach ($providerClass::getSettings() as $setting) {
211 1
                $provider->register($setting);
212
            }
213
        }
214
215 1
        return $provider;
216
    }
217
}
218