Completed
Push — develop ( 224f45...1db626 )
by Mathieu
01:43
created

Suricate::loadConfig()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 9.728

Importance

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