Completed
Push — develop ( 2e1df2...27dbda )
by Mathieu
03:22
created

Suricate::initServices()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

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

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