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