Passed
Push — develop ( b56629...ffa5e1 )
by Mathieu
01:38
created

Suricate::initServices()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6.0106

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 12
nop 0
dl 0
loc 31
ccs 14
cts 15
cp 0.9333
crap 6.0106
rs 9.2222
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * Suricate - Another micro PHP framework
4
 *
5
 * @author      Mathieu LESNIAK <[email protected]>
6
 * @copyright   2013-2019 Mathieu LESNIAK
7
 * @version     0.1.16
8
 * @package     Suricate
9
 *
10
 * @method static \Suricate\App      App()      Get instance of App service
11
 * @method static \Suricate\Database Database() Get instance of Database service
12
 * @method static \Suricate\Error    Error()    Get instance of Error service
13
 * @method static \Suricate\I18n     I18n()     Get instance of I18n service
14
 * @method static \Suricate\Request  Request()  Get instance of Request service
15
 * @method static \Suricate\Logger   Logger()   Get instance of Logger service
16
 */
17
namespace Suricate;
18
19
class Suricate
20
{
21
22
    const VERSION = '0.2.0';
23
24
    const CONF_DIR = '/conf/';
25
26
    private $config  = [];
27
    private $configFile = [];
28
29
    private $useAutoloader = false;
30
31
    private static $servicesContainer;
32
    private static $servicesRepository;
33
34
    private $servicesList = [
35
        'Logger'            => '\Suricate\Logger',
36
        'App'               => '\Suricate\App',
37
        'I18n'              => '\Suricate\I18n',
38
        'Error'             => '\Suricate\Error',
39
        'Router'            => '\Suricate\Router',
40
        'Request'           => '\Suricate\Request',
41
        'Database'          => '\Suricate\Database',
42
        'Cache'             => '\Suricate\Cache',
43
        'CacheMemcache'     => '\Suricate\Cache\Memcache',
44
        'CacheMemcached'    => '\Suricate\Cache\Memcached',
45
        'CacheApc'          => '\Suricate\Cache\Apc',
46
        'CacheFile'         => '\Suricate\Cache\File',
47
        'Curl'              => '\Suricate\Curl',
48
        'Response'          => '\Suricate\Request',
49
        'Session'           => '\Suricate\Session',
50
        'SessionNative'     => '\Suricate\Session\Native',
51
        'SessionCookie'     => '\Suricate\Session\Cookie',
52
        'SessionMemcache'   => '\Suricate\Session\Memcache',
53
    ];
54
55
56 3
    public function __construct($paths = [], $configFile = null)
57
    {
58 3
        if ($configFile !== null) {
59 2
            $this->setConfigFile($configFile);
60
        }
61
       
62
        // Load helpers
63 3
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php';
64
65 3
        $this->loadConfig();
66 3
        $this->setAppPaths($paths);
67
68 3
        if ($this->useAutoloader) {
69
            // Configure autoloader
70
            require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php';
71
            AutoLoader::register();
72
        }
73
74
        // Define error handler
75 3
        set_exception_handler(['\Suricate\Error', 'handleException']);
76 3
        set_error_handler(['\Suricate\Error', 'handleError']);
77 3
        register_shutdown_function(['\Suricate\Error', 'handleShutdownError']);
78
79 3
        self::$servicesRepository = new Container();
80
81 3
        $this->initServices();
82 3
    }
83
84 1
    public function getConfig()
85
    {
86 1
        return $this->config;
87
    }
88
89 3
    private function setAppPaths($paths = [])
90
    {
91 3
        foreach ($paths as $key => $value) {
92
            $this->config['App']['path.' . $key] = realpath($value);
93
        }
94
95 3
        return $this;
96
    }
97
    /**
98
     * Initialize Framework services
99
     * @return null
100
     */
101 3
    private function initServices()
102
    {
103 3
        self::$servicesRepository->setWarehouse($this->servicesList);
104
105 3
        self::$servicesRepository['Request']->parse();
106 3
        if (isset($this->config['App']['locale'])) {
107
            $this->config['I18n'] = ['locale' => $this->config['App']['locale']];
108
        }
109
        // first sync, && init, dependency to Suricate::request
110 3
        self::$servicesContainer = clone self::$servicesRepository;
111
112 3
        foreach (array_keys($this->servicesList) as $serviceName) {
113 3
            if (isset($this->config[$serviceName])) {
114 3
                self::$servicesRepository[$serviceName]->configure($this->config[$serviceName]);
115
116
                /**
117
                 TODO : remove sync in service creation
118
                */
119 3
                self::$servicesContainer = clone self::$servicesRepository;
120
            }
121
        }
122
123 3
        if (isset($this->config['Constants'])) {
124 1
            foreach ($this->config['Constants'] as $constantName => $constantValue) {
125 1
                $constantName = strtoupper($constantName);
126 1
                define($constantName, $constantValue);
127
            }
128
        }
129
130
        // final sync, repository is complete
131 3
        self::$servicesContainer = clone self::$servicesRepository;
132 3
    }
133
134 1
    public function hasService(string $serviceName): bool
135
    {
136 1
        return isset(self::$servicesContainer[$serviceName]);
137
    }
138
139 2
    private function setConfigFile($configFile)
140
    {
141 2
        foreach ((array) $configFile as $file) {
142 2
            if (is_file($file)) {
143 2
                $this->configFile[] = $file;
144
            }
145
        }
146
147 2
        return $this;
148
    }
149
    /**
150
     * Load framework configuration from ini file
151
     * @return null
152
     */
153 3
    private function loadConfig()
154
    {
155 3
        $userConfig = [];
156 3
        if (count($this->configFile)) {
157 2
            $userConfig = [];
158 2
            foreach ($this->configFile as $configFile) {
159 2
                $userConfig = array_merge_recursive($userConfig, parse_ini_file($configFile, true, INI_SCANNER_TYPED));
0 ignored issues
show
Bug introduced by
It seems like parse_ini_file($configFi...cate\INI_SCANNER_TYPED) can also be of type false; however, parameter $_ of array_merge_recursive() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

159
                $userConfig = array_merge_recursive($userConfig, /** @scrutinizer ignore-type */ parse_ini_file($configFile, true, INI_SCANNER_TYPED));
Loading history...
160
            }
161
162
            // Advanced ini parsing, split key with '.' into subarrays
163 2
            foreach ($userConfig as $section => $configData) {
164 1
                foreach (array_keys($configData) as $name) {
165 1
                    if (stripos($name, '.') !== false) {
166
                        $subkeys = explode('.', $name);
167
                        unset($userConfig[$section][$name]);
168
                        $str = "['" . implode("']['", $subkeys) . "'] = \$value;";
169 1
                        eval("\$userConfig[\$section]" . $str);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
170
                    }
171
                }
172
            }
173
        }
174
175 3
        foreach ($this->getDefaultConfig() as $context => $directives) {
176 3
            if (isset($userConfig[$context])) {
177
                $this->config[$context] = array_merge($directives, $userConfig[$context]);
178
                unset($userConfig[$context]);
179
            } else {
180 3
                $this->config[$context] = $directives;
181
            }
182
        }
183
184 3
        $this->config = array_merge($this->config, $userConfig);
185
186 3
        $this->configureAppMode();
187 3
    }
188
189 3
    private function configureAppMode()
190
    {
191 3
        $errorReporting     = true;
192 3
        $errorDumpContext   = true;
193 3
        $logLevel           = Logger::LOGLEVEL_WARN;
194 3
        $logFile            = 'php://stdout';
195
        
196 3
        if (isset($this->config['App']['mode'])) {
197
            switch ($this->config['App']['mode']) {
198
                case App::DEVELOPMENT_MODE:
199
                    $errorReporting     = true;
200
                    $errorDumpContext   = true;
201
                    $logLevel           = Logger::LOGLEVEL_INFO;
202
                    $logFile            = 'php://stdout';
203
                    break;
204
                case App::DEBUG_MODE:
205
                    $errorReporting     = true;
206
                    $errorDumpContext   = true;
207
                    $logLevel           = Logger::LOGLEVEL_DEBUG;
208
                    $logFile            = 'php://stdout';
209
                    break;
210
                case App::PRELIVE_MODE:
211
                    $errorReporting     = true;
212
                    $errorDumpContext   = false;
213
                    $logLevel           = Logger::LOGLEVEL_WARN;
214
                    $logFile            = 'php://stderr';
215
                    break;
216
                case App::PRODUCTION_MODE:
217
                    $errorReporting     = false;
218
                    $errorDumpContext   = false;
219
                    $logLevel           = Logger::LOGLEVEL_WARN;
220
                    $logFile            = 'php://stderr';
221
                    break;
222
            }
223
        }
224 3
        if (isset($this->config['Logger']['level'])) {
225
            $logLevel = $this->config['Logger']['level'];
226
        }
227 3
        if (isset($this->config['Logger']['logfile'])) {
228
            $logFile = $this->config['Logger']['logfile'];
229
        }
230 3
        if (isset($this->config['Error']['report'])) {
231
            $errorReporting = $this->config['Error']['report'];
232
        }
233 3
        if (isset($this->config['Error']['dumpContext'])) {
234
            $errorDumpContext = $this->config['Error']['dumpContext'];
235
        }
236
237 3
        $this->config['Logger']['level']        = $logLevel;
238 3
        $this->config['Logger']['logfile']      = $logFile;
239 3
        $this->config['Error']['report']        = $errorReporting;
240 3
        $this->config['Error']['dumpContext']   =  $errorDumpContext;
241 3
    }
242
    /**
243
     * Default setup template
244
     * @return array setup
245
     */
246 3
    private function getDefaultConfig()
247
    {
248
        return [
249 3
            'Router'    => [],
250
            'Logger'    => [
251
                'enabled'   => true,
252
            ],
253
            'App'       => ['base_uri' => '/'],
254
        ];
255
    }
256
257
    public function run()
258
    {
259
        self::$servicesContainer['Router']->doRouting();
260
    }
261
262 6
    public static function __callStatic($name, $arguments)
263
    {
264 6
        if (isset($arguments[0]) && $arguments[0] === true) {
265
            return clone self::$servicesRepository[$name];
266
        }
267
268 6
        return self::$servicesContainer[$name];
269
    }
270
}
271