Passed
Push — master ( a5ef88...f5262c )
by Mathieu
14:16
created

Suricate::configureAppMode()   B

Complexity

Conditions 10
Paths 96

Size

Total Lines 52
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 23.8348

Importance

Changes 7
Bugs 1 Features 0
Metric Value
cc 10
eloc 42
c 7
b 1
f 0
nc 96
nop 0
dl 0
loc 52
ccs 14
cts 29
cp 0.4828
crap 23.8348
rs 7.6666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use InvalidArgumentException;
8
use Suricate\Cache\Apc as CacheApc;
9
use Suricate\Cache\File as CacheFile;
10
use Suricate\Cache\Memcache as CacheMemcache;
11
use Suricate\Cache\Memcached as CacheMemcached;
12
use Suricate\Cache\Redis as CacheRedis;
13
use Suricate\Event\EventDispatcher;
14
use Suricate\Session\Native as SessionNative;
15
16
/**
17
 * Suricate - Another micro PHP framework
18
 *
19
 * @author      Mathieu LESNIAK <[email protected]>
20
 * @copyright   2013-2023 Mathieu LESNIAK
21
 * @version     0.5.0
22
 * @package     Suricate
23
 *
24
 * @method static \Suricate\App                     App($newInstance = false)             Get instance of App service
25
 * @method static \Suricate\Cache                   Cache($newInstance = false)           Get instance of Cache service
26
 * @method static \Suricate\CacheMemcache           CacheMemcache($newInstance = false)   Get instance of CacheMemcache service
27
 * @method static \Suricate\CacheMemcached          CacheMemcached($newInstance = false)  Get instance of CacheMemcached service
28
 * @method static \Suricate\CacheRedis              CacheRedis($newInstance = false)      Get instance of CacheRedis service
29
 * @method static \Suricate\CacheApc                CacheApc($newInstance = false)        Get instance of CacheApc service
30
 * @method static \Suricate\CacheFile               CacheFile($newInstance = false)       Get instance of CacheFile service
31
 * @method static \Suricate\Curl                    Curl($newInstance = false)            Get instance of Curl service
32
 * @method static \Suricate\Database                Database($newInstance = false)        Get instance of Database service
33
 * @method static \Suricate\Error                   Error($newInstance = false)           Get instance of Error service
34
 * @method static \Suricate\Event\EventDispatcher   EventDispatcher($newInstance = false) Get instance of EventDispatcher service
35
 * @method static \Suricate\I18n                    I18n($newInstance = false)            Get instance of I18n service
36
 * @method static \Suricate\Logger                  Logger($newInstance = false)          Get instance of Logger service
37
 * @method static \Suricate\Request                 Request($newInstance = false)         Get instance of Request service
38
 * @method static \Suricate\Request                 Response($newInstance = false)        Get instance of Request/Response service
39
 * @method static \Suricate\Router                  Router($newInstance = false)          Get instance of Router service
40
 * @method static \Suricate\Session                 Session($newInstance = false)         Get instance of Session service
41
 * @method static \Suricate\SessionNative           SessionNative($newInstance = false)   Get instance of Session service
42
 * @method static \Suricate\SessionCookie           SessionCookie($newInstance = false)   Get instance of Session service
43
 * @method static \Suricate\SessionMemcache         SessionMemcache($newInstance = false) Get instance of Session service
44
 */
