Completed
Push — master ( 32e652...8e829c )
by Neomerx
11:56
created

Application::createContainerInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 1
cp 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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\CoreSettings;
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\ApplicationSettingsInterface 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\Contracts\CoreSettingsInterface;
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
     * @param string                     $settingsPath
56
     * @param string|array|callable|null $settingCacheMethod
57
     * @param SapiInterface|null         $sapi
58
     */
59
    public function __construct(string $settingsPath, $settingCacheMethod = null, SapiInterface $sapi = null)
60
    {
61
        // The reason we do not use `callable` for the input parameter is that at the moment
62
        // of calling the callable might not exist. Therefore when created it will pass
63
        // `is_callable` check and will be used for getting the cached data.
64
        assert(is_null($settingCacheMethod) || is_string($settingCacheMethod) || is_array($settingCacheMethod));
65 3
66
        $this->settingsPath       = $settingsPath;
67
        $this->settingCacheMethod = $settingCacheMethod;
68
69
        $this->setSapi($sapi ?? new Sapi(new SapiEmitter()));
70 3
    }
71
72 3
    /**
73 3
     * Get container from application. If `method` and `path` are specified the container will be configured
74
     * not only with global container configurators but with route's one as well.
75 3
     *
76
     * @param string|null $method
77
     * @param string|null $path
78
     *
79
     * @return LimoncelloContainerInterface
80
     *
81
     * @SuppressWarnings(PHPMD.StaticAccess)
82
     */
83
    public function createContainer(string $method = null, string $path = null): LimoncelloContainerInterface
84
    {
85
        $container = $this->createContainerInstance();
86
87
        $settingsProvider = $this->createSettingsProvider();
88
        $container->offsetSet(SettingsProviderInterface::class, $settingsProvider);
89 1
        $container->offsetSet(CacheSettingsProviderInterface::class, $settingsProvider);
90
91 1
        $coreSettings = $settingsProvider->get(CoreSettingsInterface::class);
92
93 1
        $routeConfigurators = [];
94 1
        if (empty($method) === false && empty($path) === false) {
95 1
            list(, , , , , $routeConfigurators) = $this->initRouter($coreSettings)->match($method, $path);
96
        }
97 1
98
        // configure container
99 1
        $globalConfigurators = CoreSettings::getGlobalConfiguratorsFromData($coreSettings);
100 1
        $this->configureContainer($container, $globalConfigurators, $routeConfigurators);
101 1
102
        return $container;
103
    }
104
105 1
    /**
106 1
     * @return SettingsProviderInterface
107
     *
108 1
     * @SuppressWarnings(PHPMD.ElseExpression)
109
     */
110
    protected function createSettingsProvider(): SettingsProviderInterface
111
    {
112
        $provider = new CacheSettingsProvider();
113
        if (is_callable($method = $this->getSettingCacheMethod()) === true) {
114
            $data = call_user_func($method);
115
            $provider->unserialize($data);
116 1
        } else {
117
            $provider->setInstanceSettings($this->createFileSettingsProvider());
118 1
        }
119 1
120 1
        return $provider;
121 1
    }
122
123
    /**
124
     * @return InstanceSettingsProvider
125
     */
126 1
    protected function createFileSettingsProvider(): InstanceSettingsProvider
127
    {
128
        // Load all settings from path specified
129
        $provider = (new FileSettingsProvider())->load($this->getSettingsPath());
130
131
        // Application settings have a list of providers which might have additional settings to load
132
        $appSettings     = $provider->get(A::class);
133
        $providerClasses = $appSettings[A::KEY_PROVIDER_CLASSES];
134
        foreach ($this->selectClassImplements($providerClasses, ProvidesSettingsInterface::class) as $providerClass) {
135
            /** @var ProvidesSettingsInterface $providerClass */
136
            foreach ($providerClass::getSettings() as $setting) {
137
                $provider->register($setting);
138
            }
139
        }
140
141
        // App settings (paths, lists) --> core settings (container configurators, routes, middleware and etc).
142
        $routesPath     = $appSettings[A::KEY_ROUTES_PATH];
143
        $containersPath = $appSettings[A::KEY_CONTAINER_CONFIGURATORS_PATH];
144
        $coreSettings   = new CoreSettings($routesPath, $containersPath, $providerClasses);
145
146
        $provider->register($coreSettings);
147
148
        return $provider;
149
    }
150
151
    /**
152
     * @return LimoncelloContainerInterface
153
     */
154
    protected function createContainerInstance(): LimoncelloContainerInterface
155
    {
156
        return new Container();
157
    }
158
159
    /**
160 1
     * @return string
161
     */
162 1
    protected function getSettingsPath(): string
163
    {
164
        return $this->settingsPath;
165
    }
166
167
    /**
168 1
     * @return callable|string|null
169
     */
170 1
    protected function getSettingCacheMethod()
171
    {
172 1
        return $this->settingCacheMethod;
173 1
    }
174
}
175