Completed
Push — master ( b51747...8ab68d )
by Mathieu
21s queued 11s
created

Suricate::initServices()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6.0585

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 18
nc 12
nop 0
dl 0
loc 38
ccs 15
cts 17
cp 0.8824
crap 6.0585
rs 9.0444
c 3
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
/**
8
 * Suricate - Another micro PHP framework
9
 *
10
 * @author      Mathieu LESNIAK <[email protected]>
11
 * @copyright   2013-2019 Mathieu LESNIAK
12
 * @version     0.2.0
13
 * @package     Suricate
14
 *
15
 * @method static \Suricate\App             App($newInstance = false)             Get instance of App service
16
 * @method static \Suricate\Cache           Cache($nezwInstance = false)          Get instance of Cache service
17
 * @method static \Suricate\CacheMemcache   CacheMemcache($newInstance = false)   Get instance of CacheMemcache service
18
 * @method static \Suricate\CacheMemcached  CacheMemcached($newInstance = false)  Get instance of CacheMemcached service
19
 * @method static \Suricate\CacheApc        CacheApc($newInstance = false)        Get instance of CacheApc service
20
 * @method static \Suricate\CacheFile       CacheFile($newInstance = false)       Get instance of CacheFile service
21
 * @method static \Suricate\Curl            Curl($newInstance = false)            Get instance of Curl service
22
 * @method static \Suricate\Database        Database($newInstance = false)        Get instance of Database service
23
 * @method static \Suricate\Error           Error($newInstance = false)           Get instance of Error service
24
 * @method static \Suricate\I18n            I18n($newInstance = false)            Get instance of I18n service
25
 * @method static \Suricate\Logger          Logger($newInstance = false)          Get instance of Logger service
26
 * @method static \Suricate\Request         Request($newInstance = false)         Get instance of Request service
27
 * @method static \Suricate\Request         Response($newInstance = false)        Get instance of Request/Response service
28
 * @method static \Suricate\Router          Router($newInstance = false)          Get instance of Router service
29
 * @method static \Suricate\Session         Session($newInstance = false)         Get instance of Session service
30
 * @method static \Suricate\SessionNative   SessionNative($newInstance = false)   Get instance of Session service
31
 * @method static \Suricate\SessionCookie   SessionCookie($newInstance = false)   Get instance of Session service
32
 * @method static \Suricate\SessionMemcache SessionMemcache($newInstance = false) Get instance of Session service
33
 */
