Completed
Push — develop ( f7e243...a4fd62 )
by Mathieu
01:40
created

Suricate   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 242
Duplicated Lines 0 %

Test Coverage

Coverage 57.89%

Importance

Changes 0
Metric Value
eloc 135
dl 0
loc 242
ccs 66
cts 114
cp 0.5789
rs 9.44
c 0
b 0
f 0
wmc 37

9 Methods

Rating   Name   Duplication   Size   Complexity  
B loadConfig() 0 34 8
A initServices() 0 31 6
B configureAppMode() 0 52 10
A setConfigFile() 0 9 3
A __construct() 0 26 3
A __callStatic() 0 6 3
A run() 0 3 1
A getDefaultConfig() 0 9 1
A setAppPaths() 0 7 2
1
<?php declare(strict_types=1);
2
/**
3
 * Suricate - Another micro PHP 5 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
    protected $router;
27
28
    private $config;
29
    private $configFile = [];
30
31
    private $useAutoloader = false;
32
33
    private static $servicesContainer;
34
    private static $servicesRepository;
35
36
    private $servicesList = [
37
        'Logger'            => '\Suricate\Logger',
38
        'App'               => '\Suricate\App',
39
        'I18n'              => '\Suricate\I18n',
40
        'Error'             => '\Suricate\Error',
41
        'Router'            => '\Suricate\Router',
42
        'Request'           => '\Suricate\Request',
43
        'Database'          => '\Suricate\Database',
44
        'Cache'             => '\Suricate\Cache',
45
        'CacheMemcache'     => '\Suricate\Cache\Memcache',
46
        'CacheMemcached'    => '\Suricate\Cache\Memcached',
47
        'CacheApc'          => '\Suricate\Cache\Apc',
48
        'CacheFile'         => '\Suricate\Cache\File',
49
        'Curl'              => '\Suricate\Curl',
50
        'Response'          => '\Suricate\Request',
51
        'Session'           => '\Suricate\Session',
52
        'SessionNative'     => '\Suricate\Session\Native',
53
        'SessionCookie'     => '\Suricate\Session\Cookie',
54
        'SessionMemcache'   => '\Suricate\Session\Memcache',
55
    ];
56
57
58 1
    public function __construct($paths = [], $configFile = null)
59
    {
60 1
        if ($configFile !== null) {
61 1
            $this->setConfigFile($configFile);
62
        }
63
       
64
        // Load helpers
65 1
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php';
66
67 1
        $this->loadConfig();
68 1
        $this->setAppPaths($paths);
69
70 1
        if ($this->useAutoloader) {
71
            // Configure autoloader
72
            require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php';
73
            AutoLoader::register();
74
        }
75
76
        // Define error handler
77 1
        set_exception_handler(['\Suricate\Error', 'handleException']);
78 1
        set_error_handler(['\Suricate\Error', 'handleError']);
79 1
        register_shutdown_function(['\Suricate\Error', 'handleShutdownError']);
80
81 1
        self::$servicesRepository = new Container();
82
83 1
        $this->initServices();
84 1
    }
85
86 1
    private function setAppPaths($paths = [])
87
    {
88 1
        foreach ($paths as $key => $value) {
89
            $this->config['App']['path.' . $key] = realpath($value);
90
        }
91
92 1
        return $this;
93
    }
94
    /**
95
     * Initialize Framework services
96
     * @return null
97
     */
98 1
    private function initServices()
99
    {
100 1
        self::$servicesRepository->setWarehouse($this->servicesList);
101
102 1
        self::$servicesRepository['Request']->parse();
103 1
        if (isset($this->config['App']['locale'])) {
104
            $this->config['I18n'] = ['locale' => $this->config['App']['locale']];
105
        }
106
        // first sync, && init, dependency to Suricate::request
107 1
        self::$servicesContainer = clone self::$servicesRepository;
108
109 1
        foreach (array_keys($this->servicesList) as $serviceName) {
110 1
            if (isset($this->config[$serviceName])) {
111 1
                self::$servicesRepository[$serviceName]->configure($this->config[$serviceName]);
112
113
                /**
114
                 TODO : remove sync in service creation
115
                */
116 1
                self::$servicesContainer = clone self::$servicesRepository;
117
            }
118
        }
119
120 1
        if (isset($this->config['Constants'])) {
121
            foreach ($this->config['Constants'] as $constantName => $constantValue) {
122
                $constantName = strtoupper($constantName);
123
                define($constantName, $constantValue);
124
            }
125
        }
126
127
        // final sync, repository is complete
128 1
        self::$servicesContainer = clone self::$servicesRepository;
129 1
    }
130
131 1
    private function setConfigFile($configFile)
132
    {
133 1
        foreach ((array) $configFile as $file) {
134 1
            if (is_file($file)) {
135 1
                $this->configFile[] = $file;
136
            }
137
        }
138
139 1
        return $this;
140
    }
141
    /**
142
     * Load framework configuration from ini file
143
     * @return null
144
     */
145 1
    private function loadConfig()
146
    {
147 1
        $userConfig = [];
148 1
        if ($this->configFile !== null) {
149 1
            $userConfig = [];
150 1
            foreach ($this->configFile as $configFile) {
0 ignored issues
show
Bug introduced by
The expression $this->configFile of type mixed is not traversable.
Loading history...
151 1
                $userConfig = array_merge_recursive($userConfig, parse_ini_file($configFile, true));
0 ignored issues
show
Bug introduced by
It seems like parse_ini_file($configFile, true) 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

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