Suricate::configureAppMode()   B
last analyzed

Complexity

Conditions 10
Paths 96

Size

Total Lines 52
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 15.2734

Importance

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

208
            '!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

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