coringawc / filament-single-record-resource
A Filament plugin that solves the single-record resource pattern — resources that display exactly one record per authenticated user (e.g. 'My Profile', 'My Wallet', 'My Settings') without an index page, and their arbitrarily nested child resources.
Package info
github.com/CoringaWc/filament-single-record-resource
pkg:composer/coringawc/filament-single-record-resource
Fund package maintenance!
Requires
- php: ^8.2
- filament/filament: ^4.0 || ^5.0
- laravel/framework: ^11.0 || ^12.0
- spatie/laravel-package-tools: ^1.15.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0 || ^10.0
- orchestra/workbench: ^9.0|^10.0
- pestphp/pest: ^3.7|^4.0
- pestphp/pest-plugin-arch: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- pestphp/pest-plugin-livewire: ^3.0|^4.0
- rector/rector: ^2.0
README
This package implements the single-record resource pattern for Filament panels.
Instead of a list page (index) with many records, you open one resource that always resolves to one business record per authenticated user.
Common examples:
- My Profile
- My Wallet
- My Settings
- Current Subscription
Compatibility
- Filament
^4.0 || ^5.0 - Laravel versions supported by the selected Filament major
Installation
composer require coringawc/filament-single-record-resource
Core Concepts
This package is based on two traits:
HasSingleRecordResource(Resource trait)
- Redirects index/navigation behavior to
view - Keeps sidebar navigation working without an
indexpage - Helps nested resources resolve root URLs/slugs in single-record chains
HasSingleRecord(Page trait forViewRecordandEditRecord)
- Resolves the root single record automatically
- Supports custom resolution via builder or custom resolver method
- Normalizes breadcrumbs in deep nested resources
Step-by-Step Implementation
1. Create your resource as single-record root
In your Filament Resource, use HasSingleRecordResource and register only view (and optionally edit) pages.
<?php namespace App\Filament\Resources\MyWallets; use App\Filament\Resources\MyWallets\Pages\EditMyWallet; use App\Filament\Resources\MyWallets\Pages\ViewMyWallet; use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecordResource; use Filament\Resources\Resource; class MyWalletResource extends Resource { use HasSingleRecordResource; public static function getPages(): array { return [ 'view' => ViewMyWallet::route('/'), 'edit' => EditMyWallet::route('/edit'), ]; } }
2. Use HasSingleRecord in ViewRecord
<?php namespace App\Filament\Resources\MyWallets\Pages; use App\Filament\Resources\MyWallets\MyWalletResource; use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecord; use Filament\Resources\Pages\ViewRecord; class ViewMyWallet extends ViewRecord { use HasSingleRecord; protected static string $resource = MyWalletResource::class; }
3. Optional: also use HasSingleRecord in EditRecord
Yes, this package supports EditRecord too.
<?php namespace App\Filament\Resources\MyWallets\Pages; use App\Filament\Resources\MyWallets\MyWalletResource; use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecord; use Filament\Resources\Pages\EditRecord; class EditMyWallet extends EditRecord { use HasSingleRecord; protected static string $resource = MyWalletResource::class; }
Automatic Record Resolution (1:1 with authenticated user)
By default, HasSingleRecord calls a builder that applies whereBelongsTo(Filament::auth()->user()).
In practice, this works automatically when your resource model has a belongsTo(User::class) relation that points to the authenticated Filament user.
Typical 1:1 setup:
User hasOne WalletWallet belongsTo User
Example model relationships:
// App\Models\User public function wallet(): HasOne { return $this->hasOne(Wallet::class); } // App\Models\Wallet public function user(): BelongsTo { return $this->belongsTo(User::class); }
With this, your single-record root page resolves the wallet for the logged-in user automatically.
Custom Resolution Strategies
If your rule is not a simple belongsTo(user), override one of the methods below in the page class.
A) Customize builder (resolveSingleRecordBuilder)
protected function resolveSingleRecordBuilder(Builder $query): Builder { return parent::resolveSingleRecordBuilder($query) ->where('active', true); }
B) Full custom resolver (resolveSingleRecord)
Use this when you need firstOrCreate, tenant logic, or complex business rules.
protected function resolveSingleRecord(): ?Model { /** @var \App\Models\User|null $user */ $user = filament()->auth()->user(); if ($user === null) { return null; } return $user->wallet()->firstOrCreate([]); }
Nested Resources
For nested chains (for example MyWallet -> Companies -> Products):
- Keep
HasSingleRecordResourceon resources that follow the single-record flow - Keep
HasSingleRecordin deepViewRecord/EditRecordpages - If removing parent IDs from URLs, enforce strict query scoping in your models/pages
This package also helps preserve breadcrumb consistency in deep nested routes.
Screenshots
MyWallet (Root Single Resource)
Deep Nested Resource (MyWallet -> Companies -> Products)
Testing
Run tests:
composer test
The package CI validates the plugin in two scenarios:
- Filament 4 latest stable in major
- Filament 5 latest stable in major
Changelog
Please see CHANGELOG for details.
Contributing
Please see CONTRIBUTING.
Security
Please review our security policy.
Credits
License
The MIT License (MIT). See LICENSE.md.

