Completed
Push — develop ( 850cb3...5f4d18 )
by Mathieu
10:58 queued 09:18
created

Suricate::setAppPaths()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
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.2.0
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
    /**
57
     * Suricate contructor
58
     *
59
     * @param array $paths Application paths
60
     * @param string|array|null $configFile path of configuration file(s)
61
     */
62 8
    public function __construct($paths = [], $configFile = null)
63
    {
64 8
        if ($configFile !== null) {
65 6
            $this->setConfigFile($configFile);
66
        }
67
       
68
        // Load helpers
69 8
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php';
70
71 8
        $this->loadConfig();
72 8
        $this->setAppPaths($paths);
73
74 8
        if ($this->useAutoloader) {
75
            // Configure autoloader
76
            require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php';
77
            AutoLoader::register();
78
        }
79
80
        // Define error handler
81 8
        set_exception_handler(['\Suricate\Error', 'handleException']);
82 8
        set_error_handler(['\Suricate\Error', 'handleError']);
83 8
        register_shutdown_function(['\Suricate\Error', 'handleShutdownError']);
84
85 8
        self::$servicesRepository = new Container();
86
87 8
        $this->initServices();
88 8
    }
89
90 1
    public function getConfig()
91
    {
92 1
        return $this->config;
93
    }
94
95 8
    private function setAppPaths($paths = [])
96
    {
97 8
        foreach ($paths as $key => $value) {
98
            $this->config['App']['path.' . $key] = realpath($value);
99
        }
100
101 8
        return $this;
102
    }
103
    /**
104
     * Initialize Framework services
105
     * @return null
106
     */
107 8
    private function initServices()
108
    {
109 8
        self::$servicesRepository->setWarehouse($this->servicesList);
110
111 8
        self::$servicesRepository['Request']->parse();
112 8
        if (isset($this->config['App']['locale'])) {
113
            $this->config['I18n'] = ['locale' => $this->config['App']['locale']];
114
        }
115
        // first sync, && init, dependency to Suricate::request
116 8
        self::$servicesContainer = clone self::$servicesRepository;
117
118 8
        foreach (array_keys($this->servicesList) as $serviceName) {
119 8
            if (isset($this->config[$serviceName])) {
120 8
                self::$servicesRepository[$serviceName]->configure($this->config[$serviceName]);
121
122
                /**
123
                 TODO : remove sync in service creation
124
                */
125 8
                self::$servicesContainer = clone self::$servicesRepository;
126
            }
127
        }
128
129 8
        if (isset($this->config['Constants'])) {
130 1
            foreach ($this->config['Constants'] as $constantName => $constantValue) {
131 1
                $constantName = strtoupper($constantName);
132 1
                define($constantName, $constantValue);
133
            }
134
        }
135
136
        // final sync, repository is complete
137 8
        self::$servicesContainer = clone self::$servicesRepository;
138 8
    }
139
140 1
    public function hasService(string $serviceName): bool
141
    {
142 1
        return isset(self::$servicesContainer[$serviceName]);
143
    }
144
145 6
    private function setConfigFile($configFile)
146
    {
147 6
        foreach ((array) $configFile as $file) {
148 6
            if (is_file($file)) {
149 6
                $this->configFile[] = $file;
150
            }
151
        }
152
153 6
        return $this;
154
    }
155
    /**
156
     * Load framework configuration from ini file
157
     * @return null
158
     */
159 8
    private function loadConfig()
160
    {
161 8
        $userConfig = [];
162 8
        if (count($this->configFile)) {
163 6
            $userConfig = [];
164 6
            foreach ($this->configFile as $configFile) {
165 6
                $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

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