diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 60183c5..c09678f 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.6.0 + uses: dependabot/fetch-metadata@v2.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" compat-lookup: true diff --git a/README.md b/README.md index 8d0692e..3e5078c 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,29 @@ public function buildSortQuery() ``` This will restrict the calculations to fields value of the model instance. +### Dispatched events + +Once a sort has been completed, an event (`Spatie\EloquentSortable\EloquentModelSortedEvent`) is dispatched that you +can listen for. This can be useful for running post-sorting logic such as clearing caches or other actions that +need to be taken after a sort. + +The event has an `isFor` helper which allows you to conveniently check the Eloquent class that has been sorted. + +Below is an example of how you can listen for this event: + +```php +use Spatie\EloquentSortable\EloquentModelSortedEvent as SortEvent; + +class SortingListener +{ + public function handle(SortEvent $event): void { + if ($event->isFor(MyClass::class)) { + // ToDo: flush our cache + } + } +} +``` + ## Tests The package contains some integration/smoke tests, set up with Orchestra. The tests can be run via phpunit. diff --git a/src/EloquentModelSortedEvent.php b/src/EloquentModelSortedEvent.php new file mode 100644 index 0000000..3c78bec --- /dev/null +++ b/src/EloquentModelSortedEvent.php @@ -0,0 +1,24 @@ +model = $model; + } + + public function isFor(Model|string $model): bool + { + if (is_string($model)) { + return $model === $this->model; + } + + return get_class($model) === $this->model; + } +} diff --git a/src/SortableTrait.php b/src/SortableTrait.php index b3a6cd3..40ce734 100644 --- a/src/SortableTrait.php +++ b/src/SortableTrait.php @@ -5,6 +5,7 @@ use ArrayAccess; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; +use Illuminate\Support\Facades\Event; use InvalidArgumentException; trait SortableTrait @@ -27,12 +28,12 @@ public function setHighestOrderNumber(): void public function getHighestOrderNumber(): int { - return (int) $this->buildSortQuery()->max($this->determineOrderColumnName()); + return (int)$this->buildSortQuery()->max($this->determineOrderColumnName()); } public function getLowestOrderNumber(): int { - return (int) $this->buildSortQuery()->min($this->determineOrderColumnName()); + return (int)$this->buildSortQuery()->min($this->determineOrderColumnName()); } public function scopeOrdered(Builder $query, string $direction = 'asc') @@ -40,9 +41,13 @@ public function scopeOrdered(Builder $query, string $direction = 'asc') return $query->orderBy($this->determineOrderColumnName(), $direction); } - public static function setNewOrder($ids, int $startOrder = 1, string $primaryKeyColumn = null, callable $modifyQuery = null): void - { - if (! is_array($ids) && ! $ids instanceof ArrayAccess) { + public static function setNewOrder( + $ids, + int $startOrder = 1, + string $primaryKeyColumn = null, + callable $modifyQuery = null + ): void { + if (!is_array($ids) && !$ids instanceof ArrayAccess) { throw new InvalidArgumentException('You must pass an array or ArrayAccess object to setNewOrder'); } @@ -67,6 +72,8 @@ public static function setNewOrder($ids, int $startOrder = 1, string $primaryKey ->update([$orderColumnName => $startOrder++]); } + Event::dispatch(new EloquentModelSortedEvent(static::class)); + if (config('eloquent-sortable.ignore_timestamps', false)) { static::$ignoreTimestampsOn = array_values(array_diff(static::$ignoreTimestampsOn, [static::class])); } @@ -99,7 +106,7 @@ public function moveOrderDown(): static ->where($orderColumnName, '>', $this->$orderColumnName) ->first(); - if (! $swapWithModel) { + if (!$swapWithModel) { return $this; } @@ -115,7 +122,7 @@ public function moveOrderUp(): static ->where($orderColumnName, '<', $this->$orderColumnName) ->first(); - if (! $swapWithModel) { + if (!$swapWithModel) { return $this; } @@ -157,7 +164,9 @@ public function moveToStart(): static $this->$orderColumnName = $firstModel->$orderColumnName; $this->save(); - $this->buildSortQuery()->where($this->getQualifiedKeyName(), '!=', $this->getKey())->increment($orderColumnName); + $this->buildSortQuery()->where($this->getQualifiedKeyName(), '!=', $this->getKey())->increment( + $orderColumnName + ); return $this; } diff --git a/tests/SortableTest.php b/tests/SortableTest.php index 4b7248a..11ad2ff 100644 --- a/tests/SortableTest.php +++ b/tests/SortableTest.php @@ -3,6 +3,8 @@ namespace Spatie\EloquentSortable\Test; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Event; +use Spatie\EloquentSortable\EloquentModelSortedEvent; class SortableTest extends TestCase { @@ -33,6 +35,9 @@ public function it_can_get_the_highest_order_number_with_trashed_models() /** @test */ public function it_can_set_a_new_order() { + + Event::fake(EloquentModelSortedEvent::class); + $newOrder = Collection::make(Dummy::all()->pluck('id'))->shuffle()->toArray(); Dummy::setNewOrder($newOrder); @@ -40,6 +45,10 @@ public function it_can_set_a_new_order() foreach (Dummy::orderBy('order_column')->get() as $i => $dummy) { $this->assertEquals($newOrder[$i], $dummy->id); } + + Event::assertDispatched(EloquentModelSortedEvent::class, function (EloquentModelSortedEvent $event) { + return $event->isFor(Dummy::class); + }); } /** @test */