1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
21:
22: App::uses('ObjectCollection', 'Utility');
23:
24: 25: 26: 27: 28: 29: 30:
31: class BehaviorCollection extends ObjectCollection {
32:
33: 34: 35: 36: 37:
38: public $modelName = null;
39:
40: 41: 42: 43: 44:
45: protected $_methods = array();
46:
47: 48: 49: 50: 51:
52: protected $_mappedMethods = array();
53:
54: 55: 56: 57: 58: 59: 60: 61:
62: public function init($modelName, $behaviors = array()) {
63: $this->modelName = $modelName;
64:
65: if (!empty($behaviors)) {
66: foreach (BehaviorCollection::normalizeObjectArray($behaviors) as $behavior => $config) {
67: $this->load($config['class'], $config['settings']);
68: }
69: }
70: }
71:
72: 73: 74: 75: 76: 77: 78: 79:
80: public function attach($behavior, $config = array()) {
81: return $this->load($behavior, $config);
82: }
83:
84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103:
104: public function load($behavior, $config = array()) {
105: if (is_array($config) && isset($config['className'])) {
106: $alias = $behavior;
107: $behavior = $config['className'];
108: }
109: $configDisabled = isset($config['enabled']) && $config['enabled'] === false;
110: unset($config['enabled'], $config['className']);
111:
112: list($plugin, $name) = pluginSplit($behavior, true);
113: if (!isset($alias)) {
114: $alias = $name;
115: }
116:
117: $class = $name . 'Behavior';
118:
119: App::uses($class, $plugin . 'Model/Behavior');
120: if (!class_exists($class)) {
121: throw new MissingBehaviorException(array(
122: 'class' => $class,
123: 'plugin' => substr($plugin, 0, -1)
124: ));
125: }
126:
127: if (!isset($this->{$alias})) {
128: if (ClassRegistry::isKeySet($class)) {
129: $this->_loaded[$alias] = ClassRegistry::getObject($class);
130: } else {
131: $this->_loaded[$alias] = new $class();
132: ClassRegistry::addObject($class, $this->_loaded[$alias]);
133: if (!empty($plugin)) {
134: ClassRegistry::addObject($plugin . '.' . $class, $this->_loaded[$alias]);
135: }
136: }
137: } elseif (isset($this->_loaded[$alias]->settings) && isset($this->_loaded[$alias]->settings[$this->modelName])) {
138: if ($config !== null && $config !== false) {
139: $config = array_merge($this->_loaded[$alias]->settings[$this->modelName], $config);
140: } else {
141: $config = array();
142: }
143: }
144: if (empty($config)) {
145: $config = array();
146: }
147: $this->_loaded[$alias]->setup(ClassRegistry::getObject($this->modelName), $config);
148:
149: foreach ($this->_loaded[$alias]->mapMethods as $method => $methodAlias) {
150: $this->_mappedMethods[$method] = array($alias, $methodAlias);
151: }
152: $methods = get_class_methods($this->_loaded[$alias]);
153: $parentMethods = array_flip(get_class_methods('ModelBehavior'));
154: $callbacks = array(
155: 'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave',
156: 'beforeDelete', 'afterDelete', 'onError'
157: );
158:
159: foreach ($methods as $m) {
160: if (!isset($parentMethods[$m])) {
161: $methodAllowed = (
162: $m[0] != '_' && !array_key_exists($m, $this->_methods) &&
163: !in_array($m, $callbacks)
164: );
165: if ($methodAllowed) {
166: $this->_methods[$m] = array($alias, $m);
167: }
168: }
169: }
170:
171: if (!in_array($alias, $this->_enabled) && !$configDisabled) {
172: $this->enable($alias);
173: } elseif ($configDisabled) {
174: $this->disable($alias);
175: }
176: return true;
177: }
178:
179: 180: 181: 182: 183: 184:
185: public function unload($name) {
186: list($plugin, $name) = pluginSplit($name);
187: if (isset($this->_loaded[$name])) {
188: $this->_loaded[$name]->cleanup(ClassRegistry::getObject($this->modelName));
189: unset($this->_loaded[$name]);
190: }
191: foreach ($this->_methods as $m => $callback) {
192: if (is_array($callback) && $callback[0] == $name) {
193: unset($this->_methods[$m]);
194: }
195: }
196: $this->_enabled = array_values(array_diff($this->_enabled, (array)$name));
197: }
198:
199: 200: 201: 202: 203: 204: 205:
206: public function detach($name) {
207: return $this->unload($name);
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221:
222: public function dispatchMethod($model, $method, $params = array(), $strict = false) {
223: $method = $this->hasMethod($method, true);
224:
225: if ($strict && empty($method)) {
226: trigger_error(__d('cake_dev', "BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior", $method), E_USER_WARNING);
227: return null;
228: }
229: if (empty($method)) {
230: return array('unhandled');
231: }
232: if (count($method) === 3) {
233: array_unshift($params, $method[2]);
234: unset($method[2]);
235: }
236: return call_user_func_array(
237: array($this->_loaded[$method[0]], $method[1]),
238: array_merge(array(&$model), $params)
239: );
240: }
241:
242: 243: 244: 245: 246: 247:
248: public function methods() {
249: return $this->_methods;
250: }
251:
252: 253: 254: 255: 256: 257: 258: 259: 260:
261: public function hasMethod($method, $callback = false) {
262: if (isset($this->_methods[$method])) {
263: return $callback ? $this->_methods[$method] : true;
264: }
265: foreach ($this->_mappedMethods as $pattern => $target) {
266: if (preg_match($pattern . 'i', $method)) {
267: if ($callback) {
268: $target[] = $method;
269: return $target;
270: }
271: return true;
272: }
273: }
274: return false;
275: }
276:
277: }
278: