2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 // +----------------------------------------------------------------------+
5 // | Akelos Framework - http://www.akelos.org |
6 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez |
8 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
9 // +----------------------------------------------------------------------+
12 * @package ActiveRecord
14 * @author Bermi Ferrer <bermi a.t akelos c.om>
15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
19 require_once(AK_LIB_DIR
.DS
.'Ak.php');
20 require_once(AK_LIB_DIR
.DS
.'AkInflector.php');
21 require_once(AK_LIB_DIR
.DS
.'AkActiveRecord.php');
24 * Observer classes respond to life-cycle callbacks to implement trigger-like
25 * behavior outside the original class. This is a great way to reduce the clutter
26 * that normally comes when the model class is burdened with functionality that
27 * doesn't pertain to the core responsibility of the class.
31 * class CommentObserver extends AkObserver
33 * function afterSave($comment)
35 * Ak::mail("admin@example.com", "New comment was posted",
36 * $comment->toString());
40 * This Observer sends an email when a Comment::save is finished.
42 * ## Observing a class that can't be inferred
44 * Observers will by default be mapped to the class with which they share a name.
45 * So CommentObserver will be tied to observing Comment, ProductManagerObserver
46 * to ProductManager, and so on. If you want to name your observer differently
47 * than the class you're interested in observing, you can use the
48 * AkActiveRecord->observe() class method:
50 * function afterUpdate(&$account)
52 * $AuditTrail =& new AuditTrail($account, "UPDATED");
53 * $AuditTrail->save();
56 * If the audit observer needs to watch more than one kind of object, this can be
57 * specified with multiple arguments:
59 * function afterUpdate(&$record)
61 * $ObservedRecord =& new AuditTrail($record, "UPDATED");
62 * $ObservedRecord->save();
65 * The AuditObserver will now act on both updates to Account and Balance by
66 * treating them both as records.
68 * ## Available callback methods
70 * The observer can implement callback methods for each of these methods:
71 * beforeCreate, beforeValidation, beforeValidationOnCreate, beforeSave,
72 * afterValidation, afterValidationOnCreate, afterCreate and afterSave
74 * ## Triggering Observers
76 * In order to activate an observer, you need to call create an Observer instance
77 * and attach it to a model.
79 * In the Akelos Framework, this can be done in controllers using the short-hand
82 * $ComentObserverInstance =& new CommentObserver();
83 * $Model->addObserver(&$ComentObserverInstance);
86 class AkObserver
extends AkObject
89 * $_observing array of models that we're observing
91 var $_observing = array();
93 function __construct()
95 $num_args = func_num_args();
96 for ($i = 0; $i < $num_args; $i++
){
97 $target = func_get_arg($i);
98 if(is_object($target)){
99 $this->observe(&$target);
101 $this->setObservedModels($target);
107 * Constructs the Observer
108 * @param $subject the name or names of the Models to observe
110 function observe (&$target)
113 $model_name = $target->getModelName();
114 $class_name = get_class($this);
115 if(empty($memo[$class_name]) ||
!in_array($model_name, $memo[$class_name])){
116 $memo[$class_name][] = $model_name;
117 $this->_observing
[] = $model_name;
118 $target->addObserver(&$this);
123 * Constructs the Observer
124 * @param $subject the name or names of the Models to observe
126 function setObservedModels ()
128 $args = func_get_args();
129 $models = func_num_args() == 1 ?
( is_array($args[0]) ?
$args[0] : array($args[0]) ) : $args;
131 foreach ($models as $class_name)
134 * @todo use Ak::import() instead.
136 $class_name = AkInflector
::camelize($class_name);
137 if (!class_exists($class_name)){
138 require_once(AkInflector
::toModelFilename($class_name));
140 $model =& new $class_name();
141 $this->observe(&$model);
146 function update($state = '')