34
35
class Suricate
36
{
37
    const VERSION = '0.2.4';
38
39
    const CONF_DIR = '/conf/';
40
41
    private $config = [];
42
    private $configFile = [];
43
44
    private $useAutoloader = false;
45
46
    private static $servicesContainer;
47
    private static $servicesRepository;
48
49
    private $servicesList = [
50
        'App' => '\Suricate\App',
51
        'Cache' => '\Suricate\Cache',
52
        'CacheMemcache' => '\Suricate\Cache\Memcache',
53
        'CacheMemcached' => '\Suricate\Cache\Memcached',
54
        'CacheApc' => '\Suricate\Cache\Apc',
55
        'CacheFile' => '\Suricate\Cache\File',
56
        'Curl' => '\Suricate\Curl',
57
        'Database' => '\Suricate\Database',
58
        'Error' => '\Suricate\Error',
59
        'I18n' => '\Suricate\I18n',
60
        'Logger' => '\Suricate\Logger',
61
        'Request' => '\Suricate\Request',
62
        'Response' => '\Suricate\Request',
63
        'Router' => '\Suricate\Router',
64
        'Session' => '\Suricate\Session',
65
        'SessionNative' => '\Suricate\Session\Native',
66
        'SessionCookie' => '\Suricate\Session\Cookie',
67
        'SessionMemcache' => '\Suricate\Session\Memcache'
68
    ];
69
70
    /**
71
     * Suricate contructor
72
     *
73
     * @param array $paths Application paths
74
     * @param string|array|null $configFile path of configuration file(s)
75
     *
76
     * @SuppressWarnings(PHPMD.StaticAccess)
77
     */
78 8
    public function __construct($paths = [], $configFile = null)
79
    {
80 8
        if ($configFile !== null) {
81 6
            $this->setConfigFile($configFile);
82
        }
83
84
        // Load helpers
85 8
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php';
86
87 8
        $this->loadConfig();
88 8
        $this->setAppPaths($paths);
89
90 8
        if ($this->useAutoloader) {
91
            // Configure autoloader
92
            require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php';
93
            AutoLoader::register();
94
        }
95
96
        // Define error handler
97 8
        set_exception_handler(['\Suricate\Error', 'handleException']);
98 8
        set_error_handler(['\Suricate\Error', 'handleError']);
99 8
        register_shutdown_function(['\Suricate\Error', 'handleShutdownError']);
100
101 8
        self::$servicesRepository = new Container();
102
103 8
        $this->initServices();
104 8
    }
105
106 1
    public function getConfig()
107
    {
108 1
        return $this->config;
109
    }
110
111 8
    private function setAppPaths($paths = [])
112
    {
113 8
        foreach ($paths as $key => $value) {
114
            $this->config['App']['path.' . $key] = realpath($value);
115
        }
116
117 8
        return $this;
118
    }
119
    /**
120
     * Initialize Framework services
121
     * @return null
122
     */
123 8
    private function initServices()
124
    {
125 8
        self::$servicesRepository->setWarehouse($this->servicesList);
126
127 8
        self::$servicesRepository['Request']->parse();
128 8
        if (isset($this->config['App']['locale'])) {
129
            $this->config['I18n'] = [
130
                'locale' => $this->config['App']['locale']
131
            ];
132
        }
133
        // first sync, && init, dependency to Suricate::request
134 8
        self::$servicesContainer = clone self::$servicesRepository;
135
136 8
        foreach (array_keys($this->servicesList) as $serviceName) {
137 8
            if (isset($this->config[$serviceName])) {
138 8
                self::$servicesRepository[$serviceName]->configure(
139 8
                    $this->config[$serviceName]
140
                );
141
142
                /**
143
                 TODO : remove sync in service creation
144
                 */
145 8
                self::$servicesContainer = clone self::$servicesRepository;
146
            }
147
        }
148
149 8
        if (isset($this->config['Constants'])) {
150
            foreach (
151 1
                $this->config['Constants']
152
                as $constantName => $constantValue
153
            ) {
154 1
                $constantName = strtoupper($constantName);
155 1
                define($constantName, $constantValue);
156
            }
157
        }
158
159
        // final sync, repository is complete
160 8
        self::$servicesContainer = clone self::$servicesRepository;
161 8
    }
162
163 1
    public function hasService(string $serviceName): bool
164
    {
165 1
        return isset(self::$servicesContainer[$serviceName]);
166
    }
167
168 6
    private function setConfigFile($configFile)
169
    {
170 6
        foreach ((array) $configFile as $file) {
171 6
            if (is_file($file)) {
172 6
                $this->configFile[] = $file;
173
            }
174
        }
175
176 6
        return $this;
177
    }
178
    /**
179
     * Load framework configuration from ini file
180
     * @return null
181
     */
182 8
    private function loadConfig()
183
    {
184 8
        $userConfig = [];
185 8
        if (count($this->configFile)) {
186 6
            $userConfig = [];
187 6
            foreach ($this->configFile as $configFile) {
188 6
                $userConfig = array_merge_recursive(
189 6
                    $userConfig,
190 6
                    (array) parse_ini_file($configFile, true, INI_SCANNER_TYPED)
191
                );
192
            }
193
194
            // Advanced ini parsing, split key with '.' into subarrays
195 6
            foreach ($userConfig as $section => $configData) {
196 5
                foreach ($configData as $name => $value) {
197 5
                    if (stripos($name, '.') !== false) {
198
                        $subkeys = explode('.', $name);
199
                        unset($userConfig[$section][$name]);
200
                        $str =
201
                            "['" . implode("']['", $subkeys) . "'] = \$value;";
202
                        eval("\$userConfig[\$section]" . $str);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
203
                    }
204
                }
205
            }
206
        }
207
208 8
        foreach ($this->getDefaultConfig() as $context => $directives) {
209 8
            if (isset($userConfig[$context])) {
210
                $this->config[$context] = array_merge(
211
                    $directives,
212
                    $userConfig[$context]
213
                );
214
                unset($userConfig[$context]);
215
            } else {
216 8
                $this->config[$context] = $directives;
217
            }
218
        }
219
220 8
        $this->config = array_merge($this->config, $userConfig);
221
222 8
        $this->configureAppMode();
223 8
    }
224
225 8
    private function configureAppMode()
226
    {
227 8
        $errorReporting = true;
228 8
        $errorDumpContext = true;
229 8
        $logLevel = Logger::LOGLEVEL_WARN;
230 8
        $logFile = 'php://stdout';
231
232 8
        if (isset($this->config['App']['mode'])) {
233
            switch ($this->config['App']['mode']) {
234
                case App::DEVELOPMENT_MODE:
235
                    $errorReporting = true;
236
                    $errorDumpContext = true;
237
                    $logLevel = Logger::LOGLEVEL_INFO;
238
                    $logFile = 'php://stdout';
239
                    break;
240
                case App::DEBUG_MODE:
241
                    $errorReporting = true;
242
                    $errorDumpContext = true;
243
                    $logLevel = Logger::LOGLEVEL_DEBUG;
244
                    $logFile = 'php://stdout';
245
                    break;
246
                case App::PRELIVE_MODE:
247
                    $errorReporting = true;
248
                    $errorDumpContext = false;
249
                    $logLevel = Logger::LOGLEVEL_WARN;
250
                    $logFile = 'php://stderr';
251
                    break;
252
                case App::PRODUCTION_MODE:
253
                    $errorReporting = false;
254
                    $errorDumpContext = false;
255
                    $logLevel = Logger::LOGLEVEL_WARN;
256
                    $logFile = 'php://stderr';
257
                    break;
258
            }
259
        }
260 8
        if (isset($this->config['Logger']['level'])) {
261
            $logLevel = $this->config['Logger']['level'];
262
        }
263 8
        if (isset($this->config['Logger']['logfile'])) {
264
            $logFile = $this->config['Logger']['logfile'];
265
        }
266 8
        if (isset($this->config['Error']['report'])) {
267
            $errorReporting = $this->config['Error']['report'];
268
        }
269 8
        if (isset($this->config['Error']['dumpContext'])) {
270
            $errorDumpContext = $this->config['Error']['dumpContext'];
271
        }
272
273 8
        $this->config['Logger']['level'] = $logLevel;
274 8
        $this->config['Logger']['logfile'] = $logFile;
275 8
        $this->config['Error']['report'] = $errorReporting;
276 8
        $this->config['Error']['dumpContext'] = $errorDumpContext;
277 8
    }
278
    /**
279
     * Default setup template
280
     * @return array setup
281
     */
282 8
    private function getDefaultConfig()
283
    {
284
        return [
285 8
            'Router' => [],
286
            'Logger' => [
287
                'enabled' => true
288
            ],
289
            'App' => ['base_uri' => '/']
290
        ];
291
    }
292
293
    public function run()
294
    {
295
        self::$servicesContainer['Router']->doRouting();
296
    }
297
298 17
    public static function __callStatic($name, $arguments)
299
    {
300 17
        if (isset($arguments[0]) && $arguments[0] === true) {
301 1
            return clone self::$servicesRepository[$name];
302
        }
303
304 17
        return self::$servicesContainer[$name];
305
    }
306
}
307