/**
  * @throws Exception
  */
 public function beforeUpdate()
 {
     if ($this->node !== null && !$this->node->getIsNewRecord()) {
         $this->node->refresh();
     }
     switch ($this->operation) {
         case self::OPERATION_MAKE_ROOT:
             if ($this->treeAttribute === false) {
                 throw new Exception('Can not move a node as the root when "treeAttribute" is false.');
             }
             if ($this->owner->isRoot()) {
                 throw new Exception('Can not move the root node as the root.');
             }
             break;
         case self::OPERATION_INSERT_BEFORE:
         case self::OPERATION_INSERT_AFTER:
             if ($this->node->isRoot()) {
                 throw new Exception('Can not move a node when the target node is root.');
             }
         case self::OPERATION_PREPEND_TO:
         case self::OPERATION_APPEND_TO:
             if ($this->node->getIsNewRecord()) {
                 throw new Exception('Can not move a node when the target node is new record.');
             }
             if ($this->owner->equals($this->node)) {
                 throw new Exception('Can not move a node when the target node is same.');
             }
             if ($this->node->isChildOf($this->owner)) {
                 throw new Exception('Can not move a node when the target node is child.');
             }
     }
 }
Beispiel #2
0
 /**
  * @inheritdoc
  * @param ActiveRecord $owner
  */
 public function attach($owner)
 {
     $this->attribute = (array) $this->attribute;
     $primaryKey = $owner->primaryKey();
     $primaryKey = is_array($primaryKey) ? array_shift($primaryKey) : $primaryKey;
     if (in_array($primaryKey, $this->attribute, true) && $owner->getIsNewRecord()) {
         $this->attributes[ActiveRecord::EVENT_AFTER_INSERT] = $this->slugAttribute;
     }
     parent::attach($owner);
 }
 /**
  * @param bool $forInsertNear
  * @throws Exception
  */
 protected function checkNode($forInsertNear = false)
 {
     if ($forInsertNear && $this->node->isRoot()) {
         throw new Exception('Can not move a node before/after root.');
     }
     if ($this->node->getIsNewRecord()) {
         throw new Exception('Can not move a node when the target node is new record.');
     }
     if ($this->owner->equals($this->node)) {
         throw new Exception('Can not move a node when the target node is same.');
     }
     if ($this->checkLoop && $this->node->isChildOf($this->owner)) {
         throw new Exception('Can not move a node when the target node is child.');
     }
 }
 /**
  * @param int $to
  * @param int $depth
  * @throws Exception
  */
 protected function insertNode($to, $depth = 0)
 {
     if ($this->node->getIsNewRecord()) {
         throw new Exception('Can not create a node when the target node is new record.');
     }
     if ($depth === 0 && $this->node->isRoot()) {
         throw new Exception('Can not insert a node before/after root.');
     }
     $this->owner->setAttribute($this->leftAttribute, $to);
     $this->owner->setAttribute($this->rightAttribute, $to + 1);
     $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute) + $depth);
     if ($this->treeAttribute !== null) {
         $this->owner->setAttribute($this->treeAttribute, $this->node->getAttribute($this->treeAttribute));
     }
     $this->shift($to, null, 2);
 }
 /**
  * @throws Exception
  */
 public function beforeUpdate()
 {
     if ($this->node !== null && !$this->node->getIsNewRecord()) {
         $this->node->refresh();
     }
     switch ($this->operation) {
         case self::OPERATION_MAKE_ROOT:
             if ($this->treeAttribute === false) {
                 throw new Exception('Can not move a node as the root when "treeAttribute" is false.');
             }
             if ($this->owner->isRoot()) {
                 throw new Exception('Can not move the root node as the root.');
             }
             if (!$this->treeAttributeById) {
                 if ($this->owner->getOldAttribute($this->treeAttribute) === $this->owner->getAttribute($this->treeAttribute)) {
                     throw new Exception('Can not move a node as the root when its tree attribute "' . $this->treeAttribute . '" is not changed.');
                 }
                 if ($this->owner->find()->andWhere([$this->treeAttribute => $this->owner->getAttribute($this->treeAttribute), $this->leftAttribute => 1])->one()) {
                     throw new Exception('Can not move a node as the root when another root with this "' . $this->treeAttribute . '" already exists.');
                 }
             }
             break;
         case self::OPERATION_INSERT_BEFORE:
         case self::OPERATION_INSERT_AFTER:
             if ($this->node->isRoot()) {
                 throw new Exception('Can not move a node when the target node is root.');
             }
         case self::OPERATION_PREPEND_TO:
         case self::OPERATION_APPEND_TO:
             if ($this->node->getIsNewRecord()) {
                 throw new Exception('Can not move a node when the target node is new record.');
             }
             if ($this->owner->equals($this->node)) {
                 throw new Exception('Can not move a node when the target node is same.');
             }
             if ($this->node->isChildOf($this->owner)) {
                 throw new Exception('Can not move a node when the target node is child.');
             }
     }
 }
