1: <?php
2: /**
3: * Model behaviors base class.
4: *
5: * Adds methods and automagic functionality to Cake Models.
6: *
7: * PHP 5
8: *
9: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
10: * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
11: *
12: * Licensed under The MIT License
13: * Redistributions of files must retain the above copyright notice.
14: *
15: * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
16: * @link http://cakephp.org CakePHP(tm) Project
17: * @package Cake.Model
18: * @since CakePHP(tm) v 1.2.0.0
19: * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
20: */
21:
22: /**
23: * Model behavior base class.
24: *
25: * Defines the Behavior interface, and contains common model interaction functionality. Behaviors
26: * allow you to simulate mixins, and create reusable blocks of application logic, that can be reused across
27: * several models. Behaviors also provide a way to hook into model callbacks and augment their behavior.
28: *
29: * ### Mixin methods
30: *
31: * Behaviors can provide mixin like features by declaring public methods. These methods should expect
32: * the model instance to be shifted onto the parameter list.
33: *
34: * {{{
35: * function doSomething(Model $model, $arg1, $arg2) {
36: * //do something
37: * }
38: * }}}
39: *
40: * Would be called like `$this->Model->doSomething($arg1, $arg2);`.
41: *
42: * ### Mapped methods
43: *
44: * Behaviors can also define mapped methods. Mapped methods use pattern matching for method invocation. This
45: * allows you to create methods similar to Model::findAllByXXX methods on your behaviors. Mapped methods need to
46: * be declared in your behaviors `$mapMethods` array. The method signature for a mapped method is slightly different
47: * than a normal behavior mixin method.
48: *
49: * {{{
50: * public $mapMethods = array('/do(\w+)/' => 'doSomething');
51: *
52: * function doSomething(Model $model, $method, $arg1, $arg2) {
53: * //do something
54: * }
55: * }}}
56: *
57: * The above will map every doXXX() method call to the behavior. As you can see, the model is
58: * still the first parameter, but the called method name will be the 2nd parameter. This allows
59: * you to munge the method name for additional information, much like Model::findAllByXX.
60: *
61: * @package Cake.Model
62: * @see Model::$actsAs
63: * @see BehaviorCollection::load()
64: */
65: class ModelBehavior extends Object {
66:
67: /**
68: * Contains configuration settings for use with individual model objects. This
69: * is used because if multiple models use this Behavior, each will use the same
70: * object instance. Individual model settings should be stored as an
71: * associative array, keyed off of the model name.
72: *
73: * @var array
74: * @see Model::$alias
75: */
76: public $settings = array();
77:
78: /**
79: * Allows the mapping of preg-compatible regular expressions to public or
80: * private methods in this class, where the array key is a /-delimited regular
81: * expression, and the value is a class method. Similar to the functionality of
82: * the findBy* / findAllBy* magic methods.
83: *
84: * @var array
85: */
86: public $mapMethods = array();
87:
88: /**
89: * Setup this behavior with the specified configuration settings.
90: *
91: * @param Model $model Model using this behavior
92: * @param array $config Configuration settings for $model
93: * @return void
94: */
95: public function setup(Model $model, $config = array()) {
96: }
97:
98: /**
99: * Clean up any initialization this behavior has done on a model. Called when a behavior is dynamically
100: * detached from a model using Model::detach().
101: *
102: * @param Model $model Model using this behavior
103: * @return void
104: * @see BehaviorCollection::detach()
105: */
106: public function cleanup(Model $model) {
107: if (isset($this->settings[$model->alias])) {
108: unset($this->settings[$model->alias]);
109: }
110: }
111:
112: /**
113: * beforeFind can be used to cancel find operations, or modify the query that will be executed.
114: * By returning null/false you can abort a find. By returning an array you can modify/replace the query
115: * that is going to be run.
116: *
117: * @param Model $model Model using this behavior
118: * @param array $query Data used to execute this query, i.e. conditions, order, etc.
119: * @return boolean|array False or null will abort the operation. You can return an array to replace the
120: * $query that will be eventually run.
121: */
122: public function beforeFind(Model $model, $query) {
123: return true;
124: }
125:
126: /**
127: * After find callback. Can be used to modify any results returned by find.
128: *
129: * @param Model $model Model using this behavior
130: * @param mixed $results The results of the find operation
131: * @param boolean $primary Whether this model is being queried directly (vs. being queried as an association)
132: * @return mixed An array value will replace the value of $results - any other value will be ignored.
133: */
134: public function afterFind(Model $model, $results, $primary) {
135: }
136:
137: /**
138: * beforeValidate is called before a model is validated, you can use this callback to
139: * add behavior validation rules into a models validate array. Returning false
140: * will allow you to make the validation fail.
141: *
142: * @param Model $model Model using this behavior
143: * @return mixed False or null will abort the operation. Any other result will continue.
144: */
145: public function beforeValidate(Model $model) {
146: return true;
147: }
148:
149: /**
150: * beforeSave is called before a model is saved. Returning false from a beforeSave callback
151: * will abort the save operation.
152: *
153: * @param Model $model Model using this behavior
154: * @return mixed False if the operation should abort. Any other result will continue.
155: */
156: public function beforeSave(Model $model) {
157: return true;
158: }
159:
160: /**
161: * afterSave is called after a model is saved.
162: *
163: * @param Model $model Model using this behavior
164: * @param boolean $created True if this save created a new record
165: * @return boolean
166: */
167: public function afterSave(Model $model, $created) {
168: return true;
169: }
170:
171: /**
172: * Before delete is called before any delete occurs on the attached model, but after the model's
173: * beforeDelete is called. Returning false from a beforeDelete will abort the delete.
174: *
175: * @param Model $model Model using this behavior
176: * @param boolean $cascade If true records that depend on this record will also be deleted
177: * @return mixed False if the operation should abort. Any other result will continue.
178: */
179: public function beforeDelete(Model $model, $cascade = true) {
180: return true;
181: }
182:
183: /**
184: * After delete is called after any delete occurs on the attached model.
185: *
186: * @param Model $model Model using this behavior
187: * @return void
188: */
189: public function afterDelete(Model $model) {
190: }
191:
192: /**
193: * DataSource error callback
194: *
195: * @param Model $model Model using this behavior
196: * @param string $error Error generated in DataSource
197: * @return void
198: */
199: public function onError(Model $model, $error) {
200: }
201:
202: /**
203: * If $model's whitelist property is non-empty, $field will be added to it.
204: * Note: this method should *only* be used in beforeValidate or beforeSave to ensure
205: * that it only modifies the whitelist for the current save operation. Also make sure
206: * you explicitly set the value of the field which you are allowing.
207: *
208: * @param Model $model Model using this behavior
209: * @param string $field Field to be added to $model's whitelist
210: * @return void
211: */
212: protected function _addToWhitelist(Model $model, $field) {
213: if (is_array($field)) {
214: foreach ($field as $f) {
215: $this->_addToWhitelist($model, $f);
216: }
217: return;
218: }
219: if (!empty($model->whitelist) && !in_array($field, $model->whitelist)) {
220: $model->whitelist[] = $field;
221: }
222: }
223:
224: }
225:
226: