/** * Method for validation of status change flow * * @param AppModel $Model * @param array $data * @return boolean * @access public */ public function validateStatus($Model, $data) { if ($Model->exists() && ($current = $Model->field('status'))) { return in_array($data['status'], $this->settings[$Model->alias]['status'][$current]); } return false; }
/** * Sets the parent of the given node * * The force parameter is used to override the "don't change the parent to the current parent" logic in the event * of recovering a corrupted table, or creating new nodes. Otherwise it should always be false. In reality this * method could be private, since calling save with parent_id set also calls setParent * * @since 1.2 * @param AppModel $model * @param mixed $parent_id * @param boolean $force process even if current parent_id is the same as the value to be saved * @return boolean True on success, false on failure * @access protected */ function _set_parent(&$model, $parent_id = null, $force = false) { extract($this->settings[$model->name]); if (!$force && $parent_id == $model->field($parent)) { return false; } list($node) = array_values($model->find(array($scope, $model->escapeField() => $model->id), array($model->primaryKey, $parent, $left, $right), null, -1)); $edge = $this->__get_max($model, $scope, $right); if (empty($parent_id)) { // No parent specified. Never executed for creations (handled in beforeSave) // First, move the node (and subnodes) to the end $this->__sync($model, $edge - $node[$left] + 1, '+', "BETWEEN {$node[$left]} AND {$node[$right]}", $scope); // Then move everything back so there is no gap $this->__sync($model, $node[$right] - $node[$left] + 1, '-', "> {$node[$left]}", $scope); } else { // A parent has been specified list($parentNode) = array_values($model->find(array($scope, $model->escapeField() => $parent_id), array($model->primaryKey, $left, $right), null, -1)); if (empty($parentNode)) { trigger_error(__('Trying to move a node under a none-existant node in ' . __METHOD__, true), E_USER_WARNING); return false; } elseif ($model->id == $parent_id) { trigger_error(__('Trying to set a node to be the parent of itself in ' . __METHOD__, E_USER_WARNING)); return false; } elseif ($node[$left] < $parentNode[$left] && $parentNode[$right] < $node[$right]) { trigger_error(__('Trying to move a node under itself in ' . __METHOD__, E_USER_WARNING)); return false; } if (empty($node[$left]) && empty($node[$right])) { // The node is not yet in the tree, only for creation with parent id $this->__sync($model, 2, '+', ">= {$parentNode[$right]}}", $scope); $model->save(array($left => $parentNode[$right], $right => $parentNode[$right] + 1, $parent => $parent_id), false); } else { // Moving an existing node to a new parent // First, move the node (and subnodes) to the end of the tree $this->__sync($model, $edge - $node[$left] + 1, '+', "BETWEEN {$node[$left]} AND {$node[$right]}", $scope); $diff = $node[$right] - $node[$left] + 1; if ($node[$left] > $parentNode[$left]) { // If the Node is sequencially after the parent .. if ($node[$right] < $parentNode[$right]) { // .. and it's a reshuffle (promotion/demotion) $this->__sync($model, $diff, '-', "BETWEEN {$node[$right]} AND " . ($parentNode[$right] - 1), $scope); $this->__sync($model, $edge - $parentNode[$right] + $diff + 1, '-', "> {$edge}", $scope); } else { // .. else the Node truely is sequencially after the parent // extend Parent to encompase the hole, and move the displaced node into the hole $this->__sync($model, $diff, '+', "BETWEEN {$parentNode[$right]} AND {$node[$right]}", $scope); $this->__sync($model, $edge - $parentNode[$right] + 1, '-', "> {$edge}", $scope); } } else { // .. the node is sequencially before the parent // move Parent back leaving a hole, and move the displaced node into the hole $this->__sync($model, $diff, '-', "BETWEEN {$node[$right]} AND " . ($parentNode[$right] - 1), $scope); $this->__sync($model, $edge - $parentNode[$right] + $diff + 1, '-', "> {$edge}", $scope); } } } return true; }
/** * Backward compatible method * * Returns true if the change is successful. * * @param AppModel $model * @param mixed $parentId The ID to set as the parent of the current node. * @return true on success * @access public */ function setparent(&$model, $parentId = null, $created = null) { extract($this->settings[$model->alias]); if ($created === false && $parentId == $model->field($parent)) { return true; } return $model->saveField($parent, $parentId); }
/** * Backward compatible method * * Returns true if the change is successful. * * @param AppModel $model * @param mixed $parentId The ID to set as the parent of the current node. * @return true on success * @access public * @deprecated */ function setparent(&$model, $parentId = null, $created = null) { trigger_error(__('(TreeBehavior::setParent) Deprecated - save the record with a parent ID instead', true), E_USER_ERROR); extract($this->settings[$model->alias]); if ($created === false && $parentId == $model->field($parent)) { return true; } return $model->saveField($parent, $parentId, array('callbacks' => false)); }
/** * If editing a record, set the oldGroups property to the current group values * in the database for each group field for this model. * * @param AppModel $model */ function setOldGroups(&$model) { // If no id, we're creating not editing, so there is no old groups if (!$model->id) { return; } // If this model does not have any groups, return if (!$this->groupFields) { return; } // Set oldGroups property with key of group field and current value of group // field from db foreach ($this->groupFields as $groupField) { $this->oldGroups[$groupField] = $model->field($model->alias . '.' . $groupField); } }
/** * Moves a node up or down the order of ndoes at a particular level, i.e. * affects the relative position of a node with respect to it's siblings. * * Used as a replacement for the SequenceBehavior for hierarchical models, * which the SequenceBehavior is not suitable for. * * @param AppModel $model The model object that the behavior is attached to * @param integer $id ID of the node to affect * @param integer $newOrder New position in the sequence * @return boolean * @access public */ function setOrder(&$model, $id, $newOrder) { // Validate id supplied if (!$id) { $this->errors[] = "Id not valid"; return false; } // Validate new order if (!is_numeric($newOrder)) { $this->errors[] = "New order must be numeric"; return false; } // Get parent id $model->recursive = -1; $parentId = $model->field($this->settings[$model->alias]['parent'], array($model->primaryKey => $id)); // Get all children of node's parent, i.e. it and siblings $siblings = $model->find('list', array('conditions' => array($this->settings[$model->alias]['parent'] => $parentId))); // Get sibling ids in a numerically indexed array, starting at 0 $siblingIds = array_keys($siblings); // Get the current order the node in question in the array of sibling ids $currentOrder = array_search($id, $siblingIds); // Get the difference between the new position and old position $difference = $newOrder - $currentOrder; // Get the number of places to move the node $places = abs($difference); // Move the node up or down (depending on the sign of the difference) by the // appropriate number of places if ($difference == 0) { return true; } elseif ($difference > 0) { return $this->movedown($model, $id, $places); } else { return $this->moveup($model, $id, $places); } }