From a03f3e3a7bb10edf967f6736a0df5f1d5790d3ec Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Fri, 10 Apr 2026 13:12:50 +0700 Subject: [PATCH] refactor: migrate to HasManyDeep for cooperation reports and standardize query filtering across relation managers --- .../Cooperations/Pages/ListCooperations.php | 3 +- .../CooperationPaymentRelationManager.php | 15 ++- .../CooperationProposalRelationManager.php | 19 ++- .../ReportRelationManager.php | 30 ++--- app/Models/Cooperation.php | 14 ++- composer.json | 1 + composer.lock | 116 +++++++++++++++++- 7 files changed, 153 insertions(+), 45 deletions(-) diff --git a/app/Filament/Resources/Manage/Cooperations/Pages/ListCooperations.php b/app/Filament/Resources/Manage/Cooperations/Pages/ListCooperations.php index af26929..534c726 100644 --- a/app/Filament/Resources/Manage/Cooperations/Pages/ListCooperations.php +++ b/app/Filament/Resources/Manage/Cooperations/Pages/ListCooperations.php @@ -27,7 +27,8 @@ protected function getHeaderActions(): array CooperationExcelExport::make(), ]) ->color('success') - ->icon(null), + ->icon(null) + ->visible(! auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)), ]; } } diff --git a/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationPaymentRelationManager.php b/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationPaymentRelationManager.php index 901a320..16b9242 100644 --- a/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationPaymentRelationManager.php +++ b/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationPaymentRelationManager.php @@ -60,14 +60,13 @@ public function table(Table $table): Table ->emptyStateIcon(Heroicon::OutlinedCreditCard) ->emptyStateHeading(fn () => CheerfulNotification::getByKey('cooperation.payment_empty_heading')) ->emptyStateDescription(fn () => CheerfulNotification::getByKey('cooperation.payment_empty')) - ->defaultSort('created_at', 'desc'); - } - - public function getEloquentQuery(): Builder - { - return parent::getEloquentQuery() - ->whereHas('cooperationMedia.partnerMedia.company', function (Builder $query): void { - $query->where('user_id', auth()->id()); + ->defaultSort('created_at', 'desc') + ->modifyQueryUsing(function (Builder $query): void { + $query->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $subQuery): void { + $subQuery->whereHas('partnerMedia.company', function (Builder $q): void { + $q->where('user_id', auth()->id()); + }); + }); }); } } diff --git a/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationProposalRelationManager.php b/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationProposalRelationManager.php index 67a9f4a..ae8df56 100644 --- a/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationProposalRelationManager.php +++ b/app/Filament/Resources/Manage/Cooperations/RelationManagers/CooperationProposalRelationManager.php @@ -111,7 +111,14 @@ public function table(Table $table): Table ->emptyStateIcon(Heroicon::OutlinedDocumentText) ->emptyStateHeading(fn () => CheerfulNotification::getByKey('cooperation.proposal_empty_heading')) ->emptyStateDescription(fn () => CheerfulNotification::getByKey('cooperation.proposal_empty')) - ->defaultSort('created_at', 'desc'); + ->defaultSort('created_at', 'desc') + ->modifyQueryUsing(function (Builder $query): void { + $query->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $subQuery): void { + $subQuery->whereHas('partnerMedia.company', function (Builder $q): void { + $q->where('user_id', auth()->id()); + }); + }); + }); } public function infolist(Schema $infolist): Schema @@ -161,14 +168,4 @@ public function infolist(Schema $infolist): Schema ]) ->columns(1); } - - public function getEloquentQuery(): Builder - { - return parent::getEloquentQuery() - ->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $query): void { - $query->whereHas('partnerMedia.company', function (Builder $q): void { - $q->where('user_id', auth()->id()); - }); - }); - } } diff --git a/app/Filament/Resources/Manage/Cooperations/RelationManagers/ReportRelationManager.php b/app/Filament/Resources/Manage/Cooperations/RelationManagers/ReportRelationManager.php index baa2d8f..d4d59e5 100644 --- a/app/Filament/Resources/Manage/Cooperations/RelationManagers/ReportRelationManager.php +++ b/app/Filament/Resources/Manage/Cooperations/RelationManagers/ReportRelationManager.php @@ -55,15 +55,15 @@ public static function canViewForRecord(Model $ownerRecord, string $pageClass): public static function getBadge(Model $ownerRecord, string $pageClass): ?string { + $query = $ownerRecord->reports(); + if (auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value)) { - return $ownerRecord->reports() - ->whereHas('mediaTaskAssignment.partnerMedia.company', function ($q) { - $q->where('user_id', auth()->id()); - }) - ->count(); + $query->whereHas('mediaTaskAssignment.partnerMedia.company', function ($q) { + $q->where('user_id', auth()->id()); + }); } - return $ownerRecord->reports()->count(); + return (string) $query->count(); } public function form(Schema $schema): Schema @@ -155,6 +155,9 @@ public function table(Table $table): Table ->modalWidth(Width::Large) ->modalHeading(fn () => CheerfulNotification::getByKey('cooperation.create_report_title')) ->modalDescription(fn () => CheerfulNotification::getByKey('cooperation.create_report_desc')) + ->using(function (array $data, string $model): Model { + return $model::create($data); + }) ->mutateDataUsing(function (array $data): array { $taskAssignment = $this->getOwnerRecord()->taskAssignment; @@ -221,15 +224,12 @@ public function table(Table $table): Table ->emptyStateIcon(Heroicon::OutlinedInboxArrowDown) ->emptyStateHeading(fn () => CheerfulNotification::getByKey('cooperation.report_empty_heading')) ->emptyStateDescription(fn () => CheerfulNotification::getByKey('cooperation.report_empty')) - ->defaultSort('created_at', 'desc'); - } - - public function getEloquentQuery(): Builder - { - return parent::getEloquentQuery() - ->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $query): void { - $query->whereHas('mediaTaskAssignment.partnerMedia.company', function (Builder $q): void { - $q->where('user_id', auth()->id()); + ->defaultSort('created_at', 'desc') + ->modifyQueryUsing(function (Builder $query): void { + $query->when(auth()->user()->hasRole(RoleEnum::PERUSAHAAN->value), function (Builder $query): void { + $query->whereHas('mediaTaskAssignment.partnerMedia.company', function (Builder $q): void { + $q->where('user_id', auth()->id()); + }); }); }); } diff --git a/app/Models/Cooperation.php b/app/Models/Cooperation.php index 8585c04..73a3439 100644 --- a/app/Models/Cooperation.php +++ b/app/Models/Cooperation.php @@ -14,11 +14,13 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; +use Staudenmeir\EloquentHasManyDeep\HasManyDeep; +use Staudenmeir\EloquentHasManyDeep\HasRelationships; use Swindon\FilamentHashids\Traits\HasHashid; class Cooperation extends Model implements HasMedia { - use HasFactory, HasHashid, InteractsWithMedia, SoftDeletes; + use HasFactory, HasHashid, HasRelationships, InteractsWithMedia, SoftDeletes; protected $guarded = ['id']; @@ -92,13 +94,13 @@ public function proposal(): HasMany return $this->hasMany(CooperationProposal::class); } - public function reports(): HasManyThrough + public function reports(): HasManyDeep { - return $this->hasManyThrough( + return $this->hasManyDeep( Report::class, - MediaTaskAssignment::class, - 'task_assignment_id', - 'media_task_assignment_id' + [TaskAssignment::class, MediaTaskAssignment::class], + ['cooperation_id', 'task_assignment_id', 'media_task_assignment_id'], + ['id', 'id', 'id'] ); } diff --git a/composer.json b/composer.json index 5b23be0..fc56b5d 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "spatie/laravel-settings": "^3.6", "spatie/laravel-sluggable": "^3.7", "spatie/laravel-tags": "^4.10", + "staudenmeir/eloquent-has-many-deep": "^1.21", "swindon/filament-hashids": "^1.0", "swisnl/filament-backgrounds": "^2.0", "symfony/css-selector": "^7.4", diff --git a/composer.lock b/composer.lock index d17ab90..12b4469 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "658bd2d05451d69b51335e1dc205775e", + "content-hash": "56c24787e6cbc418cfa67149242373d2", "packages": [ { "name": "achyutn/filament-log-viewer", @@ -8102,6 +8102,114 @@ ], "time": "2026-01-12T07:42:22+00:00" }, + { + "name": "staudenmeir/eloquent-has-many-deep", + "version": "v1.21.3", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/eloquent-has-many-deep.git", + "reference": "627986482120e1d5787167bdeb953afa0835bc5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep/zipball/627986482120e1d5787167bdeb953afa0835bc5d", + "reference": "627986482120e1d5787167bdeb953afa0835bc5d", + "shasum": "" + }, + "require": { + "illuminate/database": "^12.0", + "php": "^8.2", + "staudenmeir/eloquent-has-many-deep-contracts": "^1.3" + }, + "require-dev": { + "awobaz/compoships": "^2.3", + "barryvdh/laravel-ide-helper": "^3.0", + "korridor/laravel-has-many-merged": "^1.2", + "larastan/larastan": "^3.0", + "laravel/framework": "^12.0", + "mockery/mockery": "^1.6", + "orchestra/testbench-core": "^10.0", + "phpunit/phpunit": "^11.0", + "staudenmeir/eloquent-json-relations": "^1.14", + "staudenmeir/laravel-adjacency-list": "^1.24" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Staudenmeir\\EloquentHasManyDeep\\IdeHelperServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Staudenmeir\\EloquentHasManyDeep\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Laravel Eloquent HasManyThrough relationships with unlimited levels", + "support": { + "issues": "https://github.com/staudenmeir/eloquent-has-many-deep/issues", + "source": "https://github.com/staudenmeir/eloquent-has-many-deep/tree/v1.21.3" + }, + "funding": [ + { + "url": "https://paypal.me/JonasStaudenmeir", + "type": "custom" + } + ], + "time": "2026-03-14T10:49:35+00:00" + }, + { + "name": "staudenmeir/eloquent-has-many-deep-contracts", + "version": "v1.3", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts.git", + "reference": "37ce351e4db919b3af606bc8ca0e62e2e4939cde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep-contracts/zipball/37ce351e4db919b3af606bc8ca0e62e2e4939cde", + "reference": "37ce351e4db919b3af606bc8ca0e62e2e4939cde", + "shasum": "" + }, + "require": { + "illuminate/database": "^12.0", + "php": "^8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Staudenmeir\\EloquentHasManyDeepContracts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Contracts for staudenmeir/eloquent-has-many-deep", + "support": { + "issues": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts/issues", + "source": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts/tree/v1.3" + }, + "time": "2025-02-15T17:11:01+00:00" + }, { "name": "swindon/filament-hashids", "version": "v1.0.0", @@ -15396,12 +15504,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.2" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" }