refactor(banks): add Bank::availableForUser scope (#480)

## What

The "public banks + user's own banks" query was repeated in **5
controllers** (Transaction ×2, Settings/Bank, Budget, Cashflow,
Onboarding).

New `Bank::availableForUser($user)` scope; all 5 sites use it.

Bonus: the Onboarding variant had no `where()` grouping around
`whereNull/orWhere` — harmless today (no other constraints) but a latent
precedence bug. The scope always groups.

## Stats

- **-31 / +24 lines**, 5 call sites → 1 definition

## Checks

- `php artisan test
--filter="Bank|Transaction|Budget|Cashflow|Onboarding"` — 612 passed
(2707 assertions), 1 skipped
- `vendor/bin/pint --dirty` — pass

Part of duplication-removal series (#475–#479).
This commit is contained in:
Víctor Falcón 2026-06-03 17:59:24 +02:00 committed by GitHub
parent fe5e22bcfe
commit 7784f0d4fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 21 additions and 23 deletions

View File

@ -95,10 +95,7 @@ class BudgetController extends Controller
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
$banks = Bank::query()
->where(function ($q) use ($user) {
$q->whereNull('user_id')
->orWhere('user_id', $user->id);
})
->availableForUser($user)
->orderBy('name')
->get(['id', 'name', 'logo']);

View File

@ -27,10 +27,7 @@ class CashflowController extends Controller
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
$banks = Bank::query()
->where(function ($q) use ($user) {
$q->whereNull('user_id')
->orWhere('user_id', $user->id);
})
->availableForUser($user)
->orderBy('name')
->get(['id', 'name', 'logo']);

View File

@ -19,8 +19,7 @@ class OnboardingController extends Controller
$user = $request->user();
$banks = Bank::query()
->whereNull('user_id')
->orWhere('user_id', $user->id)
->availableForUser($user)
->orderBy('name')
->get(['id', 'name', 'logo']);

View File

@ -14,11 +14,7 @@ class BankController extends Controller
{
public function index(Request $request): JsonResponse
{
$query = Bank::query()
->where(function (Builder $q) {
$q->whereNull('user_id')
->orWhere('user_id', auth()->id());
});
$query = Bank::query()->availableForUser($request->user());
$search = trim((string) $request->input('search', ''));

View File

@ -82,10 +82,7 @@ class TransactionController extends Controller
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
$banks = Bank::query()
->where(function ($q) use ($user) {
$q->whereNull('user_id')
->orWhere('user_id', $user->id);
})
->availableForUser($user)
->orderBy('name')
->get(['id', 'name', 'logo']);
@ -127,10 +124,7 @@ class TransactionController extends Controller
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
$banks = Bank::query()
->where(function ($q) use ($user) {
$q->whereNull('user_id')
->orWhere('user_id', $user->id);
})
->availableForUser($user)
->orderBy('name')
->get(['id', 'name', 'logo']);

View File

@ -3,6 +3,7 @@
namespace App\Models;
use Database\Factories\BankFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -21,6 +22,20 @@ class Bank extends Model
'user_id',
];
/**
* Scope to banks visible to the given user: public banks plus their own.
*
* @param Builder<Bank> $query
* @return Builder<Bank>
*/
public function scopeAvailableForUser(Builder $query, User $user): Builder
{
return $query->where(function (Builder $q) use ($user) {
$q->whereNull('user_id')
->orWhere('user_id', $user->id);
});
}
/** @return BelongsTo<User, $this> */
public function user(): BelongsTo
{