Passed
Push — 1.0.0-dev ( a1ce08...4f1d46 )
by nguereza
10:50
created

Loader::getLibraryPathUsingModuleInfo()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 17
rs 9.7666
1
<?php
2
    defined('ROOT_PATH') || exit('Access denied');
3
    /**
4
     * TNH Framework
5
     *
6
     * A simple PHP framework using HMVC architecture
7
     *
8
     * This content is released under the GNU GPL License (GPL)
9
     *
10
     * Copyright (C) 2017 Tony NGUEREZA
11
     *
12
     * This program is free software; you can redistribute it and/or
13
     * modify it under the terms of the GNU General Public License
14
     * as published by the Free Software Foundation; either version 3
15
     * of the License, or (at your option) any later version.
16
     *
17
     * This program is distributed in the hope that it will be useful,
18
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
     * GNU General Public License for more details.
21
     *
22
     * You should have received a copy of the GNU General Public License
23
     * along with this program; if not, write to the Free Software
24
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
     */
26
    class Loader extends BaseStaticClass {
27
		
28
        /**
29
         * List of loaded resources
30
         * @var array
31
         */
32
        public static $loaded = array();
33
		
34
35
        public function __construct() {
36
            //add the resources already loaded during application bootstrap
37
            //in the list to prevent duplicate or loading the resources again.
38
            self::$loaded = class_loaded();
39
			
40
            //Load resources from autoload configuration
41
            $this->loadResourcesFromAutoloadConfig();
42
        }
43
44
		
45
        /**
46
         * Load the model class
47
         *
48
         * @param  string $class    the class name to be loaded
49
         * @param  string $instance the name of the instance to use in super object
50
         *
51
         * @return void
52
         */
53
        public static function model($class, $instance = null) {
54
            $logger = self::getLogger();
55
            $class = str_ireplace('.php', '', $class);
56
            $class = trim($class, '/\\');
57
            $file = ucfirst($class) . '.php';
58
            $logger->debug('Loading model [' . $class . '] ...');
59
            //************
60
            if (!$instance) {
61
                $instance = self::getModelLibraryInstanceName($class);
62
            }
63
            //****************
64
            if (isset(self::$loaded[$instance])) {
65
                $logger->info('Model [' . $class . '] already loaded no need to load it again, cost in performance');
66
                return;
67
            }
68
            $classFilePath = APPS_MODEL_PATH . $file;
69
            //first check if this model is in the module
70
            $logger->debug('Checking model [' . $class . '] from module list ...');
71
            //check if the request class contains module name
72
            $moduleInfo = self::getModuleInfoForModelLibrary($class);
73
            $module = $moduleInfo['module'];
74
            $class  = $moduleInfo['class'];
75
			
76
            $moduleModelFilePath = Module::findModelFullPath($class, $module);
77
            if ($moduleModelFilePath) {
78
                $logger->info('Found model [' . $class . '] from module [' . $module . '], the file path is [' . $moduleModelFilePath . '] we will used it');
79
                $classFilePath = $moduleModelFilePath;
80
            } else {
81
                $logger->info('Cannot find model [' . $class . '] from modules using the default location');
82
            }
83
            $logger->info('The model file path to be loaded is [' . $classFilePath . ']');
84
            if (file_exists($classFilePath)) {
85
                require_once $classFilePath;
86
                if (class_exists($class)) {
87
                    $c = new $class();
88
                    $obj = & get_instance();
89
                    $obj->{$instance} = $c;
90
                    self::$loaded[$instance] = $class;
91
                    $logger->info('Model [' . $class . '] --> ' . $classFilePath . ' loaded successfully.');
92
                } else {
93
                    show_error('The file ' . $classFilePath . ' exists but does not contain the class [' . $class . ']');
94
                }
95
            } else {
96
                show_error('Unable to find the model [' . $class . ']');
97
            }
98
        }
99
100
		
101
        /**
102
         * Load the library class
103
         *
104
         * @param  string $class    the library class name to be loaded
105
         * @param  string $instance the instance name to use in super object
106
         * @param mixed $params the arguments to pass to the constructor
107
         *
108
         * @return void
109
         */
110
        public static function library($class, $instance = null, array $params = array()) {
111
            $logger = self::getLogger();
112
            $class = str_ireplace('.php', '', $class);
113
            $class = trim($class, '/\\');
114
            $file = ucfirst($class) . '.php';
115
            $logger->debug('Loading library [' . $class . '] ...');
116
            if (!$instance) {
117
                $instance = self::getModelLibraryInstanceName($class);
118
            }
119
            if (isset(self::$loaded[$instance])) {
120
                $logger->info('Library [' . $class . '] already loaded no need to load it again, cost in performance');
121
                return;
122
            }
123
            $obj = & get_instance();
124
            //Check and load Database library
125
            if (strtolower($class) == 'database') {
126
                $logger->info('This is the Database library ...');
127
                $obj->{$instance} = & class_loader('Database', 'classes/database', $params);
128
                self::$loaded[$instance] = $class;
129
                $logger->info('Library Database loaded successfully.');
130
                return;
131
            }
132
            $libraryFilePath = null;
133
            $logger->debug('Check if this is a system library ...');
134
            if (file_exists(CORE_LIBRARY_PATH . $file)) {
135
                $libraryFilePath = CORE_LIBRARY_PATH . $file;
136
                $class = ucfirst($class);
137
                $logger->info('This library is a system library');
138
            } else {
139
                $logger->info('This library is not a system library');	
140
                //first check if this library is in the module
141
                $info = self::getLibraryPathUsingModuleInfo($class);
142
                $class = $info['class'];
143
                $libraryFilePath = $info['path'];
144
            }
145
            if (!$libraryFilePath && file_exists(LIBRARY_PATH . $file)) {
146
                $libraryFilePath = LIBRARY_PATH . $file;
147
            }
148
            $logger->info('The library file path to be loaded is [' . $libraryFilePath . ']');
149
            self::loadLibrary($libraryFilePath, $class, $instance, $params);
150
        }
151
152
        /**
153
         * Load the helper
154
         *
155
         * @param  string $function the helper name to be loaded
156
         *
157
         * @return void
158
         */
159
        public static function functions($function) {
160
            $logger = self::getLogger();
161
            $function = str_ireplace('.php', '', $function);
162
            $function = trim($function, '/\\');
163
            $function = str_ireplace('function_', '', $function);
164
            $file = 'function_' . $function . '.php';
165
            $logger->debug('Loading helper [' . $function . '] ...');
166
            if (isset(self::$loaded['function_' . $function])) {
167
                $logger->info('Helper [' . $function . '] already loaded no need to load it again, cost in performance');
168
                return;
169
            }
170
            $functionFilePath = null;
171
            //first check if this helper is in the module
172
            $logger->debug('Checking helper [' . $function . '] from module list ...');
173
            $moduleInfo = self::getModuleInfoForFunction($function);
174
            $module    = $moduleInfo['module'];
175
            $function  = $moduleInfo['function'];
176
            if (!empty($moduleInfo['file'])) {
177
                $file = $moduleInfo['file'];
178
            }
179
            $moduleFunctionPath = Module::findFunctionFullPath($function, $module);
180
            if ($moduleFunctionPath) {
181
                $logger->info('Found helper [' . $function . '] from module [' . $module . '], the file path is [' . $moduleFunctionPath . '] we will used it');
182
                $functionFilePath = $moduleFunctionPath;
183
            } else {
184
                $logger->info('Cannot find helper [' . $function . '] from modules using the default location');
185
            }
186
            if (!$functionFilePath) {
187
                $functionFilePath = self::getDefaultFilePathForFunctionLanguage($file, 'function');
188
            }
189
            $logger->info('The helper file path to be loaded is [' . $functionFilePath . ']');
190
            if ($functionFilePath) {
191
                require_once $functionFilePath;
192
                self::$loaded['function_' . $function] = $functionFilePath;
193
                $logger->info('Helper [' . $function . '] --> ' . $functionFilePath . ' loaded successfully.');
194
            } else {
195
                show_error('Unable to find helper file [' . $file . ']');
196
            }
197
        }
198
199
        /**
200
         * Load the configuration file
201
         *
202
         * @param  string $filename the configuration filename located at CONFIG_PATH or MODULE_PATH/config
203
         *
204
         * @return void
205
         */
206
        public static function config($filename) {
207
            $logger = self::getLogger();
208
            $filename = str_ireplace('.php', '', $filename);
209
            $filename = trim($filename, '/\\');
210
            $filename = str_ireplace('config_', '', $filename);
211
            $file = 'config_' . $filename . '.php';
212
            $logger->debug('Loading configuration [' . $filename . '] ...');
213
            $configFilePath = CONFIG_PATH . $file;
214
            //first check if this config is in the module
215
            $logger->debug('Checking config [' . $filename . '] from module list ...');
216
            $moduleInfo = self::getModuleInfoForConfig($filename);
217
            $module    = $moduleInfo['module'];
218
            $filename  = $moduleInfo['filename'];
219
            $moduleConfigPath = Module::findConfigFullPath($filename, $module);
220
            if ($moduleConfigPath) {
221
                $logger->info('Found config [' . $filename . '] from module [' . $module . '], the file path is [' . $moduleConfigPath . '] we will used it');
222
                $configFilePath = $moduleConfigPath;
223
            } else {
224
                $logger->info('Cannot find config [' . $filename . '] from modules using the default location');
225
            }
226
            $logger->info('The config file path to be loaded is [' . $configFilePath . ']');
227
            $config = array();
228
            if (file_exists($configFilePath)) {
229
                //note need use require instead of require_once
230
                require $configFilePath;
231
                if (!empty($config) && is_array($config)) {
232
                    Config::setAll($config);
233
                    $logger->info('Configuration [' . $configFilePath . '] loaded successfully.');
234
                    $logger->info('The custom application configuration loaded are listed below: ' . stringfy_vars($config));
235
                    unset($config);
236
                }
237
            } else {
238
                show_error('Unable to find config file [' . $configFilePath . ']');
239
            }
240
        }
241
242
243
        /**
244
         * Load the language
245
         *
246
         * @param  string $language the language name to be loaded
247
         *
248
         * @return void
249
         */
250
        public static function lang($language) {
251
            $logger = self::getLogger();
252
            $language = str_ireplace('.php', '', $language);
253
            $language = trim($language, '/\\');
254
            $language = str_ireplace('lang_', '', $language);
255
            $file = 'lang_' . $language . '.php';
256
            $logger->debug('Loading language [' . $language . '] ...');
257
            if (isset(self::$loaded['lang_' . $language])) {
258
                $logger->info('Language [' . $language . '] already loaded no need to load it again, cost in performance');
259
                return;
260
            }
261
            //get the current language
262
            $appLang = self::getAppLang();
263
            $languageFilePath = null;
264
            //first check if this language is in the module
265
            $logger->debug('Checking language [' . $language . '] from module list ...');
266
            $moduleInfo = self::getModuleInfoForLanguage($language);
267
            $module    = $moduleInfo['module'];
268
            $language  = $moduleInfo['language'];
269
            if (!empty($moduleInfo['file'])) {
270
                $file = $moduleInfo['file'];
271
            }
272
            $moduleLanguagePath = Module::findLanguageFullPath($language, $appLang, $module);
273
            if ($moduleLanguagePath) {
274
                $logger->info('Found language [' . $language . '] from module [' . $module . '], the file path is [' . $moduleLanguagePath . '] we will used it');
275
                $languageFilePath = $moduleLanguagePath;
276
            } else {
277
                $logger->info('Cannot find language [' . $language . '] from modules using the default location');
278
            }
279
            if (!$languageFilePath) {
280
                $languageFilePath = self::getDefaultFilePathForFunctionLanguage($file, 'language', $appLang);
281
            }
282
            $logger->info('The language file path to be loaded is [' . $languageFilePath . ']');
283
            self::loadLanguage($languageFilePath, $language);
284
        }
285
286
        /**
287
         * Return the current app language by default will use the value from cookie 
288
         * if can not found will use the default value from configuration
289
         * @return string the app language like "en", "fr"
290
         */
291
        protected static function getAppLang() {
292
            //determine the current language
293
            $appLang = get_config('default_language');
294
            //if the language exists in the cookie use it
295
            $cfgKey = get_config('language_cookie_name');
296
            $objCookie = & class_loader('Cookie');
297
            $cookieLang = $objCookie->get($cfgKey);
298
            if ($cookieLang) {
299
                $appLang = $cookieLang;
300
            }
301
            return $appLang;
302
        }
303
304
        /**
305
         * Return the default full file path for function, language
306
         * @param  string $file    the filename
307
         * @param  string $type    the type can be "function", "language"
308
         * @param  string $appLang the application language, only if type = "language"
309
         * @return string|null          the full file path
310
         */
311
        protected static function getDefaultFilePathForFunctionLanguage($file, $type, $appLang = null){
312
            $searchDir = null;
313
            if ($type == 'function') {
314
               $searchDir = array(FUNCTIONS_PATH, CORE_FUNCTIONS_PATH);
315
            }
316
            else if ($type == 'language') {
317
                $searchDir = array(APP_LANG_PATH, CORE_LANG_PATH);
318
                $file = $appLang . DS . $file;
319
            }
320
            $fullFilePath = null;
321
            foreach ($searchDir as $dir) {
322
                $filePath = $dir . $file;
323
                if (file_exists($filePath)) {
324
                    $fullFilePath = $filePath;
325
                    //is already found not to continue
326
                    break;
327
                }
328
            }
329
            return $fullFilePath;
330
        }
331
332
        /**
333
         * Get the module using the attribute of super controller "moduleName"
334
         * @param  string|null $module the module if is not null will return it
335
         * @return string|null
336
         */
337
        protected static function getModuleFromSuperController($module){
338
            $obj = & get_instance();
339
            if (!$module && !empty($obj->moduleName)) {
340
                $module = $obj->moduleName;
341
            }
342
            return $module;
343
        }
344
345
        /**
346
         * Get the module information for the model and library to load
347
         * @param  string $class the full class name like moduleName/className, className,
348
         * @return array        the module information
349
         * array(
350
         * 	'module'=> 'module_name'
351
         * 	'class' => 'class_name'
352
         * )
353
         */
354
        protected static function getModuleInfoForModelLibrary($class) {
355
            $module = null;
356
            $path = explode('/', $class);
357
            if (count($path) >= 2 && isset($path[0]) && in_array($path[0], Module::getModuleList())) {
358
                $module = $path[0];
359
                $class = ucfirst($path[1]);
360
            } else {
361
                $class = ucfirst($class);
362
            }
363
            $module = self::getModuleFromSuperController($module);
364
            return array(
365
                        'class' => $class,
366
                        'module' => $module
367
                    );
368
        }
369
370
        /**
371
         * Get the module information for the function to load
372
         * @param  string $function the function name like moduleName/functionName, functionName,
373
         * @return array        the module information
374
         * array(
375
         * 	'module'=> 'module_name'
376
         * 	'function' => 'function'
377
         * 	'file' => 'file'
378
         * )
379
         */
380
        protected static function getModuleInfoForFunction($function) {
381
            $module = null;
382
            $file = null;
383
            //check if the request class contains module name
384
            $path = explode('/', $function);
385
            if (count($path) >= 2 && isset($path[0]) && in_array($path[0], Module::getModuleList())) {
386
                $module = $path[0];
387
                $function = 'function_' . $path[1];
388
                $file = $path[0] . DS . $function . '.php';
389
            }
390
            $module = self::getModuleFromSuperController($module);
391
            return array(
392
                        'function' => $function,
393
                        'module' => $module,
394
                        'file' => $file
395
                    );
396
        }
397
398
        /**
399
         * Get the module information for the language to load
400
         * @param  string $language the language name like moduleName/languageName, languageName,
401
         * @return array        the module information
402
         * array(
403
         * 	'module'=> 'module_name'
404
         * 	'language' => 'language'
405
         * 	'file' => 'file'
406
         * )
407
         */
408
        protected static function getModuleInfoForLanguage($language) {
409
            $module = null;
410
            $file = null;
411
            //check if the request class contains module name
412
            $path = explode('/', $language);
413
            if (count($path) >= 2 && isset($path[0]) && in_array($path[0], Module::getModuleList())) {
414
                $module = $path[0];
415
                $language = 'lang_' . $path[1] . '.php';
416
                $file = $path[0] . DS . $language;
417
            }
418
            $module = self::getModuleFromSuperController($module);
419
            return array(
420
                        'language' => $language,
421
                        'module' => $module,
422
                        'file' => $file
423
                    );
424
        }
425
426
427
        /**
428
         * Get the module information for the config to load
429
         * @param  string $filename the filename of the configuration file,
430
         * @return array        the module information
431
         * array(
432
         * 	'module'=> 'module_name'
433
         * 	'filename' => 'filename'
434
         * )
435
         */
436
        protected static function getModuleInfoForConfig($filename) {
437
            $module = null;
438
            //check if the request class contains module name
439
            $path = explode('/', $filename);
440
            if (count($path) >= 2 && isset($path[0]) && in_array($path[0], Module::getModuleList())) {
441
                $module = $path[0];
442
                $filename = $path[1] . '.php';
443
            }
444
            $module = self::getModuleFromSuperController($module);
445
            return array(
446
                        'filename' => $filename,
447
                        'module' => $module
448
                    );
449
        }
450
451
        /**
452
         * Get the name of model or library instance if is null
453
         * @param  string $class the class name to determine the instance
454
         * @return string        the instance name
455
         */
456
        protected static function getModelLibraryInstanceName($class) {
457
            //for module
458
            $instance = null;
459
            $path = explode('/', $class);
460
            if (count($path) >= 2 && isset($path[1])) {
461
                $instance = strtolower($path[1]);
462
            } else {
463
                $instance = strtolower($class);
464
            }
465
            return $instance;
466
        }
467
468
        /**
469
         * Get the library file path and class name using the module information
470
         * @param  string $class the class name
471
         * @return array        the library file path and class name
472
         */
473
        protected static function getLibraryPathUsingModuleInfo($class) {
474
            $logger = self::getLogger();
475
            $libraryFilePath = null;
476
            $logger->debug('Checking library [' . $class . '] from module list ...');
477
            $moduleInfo = self::getModuleInfoForModelLibrary($class);
478
            $module = $moduleInfo['module'];
479
            $class  = $moduleInfo['class'];
480
            $moduleLibraryPath = Module::findLibraryFullPath($class, $module);
481
            if ($moduleLibraryPath) {
482
                $logger->info('Found library [' . $class . '] from module [' . $module . '], the file path is [' . $moduleLibraryPath . '] we will used it');
483
                $libraryFilePath = $moduleLibraryPath;
484
            } else {
485
                $logger->info('Cannot find library [' . $class . '] from modules using the default location');
486
            }
487
            return array(
488
                        'path' => $libraryFilePath,
489
                        'class' => $class
490
                    );
491
        }
492
493
        /**
494
         * Load the library 
495
         * @param  string $libraryFilePath the file path of the library to load
496
         * @param  string $class           the class name
497
         * @param  string $instance        the instance
498
         * @param  array  $params          the parameter to use
499
         * @return void
500
         */
501
        protected static function loadLibrary($libraryFilePath, $class, $instance, $params = array()) {
502
            if ($libraryFilePath) {
503
                $logger = self::getLogger();
504
                require_once $libraryFilePath;
505
                if (class_exists($class)) {
506
                    $c = $params ? new $class($params) : new $class();
507
                    $obj = & get_instance();
508
                    $obj->{$instance} = $c;
509
                    self::$loaded[$instance] = $class;
510
                    $logger->info('Library [' . $class . '] --> ' . $libraryFilePath . ' loaded successfully.');
511
                } else {
512
                    show_error('The file ' . $libraryFilePath . ' exists but does not contain the class ' . $class);
513
                }
514
            } else {
515
                show_error('Unable to find library class [' . $class . ']');
516
            }
517
        }
518
519
        /**
520
         * Load the language 
521
         * @param  string $languageFilePath the file path of the language to load
522
         * @param  string $language           the language name
523
         * @return void
524
         */
525
        protected static function loadLanguage($languageFilePath, $language) {
526
            if ($languageFilePath) {
527
                $logger = self::getLogger();
528
                $lang = array();
529
                require_once $languageFilePath;
530
                if (!empty($lang) && is_array($lang)) {
531
                    $logger->info('Language file  [' . $languageFilePath . '] contains the valid languages keys add them to language list');
532
                    //Note: may be here the class 'Lang' not yet loaded
533
                    $langObj = & class_loader('Lang', 'classes');
534
                    $langObj->addLangMessages($lang);
535
                    //free the memory
536
                    unset($lang);
537
                }
538
                self::$loaded['lang_' . $language] = $languageFilePath;
539
                $logger->info('Language [' . $language . '] --> ' . $languageFilePath . ' loaded successfully.');
540
            } else {
541
                show_error('Unable to find language [' . $language . ']');
542
            }
543
        }
544
545
        /**
546
         * Load the resources autoload array
547
         * @param  string $method    this object method name to call
548
         * @param  array  $resources the resource to load
549
         * @return void            
550
         */
551
        protected function loadAutoloadResourcesArray($method, array $resources) {
552
            foreach ($resources as $name) {
553
                $this->{$method}($name);
554
            }
555
        }
556
557
        /**
558
         * Get all the autoload using the configuration file
559
         * @return array
560
         */
561
        protected function getResourcesFromAutoloadConfig() {
562
            $autoloads = array();
563
            $autoloads['config']    = array();
564
            $autoloads['languages'] = array();
565
            $autoloads['libraries'] = array();
566
            $autoloads['models']    = array();
567
            $autoloads['functions'] = array();
568
            //loading of the resources from autoload configuration file
569
            if (file_exists(CONFIG_PATH . 'autoload.php')) {
570
                $autoload = array();
571
                require_once CONFIG_PATH . 'autoload.php';
572
                if (!empty($autoload) && is_array($autoload)) {
573
                    $autoloads = array_merge($autoloads, $autoload);
574
                    unset($autoload);
575
                }
576
            }
577
            //loading autoload configuration for modules
578
            $modulesAutoloads = Module::getModulesAutoloadConfig();
579
            if (!empty($modulesAutoloads) && is_array($modulesAutoloads)) {
580
                $autoloads = array_merge_recursive($autoloads, $modulesAutoloads);
581
            }
582
            return $autoloads;
583
        }
584
585
        /**
586
         * Load the autoload configuration
587
         * @return void
588
         */
589
        protected function loadResourcesFromAutoloadConfig() {
590
            $autoloads = array();
591
            $autoloads['config']    = array();
592
            $autoloads['languages'] = array();
593
            $autoloads['libraries'] = array();
594
            $autoloads['models']    = array();
595
            $autoloads['functions'] = array();
596
597
            $list = $this->getResourcesFromAutoloadConfig();
598
            $autoloads = array_merge($autoloads, $list);
599
			
600
            //config autoload
601
            $this->loadAutoloadResourcesArray('config', $autoloads['config']);
602
			
603
            //languages autoload
604
            $this->loadAutoloadResourcesArray('lang', $autoloads['languages']);
605
			
606
            //libraries autoload
607
            $this->loadAutoloadResourcesArray('library', $autoloads['libraries']);
608
609
            //models autoload
610
            $this->loadAutoloadResourcesArray('model', $autoloads['models']);
611
			
612
            //functions autoload
613
            $this->loadAutoloadResourcesArray('functions', $autoloads['functions']);
614
        }
615
    }
616