Skip to content

Commit 4475c6c

Browse files
authored
Merge pull request #10 from nevadskiy/dev
Move using negative position values
2 parents 49960d3 + 40b8480 commit 4475c6c

File tree

3 files changed

+74
-11
lines changed

3 files changed

+74
-11
lines changed

README.md

+42-11
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,23 @@ Models simply have an integer `position` attribute corresponding to the model's
5858
5959
The `position` attribute is a kind of array index and is automatically inserted when a new model is created.
6060
61+
```php
62+
$category = Category::create();
63+
echo $category->position; // 0
64+
65+
$category = Category::create();
66+
echo $category->position; // 1
67+
68+
$category = Category::create();
69+
echo $category->position; // 2
70+
```
71+
6172
The starting position gets a `0` value by default. To change that, override the `startPosition` method in the model:
6273
6374
```php
6475
public function startPosition(): int
6576
{
66-
return 0;
77+
return 1;
6778
}
6879
```
6980
@@ -76,21 +87,21 @@ public function nextPosition(): ?int
7687
}
7788
```
7889
79-
In that example, a new model will be created in the beginning of the sequence.
90+
In that example, a new model will be created in the beginning of the sequence and the position of other models in the sequence will be automatically incremented.
8091
8192
### Deleting models
8293
8394
When a model is deleted, the positions of other records in the sequence are updated automatically.
8495
8596
### Querying models
8697
87-
To select models in the arranged sequence, use the `orderByPosition` scope.
98+
To select models in the arranged sequence, use the `orderByPosition` scope:
8899
89100
```php
90101
Category::orderByPosition()->get();
91102
```
92103
93-
### Auto ordering
104+
### Automatic ordering
94105
95106
The `orderByPosition` scope is not applied by default because the corresponding SQL statement will be added to all queries, even where it is not required.
96107
@@ -127,6 +138,12 @@ You can also use the `move` method that sets a new position value and updates th
127138
$category->move(3);
128139
```
129140
141+
If you want to move the model to the end of the sequence, you can use a negative position value:
142+
143+
```php
144+
$category->move(-1); // Move to the end
145+
```
146+
130147
#### Swap
131148
132149
The `swap` method swaps the position of two models.
@@ -139,40 +156,54 @@ $category->swap($anotherCategory);
139156
140157
By default, the package automatically updates the position of other models when the model position is updated.
141158
142-
If you want to update the model position without shifting the positions of other models, you can use the `withoutShifting` method:
159+
If you want to update the model position without shifting the position of other models, you can use the `withoutShifting` method:
143160
144161
```php
145162
Category::withoutShifting(function () {
146163
$category->move(5);
147164
})
148165
```
149166
150-
#### Arrange
167+
#### Arrange models
151168
152169
It is also possible to arrange models by their IDs.
153170
154171
The position of each model will be recalculated according to the index of its ID in the given array.
155172
156-
You can also provide a second argument as a starting position of the records.
173+
You can also provide a second argument as a starting position.
157174
158175
```php
159176
Category::arrangeByKeys([3, 5, 7]);
160177
```
161178
162179
### Grouping / Dealing with relations
163180
164-
To allow models to be positioned within groups, you need to override the `newPositionQuery` method that should return a query to the grouped model sequence:
181+
To allow models to be positioned within groups, you need to override the `newPositionQuery` method that should return a query to the grouped model sequence.
182+
183+
Using the relation builder:
165184
166185
```php
167186
use Illuminate\Database\Eloquent\Builder;
187+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
188+
use Nevadskiy\Position\HasPosition;
168189
169-
protected function newPositionQuery(): Builder
190+
class Category
170191
{
171-
return $this->category->tasks();
192+
use HasPosition;
193+
194+
public function group(): BelongsTo
195+
{
196+
return $this->hasMany(Group::class);
197+
}
198+
199+
protected function newPositionQuery(): Builder
200+
{
201+
return $this->group->categories();
202+
}
172203
}
173204
```
174205
175-
Example with self-referenced groups:
206+
Using the `where` method:
176207
177208
```php
178209
use Illuminate\Database\Eloquent\Builder;

src/HasPosition.php

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ public function getPosition(): ?int
125125
*/
126126
public function setPosition(?int $position): Model
127127
{
128+
if ($position < 0) {
129+
$position = ($this->getMaxPosition() + 1) + $position;
130+
}
131+
128132
return $this->setAttribute($this->getPositionColumn(), $position);
129133
}
130134

tests/MoveTest.php

+28
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,32 @@ public function it_can_update_position_without_moving_others(): void
6565
static::assertSame(1, $categories[1]->fresh()->getPosition());
6666
static::assertSame(2, $categories[2]->fresh()->getPosition());
6767
}
68+
69+
/**
70+
* @test
71+
*/
72+
public function it_can_move_to_end_using_negative_position(): void
73+
{
74+
$categories = CategoryFactory::new()->createMany(3);
75+
76+
$categories[0]->move(-1);
77+
78+
static::assertSame(2, $categories[0]->fresh()->getPosition());
79+
static::assertSame(0, $categories[1]->fresh()->getPosition());
80+
static::assertSame(1, $categories[2]->fresh()->getPosition());
81+
}
82+
83+
/**
84+
* @test
85+
*/
86+
public function it_can_move_to_new_position_using_negative_position(): void
87+
{
88+
$categories = CategoryFactory::new()->createMany(3);
89+
90+
$categories[0]->move(-2);
91+
92+
static::assertSame(1, $categories[0]->fresh()->getPosition());
93+
static::assertSame(0, $categories[1]->fresh()->getPosition());
94+
static::assertSame(2, $categories[2]->fresh()->getPosition());
95+
}
6896
}

0 commit comments

Comments
 (0)