/** * Map 'change' and 'get' methods. * * @param Model $Model Model using this behavior. * @param string $method Real method's name. * @return mixed For 'change' operations, returns TRUE on success and FALSE otherwise. For * 'get' operations, returns a boolean when a state is provided by comparing it to the * record's state field result, or returns the record's state field result. * @throws FatalErrorException If the state's field is not configured as such. * @see StateableBehaviorTest for examples of how arguments can be passed. */ public function __call(Model $Model, $method) { foreach (array('change', 'get') as $do) { $field = str_replace($do, '', $method); if ($field != $method) { $field = Inflector::underscore($field); break; } } if (!array_key_exists($field, $this->settings[$Model->alias]['fields'])) { throw new FatalErrorException(__d('common', "Missing state field configuration ('%s')", $field)); } $args = func_get_args(); $id = $Model->getID(); $state = isset($args[2]) ? $args[2] : null; $validate = isset($args[4]) ? $args[4] : true; if (isset($args[3])) { if (!is_bool($args[3])) { $id = $args[2]; $state = $args[3]; } else { $validate = $args[3]; } } else { if (empty($id) && (isset($args[2]) || 'get' == $do) && $Model->exists($state)) { $id = $state; $state = null; } } if (empty($id) || !$Model->exists($id)) { return false; } $current = $Model->field($field, array($Model->alias . '.' . $Model->primaryKey => $id)); if ('get' == $do) { if (!empty($state)) { return $state == $current; } return $current; } $Model->id = $id; $eventName = 'Model.' . $Model->name . '.'; $fieldName = Inflector::camelize($field); $Event = new CakeEvent($eventName . 'beforeChange' . $fieldName, $Model, compact('field', 'state', 'validate')); list($Event->break, $Event->breakOn) = array(true, false); $result = $Model->triggerEvent($Event); if (false === $result || !($ret = $state != $current && $Model->saveField($field, $state, $validate))) { return false; } $Model->triggerEvent($eventName . 'afterChange' . $fieldName, $Model); return true; }