Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CI_Loader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CI_Loader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
51 | View Code Duplication | class CI_Loader { |
|
52 | |||
53 | // All these are set automatically. Don't mess with them. |
||
54 | /** |
||
55 | * Nesting level of the output buffering mechanism |
||
56 | * |
||
57 | * @var int |
||
58 | */ |
||
59 | protected $_ci_ob_level; |
||
60 | |||
61 | /** |
||
62 | * List of paths to load views from |
||
63 | * |
||
64 | * @var array |
||
65 | */ |
||
66 | protected $_ci_view_paths = array(VIEWPATH => TRUE); |
||
67 | |||
68 | /** |
||
69 | * List of paths to load libraries from |
||
70 | * |
||
71 | * @var array |
||
72 | */ |
||
73 | protected $_ci_library_paths = array(APPPATH, BASEPATH); |
||
74 | |||
75 | /** |
||
76 | * List of paths to load models from |
||
77 | * |
||
78 | * @var array |
||
79 | */ |
||
80 | protected $_ci_model_paths = array(APPPATH); |
||
81 | |||
82 | /** |
||
83 | * List of paths to load helpers from |
||
84 | * |
||
85 | * @var array |
||
86 | */ |
||
87 | protected $_ci_helper_paths = array(APPPATH, BASEPATH); |
||
88 | |||
89 | /** |
||
90 | * List of cached variables |
||
91 | * |
||
92 | * @var array |
||
93 | */ |
||
94 | protected $_ci_cached_vars = array(); |
||
95 | |||
96 | /** |
||
97 | * List of loaded classes |
||
98 | * |
||
99 | * @var array |
||
100 | */ |
||
101 | protected $_ci_classes = array(); |
||
102 | |||
103 | /** |
||
104 | * List of loaded models |
||
105 | * |
||
106 | * @var array |
||
107 | */ |
||
108 | protected $_ci_models = array(); |
||
109 | |||
110 | /** |
||
111 | * List of loaded helpers |
||
112 | * |
||
113 | * @var array |
||
114 | */ |
||
115 | protected $_ci_helpers = array(); |
||
116 | |||
117 | /** |
||
118 | * List of class name mappings |
||
119 | * |
||
120 | * @var array |
||
121 | */ |
||
122 | protected $_ci_varmap = array( |
||
123 | 'unit_test' => 'unit', |
||
124 | 'user_agent' => 'agent' |
||
125 | ); |
||
126 | |||
127 | // -------------------------------------------------------------------- |
||
128 | |||
129 | /** |
||
130 | * Class constructor |
||
131 | * |
||
132 | * Sets component load paths, gets the initial output buffering level. |
||
133 | * |
||
134 | * @return void |
||
135 | * |
||
136 | * @codeCoverageIgnore |
||
137 | */ |
||
138 | public function __construct() |
||
139 | { |
||
140 | $this->_ci_ob_level = ob_get_level(); |
||
141 | $this->_ci_classes =& is_loaded(); |
||
142 | |||
143 | log_message('info', 'Loader Class Initialized'); |
||
144 | } |
||
145 | |||
146 | // -------------------------------------------------------------------- |
||
147 | |||
148 | /** |
||
149 | * Initializer |
||
150 | * |
||
151 | * @todo Figure out a way to move this to the constructor |
||
152 | * without breaking *package_path*() methods. |
||
153 | * @uses CI_Loader::_ci_autoloader() |
||
154 | * @used-by CI_Controller::__construct() |
||
155 | * @return void |
||
156 | * |
||
157 | * @codeCoverageIgnore |
||
158 | */ |
||
159 | public function initialize() |
||
160 | { |
||
161 | $this->_ci_autoloader(); |
||
162 | } |
||
163 | |||
164 | // -------------------------------------------------------------------- |
||
165 | |||
166 | /** |
||
167 | * Is Loaded |
||
168 | * |
||
169 | * A utility method to test if a class is in the self::$_ci_classes array. |
||
170 | * |
||
171 | * @used-by Mainly used by Form Helper function _get_validation_object(). |
||
172 | * |
||
173 | * @param string $class Class name to check for |
||
174 | * @return string|bool Class object name if loaded or FALSE |
||
175 | * |
||
176 | * @codeCoverageIgnore |
||
177 | */ |
||
178 | public function is_loaded($class) |
||
179 | { |
||
180 | return array_search(ucfirst($class), $this->_ci_classes, TRUE); |
||
181 | } |
||
182 | |||
183 | // -------------------------------------------------------------------- |
||
184 | |||
185 | /** |
||
186 | * Library Loader |
||
187 | * |
||
188 | * Loads and instantiates libraries. |
||
189 | * Designed to be called from application controllers. |
||
190 | * |
||
191 | * @param string $library Library name |
||
192 | * @param array $params Optional parameters to pass to the library class constructor |
||
193 | * @param string $object_name An optional object name to assign to |
||
194 | * @return object |
||
195 | * |
||
196 | * @codeCoverageIgnore |
||
197 | */ |
||
198 | public function library($library, $params = NULL, $object_name = NULL) |
||
199 | { |
||
200 | if (empty($library)) |
||
201 | { |
||
202 | return $this; |
||
203 | } |
||
204 | elseif (is_array($library)) |
||
205 | { |
||
206 | foreach ($library as $key => $value) |
||
207 | { |
||
208 | if (is_int($key)) |
||
209 | { |
||
210 | $this->library($value, $params); |
||
211 | } |
||
212 | else |
||
213 | { |
||
214 | $this->library($key, $params, $value); |
||
215 | } |
||
216 | } |
||
217 | |||
218 | return $this; |
||
219 | } |
||
220 | |||
221 | if ($params !== NULL && ! is_array($params)) |
||
222 | { |
||
223 | $params = NULL; |
||
224 | } |
||
225 | |||
226 | $this->_ci_load_library($library, $params, $object_name); |
||
227 | return $this; |
||
228 | } |
||
229 | |||
230 | // -------------------------------------------------------------------- |
||
231 | |||
232 | /** |
||
233 | * Model Loader |
||
234 | * |
||
235 | * Loads and instantiates models. |
||
236 | * |
||
237 | * @param string $model Model name |
||
238 | * @param string $name An optional object name to assign to |
||
239 | * @param bool $db_conn An optional database connection configuration to initialize |
||
240 | * @return object |
||
241 | * |
||
242 | * modified by ci-phpunit-test |
||
243 | */ |
||
244 | public function model($model, $name = '', $db_conn = FALSE) |
||
245 | { |
||
246 | if (empty($model)) |
||
247 | { |
||
248 | return $this; |
||
249 | } |
||
250 | elseif (is_array($model)) |
||
251 | { |
||
252 | foreach ($model as $key => $value) |
||
253 | { |
||
254 | is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn); |
||
255 | } |
||
256 | |||
257 | return $this; |
||
258 | } |
||
259 | |||
260 | $path = ''; |
||
261 | |||
262 | // Is the model in a sub-folder? If so, parse out the filename and path. |
||
263 | if (($last_slash = strrpos($model, '/')) !== FALSE) |
||
264 | { |
||
265 | // The path is in front of the last slash |
||
266 | $path = substr($model, 0, ++$last_slash); |
||
267 | |||
268 | // And the model name behind it |
||
269 | $model = substr($model, $last_slash); |
||
270 | } |
||
271 | |||
272 | if (empty($name)) |
||
273 | { |
||
274 | $name = $model; |
||
275 | } |
||
276 | |||
277 | if (in_array($name, $this->_ci_models, TRUE)) |
||
278 | { |
||
279 | return $this; |
||
280 | } |
||
281 | |||
282 | $CI =& get_instance(); |
||
283 | if (isset($CI->$name)) |
||
284 | { |
||
285 | throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name); |
||
286 | } |
||
287 | |||
288 | if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE)) |
||
289 | { |
||
290 | if ($db_conn === TRUE) |
||
291 | { |
||
292 | $db_conn = ''; |
||
293 | } |
||
294 | |||
295 | $this->database($db_conn, FALSE, TRUE); |
||
296 | } |
||
297 | |||
298 | // Note: All of the code under this condition used to be just: |
||
299 | // |
||
300 | // load_class('Model', 'core'); |
||
301 | // |
||
302 | // However, load_class() instantiates classes |
||
303 | // to cache them for later use and that prevents |
||
304 | // MY_Model from being an abstract class and is |
||
305 | // sub-optimal otherwise anyway. |
||
306 | // if ( ! class_exists('CI_Model', FALSE)) |
||
307 | // { |
||
308 | $app_path = APPPATH.'core'.DIRECTORY_SEPARATOR; |
||
309 | if (file_exists($app_path.'Model.php')) |
||
310 | { |
||
311 | require_once($app_path.'Model.php'); |
||
312 | if ( ! class_exists('CI_Model', FALSE)) |
||
313 | { |
||
314 | throw new RuntimeException($app_path."Model.php exists, but doesn't declare class CI_Model"); |
||
315 | } |
||
316 | } |
||
317 | elseif ( ! class_exists('CI_Model', FALSE)) |
||
318 | { |
||
319 | require_once(BASEPATH.'core'.DIRECTORY_SEPARATOR.'Model.php'); |
||
320 | } |
||
321 | |||
322 | $class = config_item('subclass_prefix').'Model'; |
||
323 | if (file_exists($app_path.$class.'.php')) |
||
324 | { |
||
325 | require_once($app_path.$class.'.php'); |
||
326 | if ( ! class_exists($class, FALSE)) |
||
327 | { |
||
328 | throw new RuntimeException($app_path.$class.".php exists, but doesn't declare class ".$class); |
||
329 | } |
||
330 | } |
||
331 | // } |
||
332 | |||
333 | $model = ucfirst($model); |
||
334 | if ( ! class_exists($model, FALSE)) |
||
335 | { |
||
336 | foreach ($this->_ci_model_paths as $mod_path) |
||
337 | { |
||
338 | if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) |
||
339 | { |
||
340 | continue; |
||
341 | } |
||
342 | |||
343 | require_once($mod_path.'models/'.$path.$model.'.php'); |
||
344 | if ( ! class_exists($model, FALSE)) |
||
345 | { |
||
346 | throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model); |
||
347 | } |
||
348 | |||
349 | break; |
||
350 | } |
||
351 | |||
352 | if ( ! class_exists($model, FALSE)) |
||
353 | { |
||
354 | throw new RuntimeException('Unable to locate the model you have specified: '.$model); |
||
355 | } |
||
356 | } |
||
357 | // elseif ( ! is_subclass_of($model, 'CI_Model')) |
||
358 | // { |
||
359 | // throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model"); |
||
360 | // } |
||
361 | |||
362 | $this->_ci_models[] = $name; |
||
363 | $CI->$name = new $model(); |
||
364 | return $this; |
||
365 | } |
||
366 | |||
367 | // -------------------------------------------------------------------- |
||
368 | |||
369 | /** |
||
370 | * Database Loader |
||
371 | * |
||
372 | * @param mixed $params Database configuration options |
||
373 | * @param bool $return Whether to return the database object |
||
374 | * @param bool $query_builder Whether to enable Query Builder |
||
375 | * (overrides the configuration setting) |
||
376 | * |
||
377 | * @return object|bool Database object if $return is set to TRUE, |
||
378 | * FALSE on failure, CI_Loader instance in any other case |
||
379 | * |
||
380 | * @codeCoverageIgnore |
||
381 | */ |
||
382 | public function database($params = '', $return = FALSE, $query_builder = NULL) |
||
383 | { |
||
384 | // Grab the super object |
||
385 | $CI =& get_instance(); |
||
386 | |||
387 | // Do we even need to load the database class? |
||
388 | if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id)) |
||
389 | { |
||
390 | return FALSE; |
||
391 | } |
||
392 | |||
393 | require_once(BASEPATH.'database/DB.php'); |
||
394 | |||
395 | if ($return === TRUE) |
||
396 | { |
||
397 | return DB($params, $query_builder); |
||
398 | } |
||
399 | |||
400 | // Initialize the db variable. Needed to prevent |
||
401 | // reference errors with some configurations |
||
402 | $CI->db = ''; |
||
403 | |||
404 | // Load the DB class |
||
405 | $CI->db =& DB($params, $query_builder); |
||
406 | return $this; |
||
407 | } |
||
408 | |||
409 | // -------------------------------------------------------------------- |
||
410 | |||
411 | /** |
||
412 | * Load the Database Utilities Class |
||
413 | * |
||
414 | * @param object $db Database object |
||
415 | * @param bool $return Whether to return the DB Utilities class object or not |
||
416 | * @return object |
||
417 | * |
||
418 | * @codeCoverageIgnore |
||
419 | */ |
||
420 | public function dbutil($db = NULL, $return = FALSE) |
||
421 | { |
||
422 | $CI =& get_instance(); |
||
423 | |||
424 | if ( ! is_object($db) OR ! ($db instanceof CI_DB)) |
||
425 | { |
||
426 | class_exists('CI_DB', FALSE) OR $this->database(); |
||
427 | $db =& $CI->db; |
||
428 | } |
||
429 | |||
430 | require_once(BASEPATH.'database/DB_utility.php'); |
||
431 | require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php'); |
||
432 | $class = 'CI_DB_'.$db->dbdriver.'_utility'; |
||
433 | |||
434 | if ($return === TRUE) |
||
435 | { |
||
436 | return new $class($db); |
||
437 | } |
||
438 | |||
439 | $CI->dbutil = new $class($db); |
||
440 | return $this; |
||
441 | } |
||
442 | |||
443 | // -------------------------------------------------------------------- |
||
444 | |||
445 | /** |
||
446 | * Load the Database Forge Class |
||
447 | * |
||
448 | * @param object $db Database object |
||
449 | * @param bool $return Whether to return the DB Forge class object or not |
||
450 | * @return object |
||
451 | * |
||
452 | * @codeCoverageIgnore |
||
453 | */ |
||
454 | public function dbforge($db = NULL, $return = FALSE) |
||
455 | { |
||
456 | $CI =& get_instance(); |
||
457 | if ( ! is_object($db) OR ! ($db instanceof CI_DB)) |
||
458 | { |
||
459 | class_exists('CI_DB', FALSE) OR $this->database(); |
||
460 | $db =& $CI->db; |
||
461 | } |
||
462 | |||
463 | require_once(BASEPATH.'database/DB_forge.php'); |
||
464 | require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php'); |
||
465 | |||
466 | if ( ! empty($db->subdriver)) |
||
467 | { |
||
468 | $driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php'; |
||
469 | if (file_exists($driver_path)) |
||
470 | { |
||
471 | require_once($driver_path); |
||
472 | $class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge'; |
||
473 | } |
||
474 | } |
||
475 | else |
||
476 | { |
||
477 | $class = 'CI_DB_'.$db->dbdriver.'_forge'; |
||
478 | } |
||
479 | |||
480 | if ($return === TRUE) |
||
481 | { |
||
482 | return new $class($db); |
||
483 | } |
||
484 | |||
485 | $CI->dbforge = new $class($db); |
||
486 | return $this; |
||
487 | } |
||
488 | |||
489 | // -------------------------------------------------------------------- |
||
490 | |||
491 | /** |
||
492 | * View Loader |
||
493 | * |
||
494 | * Loads "view" files. |
||
495 | * |
||
496 | * @param string $view View name |
||
497 | * @param array $vars An associative array of data |
||
498 | * to be extracted for use in the view |
||
499 | * @param bool $return Whether to return the view output |
||
500 | * or leave it to the Output class |
||
501 | * @return object|string |
||
502 | * |
||
503 | * @codeCoverageIgnore |
||
504 | */ |
||
505 | public function view($view, $vars = array(), $return = FALSE) |
||
506 | { |
||
507 | return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_prepare_view_vars($vars), '_ci_return' => $return)); |
||
508 | } |
||
509 | |||
510 | // -------------------------------------------------------------------- |
||
511 | |||
512 | /** |
||
513 | * Generic File Loader |
||
514 | * |
||
515 | * @param string $path File path |
||
516 | * @param bool $return Whether to return the file output |
||
517 | * @return object|string |
||
518 | * |
||
519 | * @codeCoverageIgnore |
||
520 | */ |
||
521 | public function file($path, $return = FALSE) |
||
522 | { |
||
523 | return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); |
||
524 | } |
||
525 | |||
526 | // -------------------------------------------------------------------- |
||
527 | |||
528 | /** |
||
529 | * Set Variables |
||
530 | * |
||
531 | * Once variables are set they become available within |
||
532 | * the controller class and its "view" files. |
||
533 | * |
||
534 | * @param array|object|string $vars |
||
535 | * An associative array or object containing values |
||
536 | * to be set, or a value's name if string |
||
537 | * @param string $val Value to set, only used if $vars is a string |
||
538 | * @return object |
||
539 | * |
||
540 | * @codeCoverageIgnore |
||
541 | */ |
||
542 | public function vars($vars, $val = '') |
||
543 | { |
||
544 | $vars = is_string($vars) |
||
545 | ? array($vars => $val) |
||
546 | : $this->_ci_prepare_view_vars($vars); |
||
547 | |||
548 | foreach ($vars as $key => $val) |
||
549 | { |
||
550 | $this->_ci_cached_vars[$key] = $val; |
||
551 | } |
||
552 | |||
553 | return $this; |
||
554 | } |
||
555 | |||
556 | // -------------------------------------------------------------------- |
||
557 | |||
558 | /** |
||
559 | * Clear Cached Variables |
||
560 | * |
||
561 | * Clears the cached variables. |
||
562 | * |
||
563 | * @return CI_Loader |
||
564 | * |
||
565 | * @codeCoverageIgnore |
||
566 | */ |
||
567 | public function clear_vars() |
||
568 | { |
||
569 | $this->_ci_cached_vars = array(); |
||
570 | return $this; |
||
571 | } |
||
572 | |||
573 | // -------------------------------------------------------------------- |
||
574 | |||
575 | /** |
||
576 | * Get Variable |
||
577 | * |
||
578 | * Check if a variable is set and retrieve it. |
||
579 | * |
||
580 | * @param string $key Variable name |
||
581 | * @return mixed The variable or NULL if not found |
||
582 | * |
||
583 | * @codeCoverageIgnore |
||
584 | */ |
||
585 | public function get_var($key) |
||
586 | { |
||
587 | return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; |
||
588 | } |
||
589 | |||
590 | // -------------------------------------------------------------------- |
||
591 | |||
592 | /** |
||
593 | * Get Variables |
||
594 | * |
||
595 | * Retrieves all loaded variables. |
||
596 | * |
||
597 | * @return array |
||
598 | * |
||
599 | * @codeCoverageIgnore |
||
600 | */ |
||
601 | public function get_vars() |
||
602 | { |
||
603 | return $this->_ci_cached_vars; |
||
604 | } |
||
605 | |||
606 | // -------------------------------------------------------------------- |
||
607 | |||
608 | /** |
||
609 | * Helper Loader |
||
610 | * |
||
611 | * @param string|string[] $helpers Helper name(s) |
||
612 | * @return object |
||
613 | * |
||
614 | * @codeCoverageIgnore |
||
615 | */ |
||
616 | public function helper($helpers = array()) |
||
617 | { |
||
618 | is_array($helpers) OR $helpers = array($helpers); |
||
619 | foreach ($helpers as &$helper) |
||
620 | { |
||
621 | $filename = basename($helper); |
||
622 | $filepath = ($filename === $helper) ? '' : substr($helper, 0, strlen($helper) - strlen($filename)); |
||
623 | $filename = strtolower(preg_replace('#(_helper)?(\.php)?$#i', '', $filename)).'_helper'; |
||
624 | $helper = $filepath.$filename; |
||
625 | |||
626 | if (isset($this->_ci_helpers[$helper])) |
||
627 | { |
||
628 | continue; |
||
629 | } |
||
630 | |||
631 | // Is this a helper extension request? |
||
632 | $ext_helper = config_item('subclass_prefix').$filename; |
||
633 | $ext_loaded = FALSE; |
||
634 | foreach ($this->_ci_helper_paths as $path) |
||
635 | { |
||
636 | if (file_exists($path.'helpers/'.$ext_helper.'.php')) |
||
637 | { |
||
638 | include_once($path.'helpers/'.$ext_helper.'.php'); |
||
639 | $ext_loaded = TRUE; |
||
640 | } |
||
641 | } |
||
642 | |||
643 | // If we have loaded extensions - check if the base one is here |
||
644 | if ($ext_loaded === TRUE) |
||
645 | { |
||
646 | $base_helper = BASEPATH.'helpers/'.$helper.'.php'; |
||
647 | if ( ! file_exists($base_helper)) |
||
648 | { |
||
649 | show_error('Unable to load the requested file: helpers/'.$helper.'.php'); |
||
650 | } |
||
651 | |||
652 | include_once($base_helper); |
||
653 | $this->_ci_helpers[$helper] = TRUE; |
||
654 | log_message('info', 'Helper loaded: '.$helper); |
||
655 | continue; |
||
656 | } |
||
657 | |||
658 | // No extensions found ... try loading regular helpers and/or overrides |
||
659 | foreach ($this->_ci_helper_paths as $path) |
||
660 | { |
||
661 | if (file_exists($path.'helpers/'.$helper.'.php')) |
||
662 | { |
||
663 | include_once($path.'helpers/'.$helper.'.php'); |
||
664 | |||
665 | $this->_ci_helpers[$helper] = TRUE; |
||
666 | log_message('info', 'Helper loaded: '.$helper); |
||
667 | break; |
||
668 | } |
||
669 | } |
||
670 | |||
671 | // unable to load the helper |
||
672 | if ( ! isset($this->_ci_helpers[$helper])) |
||
673 | { |
||
674 | show_error('Unable to load the requested file: helpers/'.$helper.'.php'); |
||
675 | } |
||
676 | } |
||
677 | |||
678 | return $this; |
||
679 | } |
||
680 | |||
681 | // -------------------------------------------------------------------- |
||
682 | |||
683 | /** |
||
684 | * Load Helpers |
||
685 | * |
||
686 | * An alias for the helper() method in case the developer has |
||
687 | * written the plural form of it. |
||
688 | * |
||
689 | * @uses CI_Loader::helper() |
||
690 | * @param string|string[] $helpers Helper name(s) |
||
691 | * @return object |
||
692 | * |
||
693 | * @codeCoverageIgnore |
||
694 | */ |
||
695 | public function helpers($helpers = array()) |
||
696 | { |
||
697 | return $this->helper($helpers); |
||
698 | } |
||
699 | |||
700 | // -------------------------------------------------------------------- |
||
701 | |||
702 | /** |
||
703 | * Language Loader |
||
704 | * |
||
705 | * Loads language files. |
||
706 | * |
||
707 | * @param string|string[] $files List of language file names to load |
||
708 | * @param string Language name |
||
709 | * @return object |
||
710 | * |
||
711 | * @codeCoverageIgnore |
||
712 | */ |
||
713 | public function language($files, $lang = '') |
||
714 | { |
||
715 | get_instance()->lang->load($files, $lang); |
||
716 | return $this; |
||
717 | } |
||
718 | |||
719 | // -------------------------------------------------------------------- |
||
720 | |||
721 | /** |
||
722 | * Config Loader |
||
723 | * |
||
724 | * Loads a config file (an alias for CI_Config::load()). |
||
725 | * |
||
726 | * @uses CI_Config::load() |
||
727 | * @param string $file Configuration file name |
||
728 | * @param bool $use_sections Whether configuration values should be loaded into their own section |
||
729 | * @param bool $fail_gracefully Whether to just return FALSE or display an error message |
||
730 | * @return bool TRUE if the file was loaded correctly or FALSE on failure |
||
731 | * |
||
732 | * @codeCoverageIgnore |
||
733 | */ |
||
734 | public function config($file, $use_sections = FALSE, $fail_gracefully = FALSE) |
||
735 | { |
||
736 | return get_instance()->config->load($file, $use_sections, $fail_gracefully); |
||
737 | } |
||
738 | |||
739 | // -------------------------------------------------------------------- |
||
740 | |||
741 | /** |
||
742 | * Driver Loader |
||
743 | * |
||
744 | * Loads a driver library. |
||
745 | * |
||
746 | * @param string|string[] $library Driver name(s) |
||
747 | * @param array $params Optional parameters to pass to the driver |
||
748 | * @param string $object_name An optional object name to assign to |
||
749 | * |
||
750 | * @return object|bool Object or FALSE on failure if $library is a string |
||
751 | * and $object_name is set. CI_Loader instance otherwise. |
||
752 | * |
||
753 | * @codeCoverageIgnore |
||
754 | */ |
||
755 | public function driver($library, $params = NULL, $object_name = NULL) |
||
756 | { |
||
757 | if (is_array($library)) |
||
758 | { |
||
759 | foreach ($library as $key => $value) |
||
760 | { |
||
761 | if (is_int($key)) |
||
762 | { |
||
763 | $this->driver($value, $params); |
||
764 | } |
||
765 | else |
||
766 | { |
||
767 | $this->driver($key, $params, $value); |
||
768 | } |
||
769 | } |
||
770 | |||
771 | return $this; |
||
772 | } |
||
773 | elseif (empty($library)) |
||
774 | { |
||
775 | return FALSE; |
||
776 | } |
||
777 | |||
778 | if ( ! class_exists('CI_Driver_Library', FALSE)) |
||
779 | { |
||
780 | // We aren't instantiating an object here, just making the base class available |
||
781 | require BASEPATH.'libraries/Driver.php'; |
||
782 | } |
||
783 | |||
784 | // We can save the loader some time since Drivers will *always* be in a subfolder, |
||
785 | // and typically identically named to the library |
||
786 | if ( ! strpos($library, '/')) |
||
787 | { |
||
788 | $library = ucfirst($library).'/'.$library; |
||
789 | } |
||
790 | |||
791 | return $this->library($library, $params, $object_name); |
||
792 | } |
||
793 | |||
794 | // -------------------------------------------------------------------- |
||
795 | |||
796 | /** |
||
797 | * Add Package Path |
||
798 | * |
||
799 | * Prepends a parent path to the library, model, helper and config |
||
800 | * path arrays. |
||
801 | * |
||
802 | * @see CI_Loader::$_ci_library_paths |
||
803 | * @see CI_Loader::$_ci_model_paths |
||
804 | * @see CI_Loader::$_ci_helper_paths |
||
805 | * @see CI_Config::$_config_paths |
||
806 | * |
||
807 | * @param string $path Path to add |
||
808 | * @param bool $view_cascade (default: TRUE) |
||
809 | * @return object |
||
810 | * |
||
811 | * @codeCoverageIgnore |
||
812 | */ |
||
813 | public function add_package_path($path, $view_cascade = TRUE) |
||
814 | { |
||
815 | $path = rtrim($path, '/').'/'; |
||
816 | |||
817 | array_unshift($this->_ci_library_paths, $path); |
||
818 | array_unshift($this->_ci_model_paths, $path); |
||
819 | array_unshift($this->_ci_helper_paths, $path); |
||
820 | |||
821 | $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths; |
||
822 | |||
823 | // Add config file path |
||
824 | $config =& $this->_ci_get_component('config'); |
||
825 | $config->_config_paths[] = $path; |
||
826 | |||
827 | return $this; |
||
828 | } |
||
829 | |||
830 | // -------------------------------------------------------------------- |
||
831 | |||
832 | /** |
||
833 | * Get Package Paths |
||
834 | * |
||
835 | * Return a list of all package paths. |
||
836 | * |
||
837 | * @param bool $include_base Whether to include BASEPATH (default: FALSE) |
||
838 | * @return array |
||
839 | * |
||
840 | * @codeCoverageIgnore |
||
841 | */ |
||
842 | public function get_package_paths($include_base = FALSE) |
||
843 | { |
||
844 | return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths; |
||
845 | } |
||
846 | |||
847 | // -------------------------------------------------------------------- |
||
848 | |||
849 | /** |
||
850 | * Remove Package Path |
||
851 | * |
||
852 | * Remove a path from the library, model, helper and/or config |
||
853 | * path arrays if it exists. If no path is provided, the most recently |
||
854 | * added path will be removed removed. |
||
855 | * |
||
856 | * @param string $path Path to remove |
||
857 | * @return object |
||
858 | * |
||
859 | * @codeCoverageIgnore |
||
860 | */ |
||
861 | public function remove_package_path($path = '') |
||
862 | { |
||
863 | $config =& $this->_ci_get_component('config'); |
||
864 | |||
865 | if ($path === '') |
||
866 | { |
||
867 | array_shift($this->_ci_library_paths); |
||
868 | array_shift($this->_ci_model_paths); |
||
869 | array_shift($this->_ci_helper_paths); |
||
870 | array_shift($this->_ci_view_paths); |
||
871 | array_pop($config->_config_paths); |
||
872 | } |
||
873 | else |
||
874 | { |
||
875 | $path = rtrim($path, '/').'/'; |
||
876 | foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var) |
||
877 | { |
||
878 | if (($key = array_search($path, $this->{$var})) !== FALSE) |
||
879 | { |
||
880 | unset($this->{$var}[$key]); |
||
881 | } |
||
882 | } |
||
883 | |||
884 | if (isset($this->_ci_view_paths[$path.'views/'])) |
||
885 | { |
||
886 | unset($this->_ci_view_paths[$path.'views/']); |
||
887 | } |
||
888 | |||
889 | if (($key = array_search($path, $config->_config_paths)) !== FALSE) |
||
890 | { |
||
891 | unset($config->_config_paths[$key]); |
||
892 | } |
||
893 | } |
||
894 | |||
895 | // make sure the application default paths are still in the array |
||
896 | $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH))); |
||
897 | $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH))); |
||
898 | $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH))); |
||
899 | $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE)); |
||
900 | $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); |
||
901 | |||
902 | return $this; |
||
903 | } |
||
904 | |||
905 | // -------------------------------------------------------------------- |
||
906 | |||
907 | /** |
||
908 | * Internal CI Data Loader |
||
909 | * |
||
910 | * Used to load views and files. |
||
911 | * |
||
912 | * Variables are prefixed with _ci_ to avoid symbol collision with |
||
913 | * variables made available to view files. |
||
914 | * |
||
915 | * @used-by CI_Loader::view() |
||
916 | * @used-by CI_Loader::file() |
||
917 | * @param array $_ci_data Data to load |
||
918 | * @return object |
||
919 | * |
||
920 | * @codeCoverageIgnore |
||
921 | */ |
||
922 | protected function _ci_load($_ci_data) |
||
923 | { |
||
924 | // Set the default data variables |
||
925 | foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val) |
||
926 | { |
||
927 | $$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE; |
||
928 | } |
||
929 | |||
930 | $file_exists = FALSE; |
||
931 | |||
932 | // Set the path to the requested file |
||
933 | if (is_string($_ci_path) && $_ci_path !== '') |
||
934 | { |
||
935 | $_ci_x = explode('/', $_ci_path); |
||
936 | $_ci_file = end($_ci_x); |
||
937 | } |
||
938 | else |
||
939 | { |
||
940 | $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); |
||
941 | $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view; |
||
942 | |||
943 | foreach ($this->_ci_view_paths as $_ci_view_file => $cascade) |
||
944 | { |
||
945 | if (file_exists($_ci_view_file.$_ci_file)) |
||
946 | { |
||
947 | $_ci_path = $_ci_view_file.$_ci_file; |
||
948 | $file_exists = TRUE; |
||
949 | break; |
||
950 | } |
||
951 | |||
952 | if ( ! $cascade) |
||
953 | { |
||
954 | break; |
||
955 | } |
||
956 | } |
||
957 | } |
||
958 | |||
959 | if ( ! $file_exists && ! file_exists($_ci_path)) |
||
960 | { |
||
961 | show_error('Unable to load the requested file: '.$_ci_file); |
||
962 | } |
||
963 | |||
964 | // This allows anything loaded using $this->load (views, files, etc.) |
||
965 | // to become accessible from within the Controller and Model functions. |
||
966 | $_ci_CI =& get_instance(); |
||
967 | foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) |
||
968 | { |
||
969 | if ( ! isset($this->$_ci_key)) |
||
970 | { |
||
971 | $this->$_ci_key =& $_ci_CI->$_ci_key; |
||
972 | } |
||
973 | } |
||
974 | |||
975 | /* |
||
976 | * Extract and cache variables |
||
977 | * |
||
978 | * You can either set variables using the dedicated $this->load->vars() |
||
979 | * function or via the second parameter of this function. We'll merge |
||
980 | * the two types and cache them so that views that are embedded within |
||
981 | * other views can have access to these variables. |
||
982 | */ |
||
983 | empty($_ci_vars) OR $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars); |
||
984 | extract($this->_ci_cached_vars); |
||
985 | |||
986 | /* |
||
987 | * Buffer the output |
||
988 | * |
||
989 | * We buffer the output for two reasons: |
||
990 | * 1. Speed. You get a significant speed boost. |
||
991 | * 2. So that the final rendered template can be post-processed by |
||
992 | * the output class. Why do we need post processing? For one thing, |
||
993 | * in order to show the elapsed page load time. Unless we can |
||
994 | * intercept the content right before it's sent to the browser and |
||
995 | * then stop the timer it won't be accurate. |
||
996 | */ |
||
997 | ob_start(); |
||
998 | |||
999 | // If the PHP installation does not support short tags we'll |
||
1000 | // do a little string replacement, changing the short tags |
||
1001 | // to standard PHP echo statements. |
||
1002 | if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE) |
||
1003 | { |
||
1004 | echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path)))); |
||
1005 | } |
||
1006 | else |
||
1007 | { |
||
1008 | include($_ci_path); // include() vs include_once() allows for multiple views with the same name |
||
1009 | } |
||
1010 | |||
1011 | log_message('info', 'File loaded: '.$_ci_path); |
||
1012 | |||
1013 | // Return the file data if requested |
||
1014 | if ($_ci_return === TRUE) |
||
1015 | { |
||
1016 | $buffer = ob_get_contents(); |
||
1017 | @ob_end_clean(); |
||
1018 | return $buffer; |
||
1019 | } |
||
1020 | |||
1021 | /* |
||
1022 | * Flush the buffer... or buff the flusher? |
||
1023 | * |
||
1024 | * In order to permit views to be nested within |
||
1025 | * other views, we need to flush the content back out whenever |
||
1026 | * we are beyond the first level of output buffering so that |
||
1027 | * it can be seen and included properly by the first included |
||
1028 | * template and any subsequent ones. Oy! |
||
1029 | */ |
||
1030 | if (ob_get_level() > $this->_ci_ob_level + 1) |
||
1031 | { |
||
1032 | ob_end_flush(); |
||
1033 | } |
||
1034 | else |
||
1035 | { |
||
1036 | $_ci_CI->output->append_output(ob_get_contents()); |
||
1037 | @ob_end_clean(); |
||
1038 | } |
||
1039 | |||
1040 | return $this; |
||
1041 | } |
||
1042 | |||
1043 | // -------------------------------------------------------------------- |
||
1044 | |||
1045 | /** |
||
1046 | * Internal CI Library Loader |
||
1047 | * |
||
1048 | * @used-by CI_Loader::library() |
||
1049 | * @uses CI_Loader::_ci_init_library() |
||
1050 | * |
||
1051 | * @param string $class Class name to load |
||
1052 | * @param mixed $params Optional parameters to pass to the class constructor |
||
1053 | * @param string $object_name Optional object name to assign to |
||
1054 | * @return void |
||
1055 | * |
||
1056 | * modified by ci-phpunit-test |
||
1057 | */ |
||
1058 | protected function _ci_load_library($class, $params = NULL, $object_name = NULL) |
||
1143 | |||
1144 | // -------------------------------------------------------------------- |
||
1145 | |||
1146 | /** |
||
1147 | * Internal CI Stock Library Loader |
||
1148 | * |
||
1149 | * @used-by CI_Loader::_ci_load_library() |
||
1150 | * @uses CI_Loader::_ci_init_library() |
||
1151 | * |
||
1152 | * @param string $library_name Library name to load |
||
1153 | * @param string $file_path Path to the library filename, relative to libraries/ |
||
1154 | * @param mixed $params Optional parameters to pass to the class constructor |
||
1155 | * @param string $object_name Optional object name to assign to |
||
1156 | * @return void |
||
1157 | * |
||
1158 | * modified by ci-phpunit-test |
||
1159 | */ |
||
1160 | protected function _ci_load_stock_library($library_name, $file_path, $params, $object_name) |
||
1240 | |||
1241 | // -------------------------------------------------------------------- |
||
1242 | |||
1243 | /** |
||
1244 | * Internal CI Library Instantiator |
||
1245 | * |
||
1246 | * @used-by CI_Loader::_ci_load_stock_library() |
||
1247 | * @used-by CI_Loader::_ci_load_library() |
||
1248 | * |
||
1249 | * @param string $class Class name |
||
1250 | * @param string $prefix Class name prefix |
||
1251 | * @param array|null|bool $config Optional configuration to pass to the class constructor: |
||
1252 | * FALSE to skip; |
||
1253 | * NULL to search in config paths; |
||
1254 | * array containing configuration data |
||
1255 | * @param string $object_name Optional object name to assign to |
||
1256 | * @return void |
||
1257 | * |
||
1258 | * @codeCoverageIgnore |
||
1259 | */ |
||
1260 | protected function _ci_init_library($class, $prefix, $config = FALSE, $object_name = NULL) |
||
1261 | { |
||
1262 | // Is there an associated config file for this class? Note: these should always be lowercase |
||
1263 | if ($config === NULL) |
||
1349 | |||
1350 | // -------------------------------------------------------------------- |
||
1351 | |||
1352 | /** |
||
1353 | * CI Autoloader |
||
1354 | * |
||
1355 | * Loads component listed in the config/autoload.php file. |
||
1356 | * |
||
1357 | * @used-by CI_Loader::initialize() |
||
1358 | * @return void |
||
1359 | * |
||
1360 | * @codeCoverageIgnore |
||
1361 | */ |
||
1362 | protected function _ci_autoloader() |
||
1432 | |||
1433 | // -------------------------------------------------------------------- |
||
1434 | |||
1435 | /** |
||
1436 | * Prepare variables for _ci_vars, to be later extract()-ed inside views |
||
1437 | * |
||
1438 | * Converts objects to associative arrays and filters-out internal |
||
1439 | * variable names (i.e. keys prefixed with '_ci_'). |
||
1440 | * |
||
1441 | * @param mixed $vars |
||
1442 | * @return array |
||
1443 | * |
||
1444 | * @codeCoverageIgnore |
||
1445 | */ |
||
1446 | protected function _ci_prepare_view_vars($vars) |
||
1465 | |||
1466 | // -------------------------------------------------------------------- |
||
1467 | |||
1468 | /** |
||
1469 | * CI Component getter |
||
1470 | * |
||
1471 | * Get a reference to a specific library or model. |
||
1472 | * |
||
1473 | * @param string $component Component name |
||
1474 | * @return bool |
||
1475 | * |
||
1476 | * @codeCoverageIgnore |
||
1477 | */ |
||
1478 | protected function &_ci_get_component($component) |
||
1483 | |||
1484 | } |
||
1485 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.