Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Single Record Resource Laravel Package

coringawc/filament-single-record-resource

Implements the single-record resource pattern for Filament. Replace index lists with a per-user “one record” resource (Profile, Settings, Wallet, Subscription). Traits handle routing, navigation, auth fallbacks, record resolution, and nested breadcrumbs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require coringawc/filament-single-record-resource
    
  2. Apply HasSingleRecordResource to your Resource:

    use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecordResource;
    
    class MyWalletResource extends Resource
    {
        use HasSingleRecordResource;
    
        public static function getPages(): array
        {
            return [
                'view' => ViewMyWallet::route('/'),
                'edit' => EditMyWallet::route('/edit'),
            ];
        }
    }
    
  3. Add HasSingleRecord to your pages:

    use CoringaWc\FilamentSingleRecordResource\Traits\HasSingleRecord;
    
    class ViewMyWallet extends ViewRecord
    {
        use HasSingleRecord;
        protected static string $resource = MyWalletResource::class;
    }
    

First Use Case

Implement a "My Profile" resource:

  • Create a UserProfileResource with HasSingleRecordResource.
  • Use HasSingleRecord in ViewUserProfile and EditUserProfile.
  • Ensure your User model has a hasOne relationship to UserProfile (or similar).

Implementation Patterns

1. Standard Single-Record Flow

  • Resource: Extend Resource with HasSingleRecordResource.
  • Pages: Use HasSingleRecord in ViewRecord/EditRecord pages.
  • Model: Define a belongsTo(User) relationship on the single-record model.

2. Custom Resolution

  • Override resolveSingleRecordBuilder for query modifications:
    public static function resolveSingleRecordBuilder(Builder $query): Builder
    {
        return $query->where('active', true);
    }
    
  • Override resolveSingleRecord for complex logic (e.g., firstOrCreate):
    public static function resolveSingleRecord(): ?Model
    {
        return auth()->user()->wallet()->firstOrCreate();
    }
    

3. Nested Resources

  • Parent Resource: Use HasSingleRecordResource.
  • Child Resource: Extend HasSingleRecord in pages.
  • URLs: Remove parent IDs from URLs (e.g., /wallets/companies/products/companies/products).
  • Breadcrumbs: Automatically normalized by the package.

4. Authorization

  • Fallback Logic: Access granted if view() is allowed on the resolved record, even if viewAny() is denied.
  • Policy Example:
    public function viewAny(User $user): bool
    {
        return false; // Deny index, but allow view() on user's record
    }
    

5. Type Safety (Optional)

  • Implement SingleRecordResolvableResource for static analysis:
    class MyWalletResource extends Resource implements SingleRecordResolvableResource
    {
        use HasSingleRecordResource;
    }
    

Gotchas and Tips

Pitfalls

  1. Missing Relationships:

    • If the single-record model lacks a belongsTo(User) relationship, resolution fails silently. Fix: Explicitly define the relationship or override resolveSingleRecord.
  2. Nested Resource Confusion:

    • Nested resources must not use HasSingleRecordResource if they’re not part of the single-record chain. Fix: Only apply it to root single-record resources.
  3. Authorization Overrides:

    • Forgetting to allow view() on the resolved record can block access. Fix: Ensure policies grant view() for user-specific records.
  4. URL Routing Issues:

    • Deeply nested resources may break if parent IDs are missing from URLs. Fix: Use HasSingleRecord in all nested pages and enforce strict query scoping.

Debugging Tips

  • Check Resolution: Override resolveSingleRecord() temporarily to log the resolved record:

    public static function resolveSingleRecord(): ?Model
    {
        $record = parent::resolveSingleRecord();
        \Log::info('Resolved record:', ['record' => $record]);
        return $record;
    }
    
  • Verify Authorization: Test viewAny() and view() separately to isolate permission issues:

    // In a policy test:
    $this->assertFalse($policy->viewAny($user));
    $this->assertTrue($policy->view($user, $record));
    
  • Clear Cache: After adding HasSingleRecordResource, run:

    php artisan optimize:clear
    

Extension Points

  1. Custom Resolvers: Extend resolveSingleRecord() for tenant-aware or multi-user scenarios.

  2. Dynamic Pages: Dynamically register pages based on resolved record attributes:

    public static function getPages(): array
    {
        $pages = ['view' => ViewMyWallet::route('/')];
        if ($record->hasPremiumFeatures) {
            $pages['premium'] = PremiumSettings::route('/premium');
        }
        return $pages;
    }
    
  3. Fallback Logic: Override getIndexUrl() or getNavigationGroup() to customize sidebar behavior:

    public static function getIndexUrl(): string
    {
        return static::getResourceUrl('view');
    }
    

Configuration Quirks

  • Filament 4 vs. 5: The package supports both, but test nested resources in Filament 5 due to routing changes.
  • Workbench Testing: Ensure DB_DATABASE is set in workbench containers to avoid SQLite connection issues (fixed in v1.1.1).

Performance

  • Eager Load Relationships: Preload related data in resolveSingleRecordBuilder to avoid N+1 queries:
    return $query->with('transactions');
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime