diff --git a/src/Commands/RecalculatePositionCommand.php b/src/Commands/RecalculatePositionCommand.php index 7b47b0b..261eee2 100644 --- a/src/Commands/RecalculatePositionCommand.php +++ b/src/Commands/RecalculatePositionCommand.php @@ -64,9 +64,6 @@ public function handle() $modelClass::sorted()->chunk(200, function (Collection $collection) use ($groups, &$positionsByGroup) { /** @var PositionTrait|Model $model */ foreach ($collection as $model) { - // Prevent the move action and force the position we set - $model->setDisablePositionUpdateAttribute(true); - // Builds the group key to get position $groupKey = $this->buildGroupKeyForPosition($model, $groups); diff --git a/src/PositionObserver.php b/src/PositionObserver.php index e223290..ea4e9a5 100644 --- a/src/PositionObserver.php +++ b/src/PositionObserver.php @@ -1,9 +1,11 @@ appendLast($model, $oldPosition); + } else if (is_null($oldPosition)) { + $this->forcedPosition($model, $position); } else { $this->move($model, $position, $oldPosition); } } } + /** + * Forces the new position, will be overriden if it's out of maximum bounds. + * + * @param Model|PositionTrait $model + * @param int $position + * @param int|null $oldPosition + */ + protected function forcedPosition($model, $position, $oldPosition = null) + { + // Build the new position + $query = new PositionQuery($model, $position); + + // Run the query + $query->runQuery($query, $oldPosition); + } + /** * Setups the position to be at the end * @@ -83,7 +103,7 @@ protected function move($model, $position, $oldPosition) // Check if the position has change and we need to recalculate if ($oldPosition != $position) { // Build the position query - $query = new PositionQuery($model, $position, $oldPosition); + $query = new MoveQuery($model, $position, $oldPosition); // Run the position query $this->runQuery($query, $oldPosition); diff --git a/src/Query/LastPositionQuery.php b/src/Query/LastPositionQuery.php index 9009d31..f637ecb 100644 --- a/src/Query/LastPositionQuery.php +++ b/src/Query/LastPositionQuery.php @@ -15,7 +15,6 @@ */ class LastPositionQuery extends AbstractPositionQuery { - /** * Creates the base query and builds the query * diff --git a/src/Query/MoveQuery.php b/src/Query/MoveQuery.php new file mode 100644 index 0000000..8bb0cb8 --- /dev/null +++ b/src/Query/MoveQuery.php @@ -0,0 +1,119 @@ +'; + /** + * Comparision condition for new position value. + * In default is for decrement. + * @var string + */ + protected $newComparisionCondition = '<='; + + + /** + * PositionQuery constructor. + * + * @param Model|PositionTrait $model + * @param int $position + * @param int|null $oldPosition + */ + public function __construct($model, $position, $oldPosition) + { + parent::__construct($model, $oldPosition, false); + + $this->position = $position; + + // Indicate if si the increment/decrement + $this->increment = $position < $oldPosition; + + // Get the column for position to build correct query + $this->positionColumn = $model->getPositionColumn(); + + // Build the comparision condition + $this->buildComparisionCondition(); + + // Prepare the query + $this->query = $this->buildQuery(); + } + + //region Query + + /** + * Runs the increment/decrement query + * + * @param Builder $query + * + * @return int + */ + public function runQuery($query) + { + if ($this->increment) { + return $query->increment($this->positionColumn); + } else { + return $query->decrement($this->positionColumn); + } + } + + /** + * Builds the basic query with where condition (includes the position conditions) + * @return Builder + */ + protected function buildQuery() + { + // Create query + $query = parent::buildQuery(); + + // Build the where condition for the position. This will ensure to update only required rows + return $query->where($this->positionColumn, $this->oldComparisionCondition, $this->oldPosition) + ->where($this->positionColumn, $this->newComparisionCondition, $this->position); + } + + /** + * Builds the correct comparision condition + */ + protected function buildComparisionCondition() + { + if ($this->increment) { + $this->oldComparisionCondition = '<'; + $this->newComparisionCondition = '>='; + } + } + //endregion + + //region Getters + + /** + * @return mixed + */ + public function position() + { + return $this->position; + } + //endregion +} diff --git a/src/Query/PositionQuery.php b/src/Query/PositionQuery.php index 1da32cc..6b823b7 100644 --- a/src/Query/PositionQuery.php +++ b/src/Query/PositionQuery.php @@ -1,16 +1,14 @@ '; - /** - * Comparision condition for new position value. - * In default is for decrement. - * @var string + * When only the new model is updated, we don`t need to run query + * @var bool */ - protected $newComparisionCondition = '<='; - + protected $shouldRunQuery = false; /** - * PositionQuery constructor. + * Creates the base query and builds the query * * @param Model|PositionTrait $model - * @param int $position - * @param int $oldPosition */ - public function __construct($model, $position, $oldPosition) + public function __construct($model, $position) { - parent::__construct($model, $oldPosition, false); - + // Store the new position $this->position = $position; - // Indicate if si the increment/decrement - $this->increment = $position < $oldPosition; - - // Get the column for position to build correct query + // Get the position column $this->positionColumn = $model->getPositionColumn(); - // Build the comparision condition - $this->buildComparisionCondition(); - - // Prepare the query - $this->query = $this->buildQuery(); - } - - //region Query - - /** - * Runs the increment/decrement query - * - * @param Builder $query - * - * @return int - */ - public function runQuery($query) - { - if ($this->increment) { - return $query->increment($this->positionColumn); - } else { - return $query->decrement($this->positionColumn); - } + // Build the query + parent::__construct($model, null, true); } /** - * Builds the basic query with where condition (includes the position conditions) + * Builds the basic query and appends a where conditions for group is set * @return Builder */ protected function buildQuery() @@ -89,31 +47,41 @@ protected function buildQuery() // Create query $query = parent::buildQuery(); - // Build the where condition for the position. This will ensure to update only required rows - return $query->where($this->positionColumn, $this->oldComparisionCondition, $this->oldPosition) - ->where($this->positionColumn, $this->newComparisionCondition, $this->position); - } + // Get the last position and move the position + $lastPosition = $query->max($this->positionColumn); - /** - * Builds the correct comparision condition - */ - protected function buildComparisionCondition() - { - if ($this->increment) { - $this->oldComparisionCondition = '<'; - $this->newComparisionCondition = '>='; + // If the new position is last position, just update the position or if + // new position is out of bounds + if ($this->position >= $lastPosition) { + $this->model()->setPosition($lastPosition + 1); + } else { + $this->shouldRunQuery = true; + + // Set the forced position + $this->model()->setPosition($this->position); + + // Move other models + $query->where($this->positionColumn, '>=', $this->position); } + + return $query; } - //endregion - //region Getters /** - * @return mixed + * Runs the query for last position and sets the model position if the position has + * changed + * + * @param Builder $query + * + * @return int the last position returned */ - public function position() + public function runQuery($query) { - return $this->position; + if ($this->shouldRunQuery) { + return $query->increment($this->positionColumn); + } + + return $this->model()->getPosition(); } - //endregion -} +} \ No newline at end of file diff --git a/src/Traits/BasePositionTrait.php b/src/Traits/BasePositionTrait.php index 4796394..0d6f597 100644 --- a/src/Traits/BasePositionTrait.php +++ b/src/Traits/BasePositionTrait.php @@ -128,26 +128,20 @@ protected function resetPositionOptionCache() * Enables setting disablePositionUpdate option in runtime * * @param boolean $value - * - * @return $this */ public function setDisablePositionUpdateAttribute($value) { $this->optionCache['disablePositionUpdate'] = $value; - return $this; } /** * Enables setting positionColumn option in runtime * * @param string $value - * - * @return $this */ public function setPositionColumnAttribute($value) { $this->optionCache['positionColumn'] = $value; - return $this; } //endregion }