Skip to content

Commit e500729

Browse files
authored
Merge pull request #64 from blemli/without-trashed
respect softdeletes when the ->withoutTrashed() option is set
2 parents d4c4cda + c668495 commit e500729

File tree

7 files changed

+111
-1
lines changed

7 files changed

+111
-1
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,23 @@ public function panel(Panel $panel): Panel
132132
}
133133
```
134134

135+
## Excluding Soft Deleted Records
136+
137+
If your models use soft deletes, you can exclude trashed records from the count with the `withoutTrashed` method on the plugin.
138+
139+
```php
140+
use Awcodes\Overlook\OverlookPlugin;
141+
142+
public function panel(Panel $panel): Panel
143+
{
144+
return $panel
145+
->plugins([
146+
OverlookPlugin::make()
147+
->withoutTrashed(),
148+
]);
149+
}
150+
```
151+
135152
## Sorting the Items
136153

137154
By default, the items will be sorted in the order they are registered with Filament or as provided in the `includes` method. You can change this to sort them alphabetically with the `alphabetical` method on the plugin.

src/OverlookPlugin.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class OverlookPlugin implements Plugin
2929

3030
protected array|Closure|null $icons = null;
3131

32+
protected bool|Closure|null $withoutTrashed = null;
33+
3234
public static function make(): self
3335
{
3436
return app(self::class);
@@ -143,4 +145,16 @@ public function getIcons(): array
143145
{
144146
return $this->evaluate($this->icons) ?? [];
145147
}
148+
149+
public function withoutTrashed(bool|Closure|null $condition = true): static
150+
{
151+
$this->withoutTrashed = $condition;
152+
153+
return $this;
154+
}
155+
156+
public function shouldExcludeTrashed(): bool
157+
{
158+
return $this->evaluate($this->withoutTrashed) ?? false;
159+
}
146160
}

src/Widgets/OverlookWidget.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Awcodes\Overlook\OverlookPlugin;
99
use Exception;
1010
use Filament\Widgets\Widget;
11+
use Illuminate\Database\Eloquent\SoftDeletes;
1112
use Illuminate\Support\Number;
1213

1314
class OverlookWidget extends Widget
@@ -71,14 +72,18 @@ public function getData(): array
7172
? $includes
7273
: filament()->getCurrentOrDefaultPanel()->getResources();
7374

74-
return collect($rawResources)->filter(fn ($resource): bool => ! in_array($resource, $excludes))->transform(function ($resource) use ($icons): ?array {
75+
return collect($rawResources)->filter(fn ($resource): bool => ! in_array($resource, $excludes))->transform(function ($resource) use ($plugin, $icons): ?array {
7576

7677
$customIcon = array_search($resource, $icons);
7778

7879
$res = app($resource);
7980

8081
$widgetQuery = $res->getEloquentQuery();
8182

83+
if ($plugin->shouldExcludeTrashed() && in_array(SoftDeletes::class, class_uses_recursive($widgetQuery->getModel()))) {
84+
$widgetQuery = $widgetQuery->withoutTrashed();
85+
}
86+
8287
if ($res instanceof CustomizeOverlookWidget) {
8388
$rawCount = $res->getOverlookWidgetQuery($widgetQuery)->count();
8489
$title = $res->getOverlookWidgetTitle();

tests/src/Feature/WidgetTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,50 @@
8383
&& $data[0]['name'] === 'Unverified Users';
8484
});
8585
});
86+
87+
it('excludes soft deleted records when withoutTrashed is enabled', function () {
88+
// setUp creates 1 user for authentication
89+
User::factory()->count(3)->create();
90+
User::factory()->count(2)->create(['deleted_at' => now()]);
91+
92+
$this->panel
93+
->plugins([
94+
OverlookPlugin::make()
95+
->withoutTrashed()
96+
->includes([
97+
UserResource::class,
98+
]),
99+
])
100+
->widgets([
101+
OverlookWidget::class,
102+
]);
103+
104+
// 1 (from setUp) + 3 (created) = 4 non-trashed users
105+
livewire(OverlookWidget::class)
106+
->assertViewHas('data', function ($data) {
107+
return $data[0]['count'] === '4';
108+
});
109+
});
110+
111+
it('excludes soft deleted records by default due to SoftDeletes global scope', function () {
112+
// setUp creates 1 user for authentication
113+
User::factory()->count(3)->create();
114+
User::factory()->count(2)->create(['deleted_at' => now()]);
115+
116+
$this->panel
117+
->plugins([
118+
OverlookPlugin::make()
119+
->includes([
120+
UserResource::class,
121+
]),
122+
])
123+
->widgets([
124+
OverlookWidget::class,
125+
]);
126+
127+
// Default SoftDeletes global scope excludes trashed: 1 (from setUp) + 3 = 4
128+
livewire(OverlookWidget::class)
129+
->assertViewHas('data', function ($data) {
130+
return $data[0]['count'] === '4';
131+
});
132+
});

tests/src/Fixtures/Models/User.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
use Filament\Models\Contracts\FilamentUser;
99
use Filament\Panel;
1010
use Illuminate\Database\Eloquent\Factories\HasFactory;
11+
use Illuminate\Database\Eloquent\SoftDeletes;
1112
use Illuminate\Foundation\Auth\User as Authenticatable;
1213
use Illuminate\Notifications\Notifiable;
1314

1415
class User extends Authenticatable implements FilamentUser
1516
{
1617
use HasFactory;
1718
use Notifiable;
19+
use SoftDeletes;
1820

1921
protected $guarded = [];
2022

tests/src/TestCase.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Filament\Tables\TablesServiceProvider;
2020
use Filament\Widgets\WidgetsServiceProvider;
2121
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
22+
use Illuminate\Support\Facades\Schema;
2223
use Livewire\LivewireServiceProvider;
2324
use Orchestra\Testbench\Concerns\WithWorkbench;
2425
use Orchestra\Testbench\TestCase as Orchestra;
@@ -36,6 +37,15 @@ protected function setUp(): void
3637
$this->actingAs(User::factory()->create());
3738
}
3839

40+
protected function afterRefreshingDatabase(): void
41+
{
42+
if (! Schema::hasColumn('users', 'deleted_at')) {
43+
Schema::table('users', function ($table) {
44+
$table->softDeletes();
45+
});
46+
}
47+
}
48+
3949
protected function getPackageProviders($app): array
4050
{
4151
$providers = [

tests/src/Unit/PluginTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,18 @@
170170
expect(Filament::getPlugin('awcodes/overlook')->getIncludes())
171171
->toContain('Awcodes\Overlook\Tests\Fixtures\Resources\Users\UserResource');
172172
});
173+
174+
it('sets withoutTrashed', function (bool|Closure|null $condition) {
175+
$this->panel
176+
->plugins([
177+
OverlookPlugin::make()->withoutTrashed($condition),
178+
]);
179+
180+
expect(Filament::getPlugin('awcodes/overlook')->shouldExcludeTrashed())
181+
->toBe($condition);
182+
})->with([
183+
true,
184+
fn () => true,
185+
false,
186+
fn () => false,
187+
]);

0 commit comments

Comments
 (0)