Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch event after performing a sort #178

Merged
merged 5 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
24 changes: 24 additions & 0 deletions src/EloquentModelSortedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Spatie\EloquentSortable;

use Illuminate\Database\Eloquent\Model;

class EloquentModelSortedEvent
{
public string $model;

public function __construct(string $model)
{
$this->model = $model;
}

public function isFor(Model|string $model): bool
{
if (is_string($model)) {
return $model === $this->model;
}

return get_class($model) === $this->model;
}
}
25 changes: 17 additions & 8 deletions src/SortableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,22 +28,26 @@ 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')
{
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');
}

Expand All @@ -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]));
}
Expand Down Expand Up @@ -99,7 +106,7 @@ public function moveOrderDown(): static
->where($orderColumnName, '>', $this->$orderColumnName)
->first();

if (! $swapWithModel) {
if (!$swapWithModel) {
return $this;
}

Expand All @@ -115,7 +122,7 @@ public function moveOrderUp(): static
->where($orderColumnName, '<', $this->$orderColumnName)
->first();

if (! $swapWithModel) {
if (!$swapWithModel) {
return $this;
}

Expand Down Expand Up @@ -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;
}
Expand Down
9 changes: 9 additions & 0 deletions tests/SortableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -33,13 +35,20 @@ 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);

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 */
Expand Down
Loading