1: <?php
2: /**
3: *
4: * PHP versions 4 and 5
5: *
6: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
7: * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
8: *
9: * Licensed under The MIT License
10: * Redistributions of files must retain the above copyright notice.
11: *
12: * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
13: * @link http://cakephp.org CakePHP(tm) Project
14: * @package cake
15: * @subpackage cake.cake.libs.controller
16: * @since CakePHP(tm) v TBD
17: * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
18: */
19:
20: /**
21: * Handler for Controller::$components
22: *
23: * @package cake
24: * @subpackage cake.cake.libs.controller
25: * @link http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Components.html
26: */
27: class Component extends Object {
28:
29: /**
30: * Contains various controller variable information (plugin, name, base).
31: *
32: * @var object
33: * @access private
34: */
35: var $__controllerVars = array('plugin' => null, 'name' => null, 'base' => null);
36:
37: /**
38: * List of loaded components.
39: *
40: * @var object
41: * @access protected
42: */
43: var $_loaded = array();
44:
45: /**
46: * List of components attached directly to the controller, which callbacks
47: * should be executed on.
48: *
49: * @var object
50: * @access protected
51: */
52: var $_primary = array();
53:
54: /**
55: * Settings for loaded components.
56: *
57: * @var array
58: * @access private
59: */
60: var $__settings = array();
61:
62: /**
63: * Used to initialize the components for current controller.
64: *
65: * @param object $controller Controller with components to load
66: * @return void
67: * @access public
68: */
69: function init(&$controller) {
70: if (!is_array($controller->components)) {
71: return;
72: }
73: $this->__controllerVars = array(
74: 'plugin' => $controller->plugin, 'name' => $controller->name,
75: 'base' => $controller->base
76: );
77:
78: $this->_loadComponents($controller);
79: }
80:
81: /**
82: * Called before the Controller::beforeFilter().
83: *
84: * @param object $controller Controller with components to initialize
85: * @return void
86: * @access public
87: * @link http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Components.html#mvc-class-access-within-components
88: */
89: function initialize(&$controller) {
90: foreach (array_keys($this->_loaded) as $name) {
91: $component =& $this->_loaded[$name];
92:
93: if (method_exists($component,'initialize') && $component->enabled === true) {
94: $settings = array();
95: if (isset($this->__settings[$name])) {
96: $settings = $this->__settings[$name];
97: }
98: $component->initialize($controller, $settings);
99: }
100: }
101: }
102:
103: /**
104: * Called after the Controller::beforeFilter() and before the controller action
105: *
106: * @param object $controller Controller with components to startup
107: * @return void
108: * @access public
109: * @link http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Components.html#mvc-class-access-within-components
110: * @deprecated See Component::triggerCallback()
111: */
112: function startup(&$controller) {
113: $this->triggerCallback('startup', $controller);
114: }
115:
116: /**
117: * Called after the Controller::beforeRender(), after the view class is loaded, and before the
118: * Controller::render()
119: *
120: * @param object $controller Controller with components to beforeRender
121: * @return void
122: * @access public
123: * @deprecated See Component::triggerCallback()
124: */
125: function beforeRender(&$controller) {
126: $this->triggerCallback('beforeRender', $controller);
127: }
128:
129: /**
130: * Called before Controller::redirect().
131: *
132: * @param object $controller Controller with components to beforeRedirect
133: * @return void
134: * @access public
135: */
136: function beforeRedirect(&$controller, $url, $status = null, $exit = true) {
137: $response = array();
138:
139: foreach ($this->_primary as $name) {
140: $component =& $this->_loaded[$name];
141:
142: if ($component->enabled === true && method_exists($component, 'beforeRedirect')) {
143: $resp = $component->beforeRedirect($controller, $url, $status, $exit);
144: if ($resp === false) {
145: return false;
146: }
147: $response[] = $resp;
148: }
149: }
150: return $response;
151: }
152:
153: /**
154: * Called after Controller::render() and before the output is printed to the browser.
155: *
156: * @param object $controller Controller with components to shutdown
157: * @return void
158: * @access public
159: * @deprecated See Component::triggerCallback()
160: */
161: function shutdown(&$controller) {
162: $this->triggerCallback('shutdown', $controller);
163: }
164:
165: /**
166: * Trigger a callback on all primary components. Will fire $callback on all components
167: * that have such a method. You can implement and fire custom callbacks in addition to the
168: * standard ones.
169: *
170: * example use, from inside a controller:
171: *
172: * `$this->Component->triggerCallback('beforeFilter', $this);`
173: *
174: * will trigger the beforeFilter callback on all components that have implemented one. You
175: * can trigger any method in this fashion.
176: *
177: * @param Controller $controller Controller instance
178: * @param string $callback Callback to trigger.
179: * @return void
180: * @access public
181: */
182: function triggerCallback($callback, &$controller) {
183: foreach ($this->_primary as $name) {
184: $component =& $this->_loaded[$name];
185: if (method_exists($component, $callback) && $component->enabled === true) {
186: $component->{$callback}($controller);
187: }
188: }
189: }
190:
191: /**
192: * Loads components used by this component.
193: *
194: * @param object $object Object with a Components array
195: * @param object $parent the parent of the current object
196: * @return void
197: * @access protected
198: */
199: function _loadComponents(&$object, $parent = null) {
200: $base = $this->__controllerVars['base'];
201: $normal = Set::normalize($object->components);
202: foreach ((array)$normal as $component => $config) {
203: $plugin = isset($this->__controllerVars['plugin']) ? $this->__controllerVars['plugin'] . '.' : null;
204: list($plugin, $component) = pluginSplit($component, true, $plugin);
205: $componentCn = $component . 'Component';
206:
207: if (!class_exists($componentCn)) {
208: if (is_null($plugin) || !App::import('Component', $plugin . $component)) {
209: if (!App::import('Component', $component)) {
210: $this->cakeError('missingComponentFile', array(array(
211: 'className' => $this->__controllerVars['name'],
212: 'component' => $component,
213: 'file' => Inflector::underscore($component) . '.php',
214: 'base' => $base,
215: 'code' => 500
216: )));
217: return false;
218: }
219: }
220:
221: if (!class_exists($componentCn)) {
222: $this->cakeError('missingComponentClass', array(array(
223: 'className' => $this->__controllerVars['name'],
224: 'component' => $component,
225: 'file' => Inflector::underscore($component) . '.php',
226: 'base' => $base,
227: 'code' => 500
228: )));
229: return false;
230: }
231: }
232:
233: if ($parent === null) {
234: $this->_primary[] = $component;
235: }
236:
237: if (isset($this->_loaded[$component])) {
238: $object->{$component} =& $this->_loaded[$component];
239:
240: if (!empty($config) && isset($this->__settings[$component])) {
241: $this->__settings[$component] = array_merge($this->__settings[$component], $config);
242: } elseif (!empty($config)) {
243: $this->__settings[$component] = $config;
244: }
245: } else {
246: if ($componentCn === 'SessionComponent') {
247: $object->{$component} =& new $componentCn($base);
248: } else {
249: if (PHP5) {
250: $object->{$component} = new $componentCn();
251: } else {
252: $object->{$component} =& new $componentCn();
253: }
254: }
255: $object->{$component}->enabled = true;
256: $this->_loaded[$component] =& $object->{$component};
257: if (!empty($config)) {
258: $this->__settings[$component] = $config;
259: }
260:
261: if (isset($object->{$component}->components) && is_array($object->{$component}->components) && (!isset($object->{$component}->{$parent}))) {
262: $this->_loadComponents($object->{$component}, $component);
263: }
264: }
265: }
266: }
267: }
268: