Completed
Push — master ( 200c6a...200e13 )
by Freek
01:43 queued 10s
created

src/SortableTrait.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Spatie\EloquentSortable;
4
5
use ArrayAccess;
6
use InvalidArgumentException;
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Database\Eloquent\SoftDeletingScope;
9
10
trait SortableTrait
11
{
12
    public static function bootSortableTrait()
13
    {
14
        static::creating(function ($model) {
15
            if ($model instanceof Sortable && $model->shouldSortWhenCreating()) {
16
                $model->setHighestOrderNumber();
17
            }
18
        });
19
    }
20
21
    public function setHighestOrderNumber()
22
    {
23
        $orderColumnName = $this->determineOrderColumnName();
24
25
        $this->$orderColumnName = $this->getHighestOrderNumber() + 1;
26
    }
27
28
    public function getHighestOrderNumber(): int
29
    {
30
        return (int) $this->buildSortQuery()->max($this->determineOrderColumnName());
31
    }
32
33
    public function scopeOrdered(Builder $query, string $direction = 'asc')
34
    {
35
        return $query->orderBy($this->determineOrderColumnName(), $direction);
36
    }
37
38
    public static function setNewOrder($ids, int $startOrder = 1, string $primaryKeyColumn = null)
39
    {
40
        if (! is_array($ids) && ! $ids instanceof ArrayAccess) {
41
            throw new InvalidArgumentException('You must pass an array or ArrayAccess object to setNewOrder');
42
        }
43
44
        $model = new static;
45
46
        $orderColumnName = $model->determineOrderColumnName();
47
48
        if (is_null($primaryKeyColumn)) {
49
            $primaryKeyColumn = $model->getKeyName();
50
        }
51
52
        foreach ($ids as $id) {
53
            static::withoutGlobalScope(SoftDeletingScope::class)
54
                ->where($primaryKeyColumn, $id)
55
                ->update([$orderColumnName => $startOrder++]);
56
        }
57
    }
58
59
    public static function setNewOrderByCustomColumn(string $primaryKeyColumn, $ids, int $startOrder = 1)
60
    {
61
        self::setNewOrder($ids, $startOrder, $primaryKeyColumn);
62
    }
63
64
    protected function determineOrderColumnName(): string
65
    {
66
        if (
67
            isset($this->sortable['order_column_name']) &&
68
            ! empty($this->sortable['order_column_name'])
69
        ) {
70
            return $this->sortable['order_column_name'];
71
        }
72
73
        return 'order_column';
74
    }
75
76
    /**
77
     * Determine if the order column should be set when saving a new model instance.
78
     */
79
    public function shouldSortWhenCreating(): bool
80
    {
81
        return $this->sortable['sort_when_creating'] ?? true;
82
    }
83
84 View Code Duplication
    public function moveOrderDown()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
85
    {
86
        $orderColumnName = $this->determineOrderColumnName();
87
88
        $swapWithModel = $this->buildSortQuery()->limit(1)
89
            ->ordered()
90
            ->where($orderColumnName, '>', $this->$orderColumnName)
91
            ->first();
92
93
        if (! $swapWithModel) {
94
            return $this;
95
        }
96
97
        return $this->swapOrderWithModel($swapWithModel);
98
    }
99
100 View Code Duplication
    public function moveOrderUp()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
    {
102
        $orderColumnName = $this->determineOrderColumnName();
103
104
        $swapWithModel = $this->buildSortQuery()->limit(1)
105
            ->ordered('desc')
106
            ->where($orderColumnName, '<', $this->$orderColumnName)
107
            ->first();
108
109
        if (! $swapWithModel) {
110
            return $this;
111
        }
112
113
        return $this->swapOrderWithModel($swapWithModel);
114
    }
115
116
    public function swapOrderWithModel(Sortable $otherModel)
117
    {
118
        $orderColumnName = $this->determineOrderColumnName();
119
120
        $oldOrderOfOtherModel = $otherModel->$orderColumnName;
121
122
        $otherModel->$orderColumnName = $this->$orderColumnName;
123
        $otherModel->save();
124
125
        $this->$orderColumnName = $oldOrderOfOtherModel;
126
        $this->save();
127
128
        return $this;
129
    }
130
131
    public static function swapOrder(Sortable $model, Sortable $otherModel)
132
    {
133
        $model->swapOrderWithModel($otherModel);
134
    }
135
136
    public function moveToStart()
137
    {
138
        $firstModel = $this->buildSortQuery()->limit(1)
139
            ->ordered()
140
            ->first();
141
142
        if ($firstModel->id === $this->id) {
143
            return $this;
144
        }
145
146
        $orderColumnName = $this->determineOrderColumnName();
147
148
        $this->$orderColumnName = $firstModel->$orderColumnName;
149
        $this->save();
150
151
        $this->buildSortQuery()->where($this->getKeyName(), '!=', $this->id)->increment($orderColumnName);
152
153
        return $this;
154
    }
155
156
    public function moveToEnd()
157
    {
158
        $maxOrder = $this->getHighestOrderNumber();
159
160
        $orderColumnName = $this->determineOrderColumnName();
161
162
        if ($this->$orderColumnName === $maxOrder) {
163
            return $this;
164
        }
165
166
        $oldOrder = $this->$orderColumnName;
167
168
        $this->$orderColumnName = $maxOrder;
169
        $this->save();
170
171
        $this->buildSortQuery()->where($this->getKeyName(), '!=', $this->id)
172
            ->where($orderColumnName, '>', $oldOrder)
173
            ->decrement($orderColumnName);
174
175
        return $this;
176
    }
177
178
    public function buildSortQuery()
179
    {
180
        return static::query();
181
    }
182
}
183