45
46
class Suricate
47
{
48
    const VERSION = '0.5.0';
49
50
    const CONF_DIR = '/conf/';
51
52
    private $config = [];
53
    private $configFile = [];
54
55
    private $useAutoloader = false;
56
57
    private static $servicesContainer;
58
    private static $servicesRepository;
59
60
    private $servicesList = [
61
        'App' => App::class,
62
        'Cache' => Cache::class,
63
        'CacheMemcache' => CacheMemcache::class,
64
        'CacheMemcached' => CacheMemcached::class,
65
        'CacheRedis' => CacheRedis::class,
66
        'CacheApc' => CacheApc::class,
67
        'CacheFile' => CacheFile::class,
68
        'Curl' => Curl::class,
69
        'Database' => Database::class,
70
        'Error' => Error::class,
71
        'EventDispatcher' => EventDispatcher::class,
72
        'I18n' => I18n::class,
73
        'Logger' => Logger::class,
74
        'Request' => Request::class,
75
        'Response' => Request::class,
76
        'Router' => Router::class,
77
        'Session' => Session::class,
78
        'SessionNative' => SessionNative::class,
79
        'SessionCookie' => '\Suricate\Session\Cookie',
80
        'SessionMemcache' => '\Suricate\Session\Memcache'
81
    ];
82 8
83
    /**
84 8
     * Suricate contructor
85 6
     *
86
     * @param array $paths Application paths
87
     * @param string|array|null $configFile path of configuration file(s)
88
     *
89 8
     * @SuppressWarnings(PHPMD.StaticAccess)
90
     */
91 8
    public function __construct($paths = [], $configFile = null)
92 8
    {
93
        if ($configFile !== null) {
94 8
            $this->setConfigFile($configFile);
95
        }
96
97
        // Load helpers
98
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php';
99
100
        $this->loadConfig();
101 8
        $this->setAppPaths($paths);
102 8
103 8
        if ($this->useAutoloader) {
104
            // Configure autoloader
105 8
            require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php';
106
            AutoLoader::register();
107 8
        }
108 8
109
        // Define error handler
110
        set_exception_handler(['\Suricate\Error', 'handleException']);
111
        set_error_handler(['\Suricate\Error', 'handleError']);
112
        register_shutdown_function(['\Suricate\Error', 'handleShutdownError']);
113
114
        self::$servicesRepository = new Container();
115 1
116
        $this->initServices();
117 1
    }
118
119
    /**
120 8
     * Get app configuration
121
     *
122 8
     * @return array
123
     */
124
    public function getConfig(): array
125
    {
126 8
        return $this->config;
127
    }
128
129
    private function setAppPaths($paths = [])
130
    {
131
        foreach ($paths as $key => $value) {
132 8
            $this->config['App']['path.' . $key] = realpath($value);
133
        }
134 8
135
        return $this;
136 8
    }
137 8
    /**
138
     * Initialize Framework services
139
     * @return void
140
     */
141
    private function initServices()
142
    {
143 8
        self::$servicesRepository->setWarehouse($this->servicesList);
144
145 8
        self::$servicesRepository['Request']->parse();
146 8
        if (isset($this->config['App']['locale'])) {
147 8
            $this->config['I18n'] = [
148 8
                'locale' => $this->config['App']['locale']
149
            ];
150
        }
151
152
        // Define constants
153
        if (isset($this->config['Constants'])) {
154 8
            foreach (
155
                $this->config['Constants']
156
                as $constantName => $constantValue
157
            ) {
158 8
                $constantName = strtoupper($constantName);
159
                define($constantName, $constantValue);
160 1
            }
161
        }
162
163 1
        // first sync, && init, dependency to Suricate::request
164 1
        self::$servicesContainer = clone self::$servicesRepository;
165
166
        foreach (array_keys($this->servicesList) as $serviceName) {
167
            if (isset($this->config[$serviceName])) {
168
                self::$servicesRepository[$serviceName]->configure(
169 8
                    $this->config[$serviceName]
170 8
                );
171
172 1
                /**
173
                 TODO : remove sync in service creation
174 1
                 */
175
                self::$servicesContainer = clone self::$servicesRepository;
176
            }
177 6
        }
178
179 6
        // final sync, repository is complete
180 6
        self::$servicesContainer = clone self::$servicesRepository;
181 6
    }
182
183
    public function hasService(string $serviceName): bool
184
    {
185 6
        return isset(self::$servicesContainer[$serviceName]);
186
    }
187
188
    private function setConfigFile($configFile)
189
    {
190
        foreach ((array) $configFile as $file) {
191 8
            if (is_file($file)) {
192
                $this->configFile[] = $file;
193 8
            }
194 8
        }
195 6
196 6
        return $this;
197 6
    }
198 6
199 6
    private function parseYamlConfig($filename) {
200
        return yaml_parse_file($filename, 0, $ndocs,
201
        [
202
            '!include' => function($value, $tag, $flags) use($filename)
0 ignored issues
show
Unused Code introduced by
The parameter $flags is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

202
            '!include' => function($value, $tag, /** @scrutinizer ignore-unused */ $flags) use($filename)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $tag is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

202
            '!include' => function($value, /** @scrutinizer ignore-unused */ $tag, $flags) use($filename)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
203
            {
204 6
                $directory = dirname($filename);
205 5
                return $this->parseYamlConfig("$directory/$value");
206 5
            }
207
        ]);
208
    }
209
    /**
210
     * Load framework configuration from ini file
211
     * @return void
212
     */
213
    private function loadConfig()
214
    {
215
        $userConfig = [];
216
        if (count($this->configFile)) {
217 8
            $userConfig = [];
218 8
            foreach ($this->configFile as $configFile) {
219
                if (stripos($configFile, 'yml') !== false) {
220
                    $userConfig = array_merge_recursive($userConfig, $this->parseYamlConfig($configFile));
221
                } else {
222
                    $userConfig = array_merge_recursive(
223
                        $userConfig,
224
                        (array) parse_ini_file($configFile, true, INI_SCANNER_TYPED)
225 8
                    );
226
                }
227
            }
228
229 8
            // Advanced ini parsing, split key with '.' into subarrays
230
            foreach ($userConfig as $section => $configData) {
231 8
                foreach ($configData as $name => $value) {
232 8
                    if (stripos($name, '.') !== false) {
233
                        $subkeys = explode('.', $name);
234 8
                        unset($userConfig[$section][$name]);
235
                        $str =
236 8
                            "['" . implode("']['", $subkeys) . "'] = \$value;";
237 8
                        eval("\$userConfig[\$section]" . $str);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
238 8
                    }
239 8
                }
240
            }
241 8
        }
242
243
        foreach ($this->getDefaultConfig() as $context => $directives) {
244
            if (isset($userConfig[$context])) {
245
                $this->config[$context] = array_merge(
246
                    $directives,
247
                    $userConfig[$context]
248
                );
249
                unset($userConfig[$context]);
250
            } else {
251
                $this->config[$context] = $directives;
252
            }
253
        }
254
255
        $this->config = array_merge($this->config, $userConfig);
256
        $this->configureAppMode();
257
    }
258
259
    private function configureAppMode()
260
    {
261
        $errorReporting = true;
262
        $errorDumpContext = true;
263
        $logLevel = Logger::LOGLEVEL_WARN;
264
        $logFile = 'php://stdout';
265
266
        if (isset($this->config['App']['mode'])) {
267
            switch ($this->config['App']['mode']) {
268
                case App::DEVELOPMENT_MODE:
269 8
                    $errorReporting = true;
270
                    $errorDumpContext = true;
271
                    $logLevel = Logger::LOGLEVEL_INFO;
272 8
                    $logFile = 'php://stdout';
273
                    break;
274
                case App::DEBUG_MODE:
275 8
                    $errorReporting = true;
276
                    $errorDumpContext = true;
277
                    $logLevel = Logger::LOGLEVEL_DEBUG;
278 8
                    $logFile = 'php://stdout';
279
                    break;
280
                case App::PRELIVE_MODE:
281
                    $errorReporting = true;
282 8
                    $errorDumpContext = false;
283 8
                    $logLevel = Logger::LOGLEVEL_WARN;
284 8
                    $logFile = 'php://stderr';
285 8
                    break;
286 8
                case App::PRODUCTION_MODE:
287
                    $errorReporting = false;
288
                    $errorDumpContext = false;
289
                    $logLevel = Logger::LOGLEVEL_WARN;
290
                    $logFile = 'php://stderr';
291 8
                    break;
292
            }
293
        }
294 8
        if (isset($this->config['Logger']['level'])) {
295
            $logLevel = $this->config['Logger']['level'];
296
        }
297
        if (isset($this->config['Logger']['logfile'])) {
298
            $logFile = $this->config['Logger']['logfile'];
299
        }
300
        if (isset($this->config['Error']['report'])) {
301
            $errorReporting = $this->config['Error']['report'];
302
        }
303
        if (isset($this->config['Error']['dumpContext'])) {
304
            $errorDumpContext = $this->config['Error']['dumpContext'];
305
        }
306
307 19
        $this->config['Logger']['level'] = $logLevel;
308
        $this->config['Logger']['logfile'] = $logFile;
309 19
        $this->config['Error']['report'] = $errorReporting;
310 1
        $this->config['Error']['dumpContext'] = $errorDumpContext;
311
    }
312
    /**
313 19
     * Default setup template
314
     * @return array setup
315
     */
316
    private function getDefaultConfig()
317
    {
318
        return [
319
            'Router' => [],
320
            'Logger' => [
321
                'enabled' => true
322
            ],
323
            'App' => ['base_uri' => '/']
324
        ];
325
    }
326
327
    public function run()
328
    {
329
        self::$servicesContainer['Router']->doRouting();
330
    }
331
332
    public static function __callStatic($name, $arguments)
333
    {
334
        if (isset($arguments[0]) && $arguments[0] === true) {
335
            return clone self::$servicesRepository[$name];
336
        }
337
338
        return self::$servicesContainer[$name];
339
    }
340
341
    public function registerService(string $serviceName, string $serviceClass): self
342
    {
343
        if (isset(self::$servicesContainer[$serviceName])) {
344
            throw new InvalidArgumentException('Service ' . $serviceName . ' already registered');
345
        }
346
347
        self::$servicesContainer->addToWarehouse($serviceName, $serviceClass);
348
        self::$servicesRepository->addToWarehouse($serviceName, $serviceClass);
349
        if (isset($this->config[$serviceName])) {
350
            self::$servicesContainer[$serviceName]->configure(
351
                $this->config[$serviceName]
352
            );
353
        }
354
        return $this;
355
    }
356
}
357