Factory::createConfig()   A
last analyzed

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 8
nop 1
dl 0
loc 18
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Webino™ (http://webino.sk)
4
 *
5
 * @link        https://github.com/webino for the canonical source repository
6
 * @copyright   Copyright (c) 2015-2017 Webino, s.r.o. (http://webino.sk)
7
 * @author      Peter Bačinský <[email protected]>
8
 * @license     BSD-3-Clause
9
 */
10
11
namespace WebinoAppLib;
12
13
use WebinoAppLib\Application\AbstractBaseApplication;
14
use WebinoAppLib\Application\Config;
15
use WebinoAppLib\Application\CoreConfig;
16
use WebinoAppLib\Exception\DomainException;
17
use WebinoAppLib\Exception\InvalidArgumentException;
18
use WebinoAppLib\Service\DebuggerInterface;
19
use Zend\ServiceManager\ServiceManager;
20
21
/**
22
 * Class Factory
23
 */
24
final class Factory
25
{
26
    /**
27
     * Application debugger file path
28
     */
29
    const DEBUGGER_PATH = 'config/debugger.php';
30
31
    /**
32
     * Application configuration file path
33
     */
34
    const CONFIG_PATH = 'config/application.php';
35
36
    /**
37
     * @param array|object $config
38
     * @param DebuggerInterface $debugger
39
     * @return Application\AbstractBaseApplication
40
     */
41
    public function create($config = null, DebuggerInterface $debugger = null)
42
    {
43
        $_debugger = $this->createDebugger($debugger);
44
        $_config   = $this->createConfig($config);
0 ignored issues
show
Bug introduced by
It seems like $config defined by parameter $config on line 41 can also be of type object; however, WebinoAppLib\Factory::createConfig() does only seem to accept array|object<WebinoAppLi...pplication\Config>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
45
46
        $services = $this->createServices($_config);
47
        $services->setService(Application::DEBUGGER, $_debugger);
48
49
        $app = $services->get(Application::SERVICE);
50
        if (!($app instanceof AbstractBaseApplication)) {
51
            throw (new DomainException('Expected application type %s but got %s'))
52
                ->format(AbstractBaseApplication::class, get_class($app));
53
        }
54
55
        return $app;
56
    }
57
58
    /**
59
     * @param DebuggerInterface $debugger
60
     * @return mixed|DebuggerInterface|\WebinoAppLib\Service\NullDebugger
61
     */
62
    private function createDebugger(DebuggerInterface $debugger = null)
63
    {
64
        if (null !== $debugger) {
65
            return $debugger;
66
        }
67
68
        $filePath = $this::DEBUGGER_PATH;
69
        if (!@stream_resolve_include_path($filePath)) {
70
            return $debugger;
71
        }
72
73
        /** @noinspection PhpIncludeInspection */
74
        $created = require $filePath;
75
        if (null === $created) {
76
            return null;
77
        }
78
        if (!($created instanceof DebuggerInterface)) {
79
            throw (new DomainException('Expected type of included debugger is %s but got %s'))
80
                ->format(DebuggerInterface::class, get_class($created));
81
        }
82
83
        return $created;
84
    }
85
86
    /**
87
     * @param array|Config $config
88
     * @return array
89
     */
90
    private function normalizeConfig($config)
91
    {
92
        if (null === $config) {
93
            return [];
94
        }
95
        if (is_array($config)) {
96
            return $config;
97
        }
98
        if (method_exists($config, 'toArray')) {
99
            return $config->toArray();
100
        }
101
102
        throw (new InvalidArgumentException('Expected config as %s but got %s'))
103
            ->format('array or object with toArray() method', $config);
104
    }
105
106
    /**
107
     * @param array|Config|null $config
108
     * @return Config
109
     * @throws InvalidArgumentException
110
     */
111
    private function createConfig($config)
112
    {
113
        if (null !== $config) {
114
            $normalized = $this->normalizeConfig($config);
115
        }
116
117
        $filePath = $this::CONFIG_PATH;
118
        if (@stream_resolve_include_path($filePath)) {
119
            /** @noinspection PhpIncludeInspection */
120
            $normalized = $this->normalizeConfig(require $filePath);
121
        }
122
123
        if (empty($normalized)) {
124
            $normalized = (new CoreConfig)->toArray();
125
        }
126
127
        return new Config($normalized, true);
128
    }
129
130
    /**
131
     * @param Config $config
132
     * @return ServiceManager
133
     */
134
    private function createServices(Config $config)
135
    {
136
        /** @var Config $coreConfig */
137
        $coreConfig = $config->get(CoreConfig::CORE);
138
        if (null === $coreConfig) {
139
            throw (new DomainException('Expected %s node in the application config'))
140
                ->format(CoreConfig::CORE);
141
        }
142
143
        $servicesConfig = $coreConfig->get(CoreConfig::SERVICES);
144
        if (null === $servicesConfig) {
145
            throw (new DomainException('Expected %s node in the application %s config node'))
146
                ->format(CoreConfig::SERVICES, CoreConfig::CORE);
147
        }
148
149
        $services = new ServiceManager;
150
        $this->configureServices($services, $coreConfig);
151
152
        $services->setService(Application::CORE_CONFIG, $coreConfig);
153
        $services->setService(Application::CONFIG, $config);
154
155
        return $services;
156
    }
157
158
    /**
159
     * Configure service manager invokables and factories only
160
     *
161
     * @param ServiceManager $services
162
     * @param Config $coreConfig
163
     */
164
    private function configureServices(ServiceManager $services, Config $coreConfig)
165
    {
166
        $config = $coreConfig[CoreConfig::SERVICES];
167
168 View Code Duplication
        if (!empty($config[CoreConfig::INVOKABLES])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
169
            foreach ($config[CoreConfig::INVOKABLES] as $name => $service) {
170
                $services->setInvokableClass($name, $service);
171
            }
172
        }
173
174 View Code Duplication
        if (!empty($config[CoreConfig::FACTORIES])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
            foreach ($config[CoreConfig::FACTORIES] as $name => $service) {
176
                $services->setFactory($name, $service);
177
            }
178
        }
179
180
        if (!empty($config[CoreConfig::INITIALIZERS])) {
181
            foreach ($config[CoreConfig::INITIALIZERS] as $initializer) {
182
                $services->addInitializer($initializer);
183
            }
184
        }
185
    }
186
}
187