Skip to content

Latest commit

 

History

History
94 lines (84 loc) · 2.51 KB

reorder_models_trait.md

File metadata and controls

94 lines (84 loc) · 2.51 KB

Reorder models trait

Reorderable trait to change position of models in minimum number of queries

trait Reorderable
{
    /**
     * Reorder items by changing the
     * value in the position field in DB.
     *
     * @param array  $data
     *
     * @return \Illuminate\Support\Collection
     */
    public function reorder(array $data)
    {
        $currentPosition = $data['currentPosition'];
        $droppedPosition = $data['droppedPosition'];
        $move = $currentPosition > $droppedPosition ? 'up' : 'down';
        $modelTable = $this->getTable();

        $this->setDraggedItemPositionToZero($currentPosition);

        if ($move === 'down') {
            \DB::statement("
                UPDATE {$modelTable}
                SET position = (position - 1)
                WHERE position > {$currentPosition}
                AND position <= {$droppedPosition}
            ");
        }

        if ($move === 'up') {
            \DB::statement("
                UPDATE {$modelTable}
                SET position = (position + 1)
                WHERE position >= {$droppedPosition}
                AND position < {$currentPosition}
            ");
        }

        $this->setDesiredPositionOnItem($droppedPosition);

        return $this->orderBy('position')->get();
    }

    /**
     * Set position to 0 to the item that is dragged.
     *
     * @param int $currentPosition
     */
    protected function setDraggedItemPositionToZero($currentPosition)
    {
        $draggedItem = $this->getDraggedItem($currentPosition);
        $draggedItem->update(['position' => 0]);
    }

    /**
     * Set the desired position for the dragged item.
     *
     * @param int $droppedPosition
     */
    protected function setDesiredPositionOnItem($droppedPosition)
    {
        $draggedItem = $this->getDraggedItem(0);
        $draggedItem->update(['position' => $droppedPosition]);
    }

    /**
     * Get model of the dragged item.
     *
     * @param int $currentPosition
     *
     * @return Illuminate\Database\Eloquent\Model
     */
    protected function getDraggedItem($currentPosition)
    {
        return $this->findByPosition($currentPosition)->first();
    }

    /**
     * Scope a query to find model by position.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $currentPosition
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeFindByPosition($query, $currentPosition)
    {
        return $query->where('position', $currentPosition);
    }
}