Beispiel #6
0
 /**
  * Find all SEO data.
  * Result will be in format ['condition1'=>Seo(), 'condition2'=>Seo(), ...]
  * @param ActiveRecord $owner the model for which to find data
  * @return self[]
  */
 public static function findAll(ActiveRecord $owner)
 {
     /** @var self[] $seoList */
     $seoList = [];
     if ($owner->getIsNewRecord()) {
         return $seoList;
     }
     $query = (new Query())->from(Seo::tableName($owner))->andWhere(['model_id' => $owner->getPrimaryKey()]);
     foreach ($query->all($owner->getDb()) as $seo) {
         $seo = new Seo($seo);
         $seo->_isNewRecord = false;
         $seo->_owner = $owner;
         $seoList[$seo['condition']] = $seo;
     }
     return $seoList;
 }
 /**
  * Establishes the relationship between two models.
  *
  * The relationship is established by setting the foreign key value(s) in one model
  * to be the corresponding primary key value(s) in the other model.
  * The model with the foreign key will be saved into database without performing validation.
  *
  * If the relationship involves a pivot table, a new row will be inserted into the
  * pivot table which contains the primary key values from both models.
  *
  * Note that this method requires that the primary key value is not null.
  *
  * @param string $name the case sensitive name of the relationship
  * @param ActiveRecord $model the model to be linked with the current one.
  * @param array $extraColumns additional column values to be saved into the pivot table.
  * This parameter is only meaningful for a relationship involving a pivot table
  * (i.e., a relation set with `[[ActiveRelation::via()]]` or `[[ActiveRelation::viaTable()]]`.)
  * @throws InvalidCallException if the method is unable to link two models.
  */
 public function link($name, $model, $extraColumns = [])
 {
     $relation = $this->getRelation($name);
     if ($relation->via !== null) {
         if ($this->getIsNewRecord() || $model->getIsNewRecord()) {
             throw new InvalidCallException('Unable to link models: both models must NOT be newly created.');
         }
         if (is_array($relation->via)) {
             /** @var ActiveRelation $viaRelation */
             list($viaName, $viaRelation) = $relation->via;
             $viaClass = $viaRelation->modelClass;
             // unset $viaName so that it can be reloaded to reflect the change
             unset($this->_related[$viaName]);
         } else {
             $viaRelation = $relation->via;
             $viaTable = reset($relation->via->from);
         }
         $columns = [];
         foreach ($viaRelation->link as $a => $b) {
             $columns[$a] = $this->{$b};
         }
         foreach ($relation->link as $a => $b) {
             $columns[$b] = $model->{$a};
         }
         foreach ($extraColumns as $k => $v) {
             $columns[$k] = $v;
         }
         if (is_array($relation->via)) {
             /** @var $viaClass ActiveRecord */
             /** @var $record ActiveRecord */
             $record = new $viaClass();
             foreach ($columns as $column => $value) {
                 $record->{$column} = $value;
             }
             $record->insert(false);
         } else {
             /** @var $viaTable string */
             static::getDb()->createCommand()->insert($viaTable, $columns)->execute();
         }
     } else {
         $p1 = $model->isPrimaryKey(array_keys($relation->link));
         $p2 = $this->isPrimaryKey(array_values($relation->link));
         if ($p1 && $p2) {
             if ($this->getIsNewRecord() && $model->getIsNewRecord()) {
                 throw new InvalidCallException('Unable to link models: both models are newly created.');
             } elseif ($this->getIsNewRecord()) {
                 $this->bindModels(array_flip($relation->link), $this, $model);
             } else {
                 $this->bindModels($relation->link, $model, $this);
             }
         } elseif ($p1) {
             $this->bindModels(array_flip($relation->link), $this, $model);
         } elseif ($p2) {
             $this->bindModels($relation->link, $model, $this);
         } else {
             throw new InvalidCallException('Unable to link models: the link does not involve any primary key.');
         }
     }
     // update lazily loaded related objects
     if (!$relation->multiple) {
         $this->_related[$name] = $model;
     } elseif (isset($this->_related[$name])) {
         if ($relation->indexBy !== null) {
             $indexBy = $relation->indexBy;
             $this->_related[$name][$model->{$indexBy}] = $model;
         } else {
             $this->_related[$name][] = $model;
         }
     }
 }
 /**
  * @param int $left
  * @param int $right
  * @param int $depth
  * @param bool $forward
  * @param array|null $parent
  * @throws Exception
  */
 protected function insertNode($left, $right, $depth = 0, $forward = true, $parent = null)
 {
     if ($this->node->getIsNewRecord()) {
         throw new Exception('Can not create a node when the target node is new record.');
     }
     if ($depth === 0 && $this->getNodeBehavior()->isRoot()) {
         throw new Exception('Can not insert a node before/after root.');
     }
     $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute) + $depth);
     if ($this->treeAttribute !== null) {
         $this->owner->setAttribute($this->treeAttribute, $this->node->getAttribute($this->treeAttribute));
     }
     if ($right - $left < 3) {
         for ($i = $right - $left; $i < 3; $i++) {
             $unallocated = $this->findUnallocatedAll($left, $right);
             if ($unallocated < $left) {
                 $this->shift($unallocated, $left, -1);
                 $left--;
             } else {
                 $this->shift($right, $unallocated, 1);
                 $right++;
             }
         }
         $this->owner->setAttribute($this->leftAttribute, $left + 1);
         $this->owner->setAttribute($this->rightAttribute, $right - 1);
     } else {
         $left++;
         $right--;
         $isPadding = false;
         if ($depth === 1 || $parent !== null) {
             // prepending/appending
             if (is_array($this->amountOptimize)) {
                 if (isset($this->amountOptimize[$depth - 1])) {
                     $amountOptimize = $this->amountOptimize[$depth - 1];
                 } else {
                     $amountOptimize = $this->amountOptimize[count($this->amountOptimize) - 1];
                 }
             } else {
                 $amountOptimize = $this->amountOptimize;
             }
             $pLeft = $parent !== null ? (int) $parent[$this->leftAttribute] : $this->node->getAttribute($this->leftAttribute);
             $pRight = $parent !== null ? (int) $parent[$this->rightAttribute] : $this->node->getAttribute($this->rightAttribute);
             $isCenter = !$this->noAppend && !$this->noPrepend;
             $isFirst = $left === $pLeft + 1 && $right === $pRight - 1;
             $isPadding = !$this->noInsert || $isFirst && ($forward ? !$this->noPrepend : !$this->noAppend);
             $step = $amountOptimize + $this->reserveFactor * ($this->noInsert ? $isCenter ? 2 : 1 : $amountOptimize + 1);
             $step = ($pRight - $pLeft - 1) / $step;
             $stepGap = $step * $this->reserveFactor;
             $padding = $isPadding ? $stepGap : 0;
             if ($forward) {
                 $pLeft = $left + (int) floor($padding);
                 $pRight = $left + (int) floor($padding + $step) - 1;
             } else {
                 $pLeft = $right - (int) floor($padding + $step) + 1;
                 $pRight = $right - (int) floor($padding);
             }
             if ($isFirst && $isCenter) {
                 $initPosition = (int) floor(($amountOptimize - 1) / 2) * (int) floor($step + ($this->noInsert ? 0 : $stepGap)) + ($this->noInsert ? 1 : 0);
                 $pLeft += $forward ? $initPosition : -$initPosition;
                 $pRight += $forward ? $initPosition : -$initPosition;
             }
             if ($pLeft < $pRight && $pRight <= $right && $left <= $pLeft && ($forward || $left < $pLeft) && (!$forward || $pRight < $right)) {
                 $this->owner->setAttribute($this->leftAttribute, $pLeft);
                 $this->owner->setAttribute($this->rightAttribute, $pRight);
                 return;
             }
         }
         $isPadding = $isPadding || !$this->noInsert;
         $step = (int) floor(($right - $left) / ($isPadding ? 3 : 2));
         $this->owner->setAttribute($this->leftAttribute, $left + ($forward && !$isPadding ? 0 : $step));
         $this->owner->setAttribute($this->rightAttribute, $right - (!$forward && !$isPadding ? 0 : $step));
     }
 }