From 1e273deb47b5446cf606ead6371daadda91e9446 Mon Sep 17 00:00:00 2001 From: Alexander Gabriel Date: Mon, 9 Feb 2026 01:49:28 +0000 Subject: [PATCH] =?UTF-8?q?test-policy=20mit=20mkro=20zum=20Filtern=20von?= =?UTF-8?q?=20Datens=C3=A4tzen=20in=20Tabelle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contracts/Tables/ContractsTable.php | 1 + app/Models/Contract.php | 3 + app/Policies/ContractPolicy.php | 74 +++++++++++++++++++ app/Providers/AppServiceProvider.php | 55 +++++++++++++- 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 app/Policies/ContractPolicy.php diff --git a/app/Filament/Resources/Contracts/Tables/ContractsTable.php b/app/Filament/Resources/Contracts/Tables/ContractsTable.php index 05a858f..30b9a99 100644 --- a/app/Filament/Resources/Contracts/Tables/ContractsTable.php +++ b/app/Filament/Resources/Contracts/Tables/ContractsTable.php @@ -13,6 +13,7 @@ class ContractsTable public static function configure(Table $table): Table { return $table + ->applyRowAccessPolicy() ->columns([ TextColumn::make('name') ->searchable(), diff --git a/app/Models/Contract.php b/app/Models/Contract.php index 68d9003..9d60b7e 100644 --- a/app/Models/Contract.php +++ b/app/Models/Contract.php @@ -3,10 +3,13 @@ namespace App\Models; use App\HasDocuments; +use App\Policies\ContractPolicy; +use Illuminate\Database\Eloquent\Attributes\UsePolicy; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphTo; +#[UsePolicy(ContractPolicy::class)] class Contract extends Model { use HasDocuments; diff --git a/app/Policies/ContractPolicy.php b/app/Policies/ContractPolicy.php new file mode 100644 index 0000000..14dd035 --- /dev/null +++ b/app/Policies/ContractPolicy.php @@ -0,0 +1,74 @@ +where('responsible_id', $user->id); + } + + /** + * Determine whether the user can view any models. + */ + public function viewAny(User $user): bool + { + return true; + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, Contract $contract): bool + { + return true; + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, Contract $contract): bool + { + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, Contract $contract): bool + { + return true; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, Contract $contract): bool + { + return true; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, Contract $contract): bool + { + return true; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..211eb07 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use Filament\Tables\Table; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -19,6 +20,58 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + # Makro, um die Zeilen zu filtern. + # geklaut hier: https://filamentglow.com/trick/implementing-row-level-security-in-filament-tables-with-applyrowaccesspolicy-30090998 + Table::macro('applyRowAccessPolicy', function (\Closure | bool $condition = true): Table { + if ($condition instanceof \Closure) { + $condition = $this->evaluate($condition); + } + + /** + * Store the view row scope condition in Laravel's service container. + * + * How this works: + * 1. We generate a unique ID for each Table instance using spl_object_hash() + * 2. We create a container binding with a key specific to this Table instance + * 3. The condition value (true/false) is stored in the container + * + * The container binding will be automatically cleaned up when the Table instance + * is garbage collected, as the binding key is unique to this instance. + */ + $tableId = spl_object_hash($this); + app()->instance('filament.table.viewRowScope.' . $tableId, $condition); + + return $this->modifyQueryUsing(function (\Illuminate\Database\Eloquent\Builder $query) use ($tableId): \Illuminate\Database\Eloquent\Builder { + // Check the container for this Table's specific viewRowScope setting + // Defaults to true if no binding exists (fallback for safety) + $shouldApply = app()->bound('filament.table.viewRowScope.' . $tableId) + ? app()->make('filament.table.viewRowScope.' . $tableId) + : true; + + if (! $shouldApply) { + return $query; + } + + $model = $query->getModel(); + + if (! $model) { + return $query; + } + + $policy = \Gate::getPolicyFor($model); + + if (! $policy || ! method_exists($policy, 'applyRowAccessPolicy')) { + return $query; + } + + $modifiedQuery = $policy->applyRowAccessPolicy(auth()->user(), $query); + + if (! $modifiedQuery instanceof \Illuminate\Database\Eloquent\Builder) { + throw new \RuntimeException("The applyRowAccessPolicy method for " . $policy::class . " must return an instance of Illuminate\Database\Eloquent\Builder."); + } + + return $modifiedQuery; + }); + }); } }