finity-labs / fin-support
Shared support code for Finity Labs Filament plugins: page access through Filament Shield or a Gate ability, installer helpers for panel providers and the Shield config, and per-panel policy registration.
Requires
- php: ^8.2
- filament/filament: ^4.0|^5.0
- finity-labs/lin-support: ^0.1
- illuminate/contracts: ^11.28|^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
Suggests
- bezhansalleh/filament-shield: Page permissions through HasPageShieldSupport (^4.0).
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-09 11:02:06 UTC
README
Shared support code for Finity Labs Filament plugins. Builds on lin-support and Filament 4 or 5; the pieces every fin-* package kept copying, kept once. Not a Filament plugin itself: there is nothing to register on a panel.
Installation
composer require finity-labs/fin-support
What is in it
Page access with or without Shield
FinityLabs\FinSupport\Pages\Concerns\HasPageShieldSupport gates a Filament page three ways. With Filament Shield installed it asks Shield for the page's permission, whatever naming the host configured, and follows it. Without Shield, a host may define a Gate ability named after the page class, page_HelpSettings for a HelpSettings page, and the trait follows that. With neither, canAccessFallback() answers, which is open unless the page overrides it.
use Filament\Pages\Page; use FinityLabs\FinSupport\Pages\Concerns\HasPageShieldSupport; class ManageSettings extends Page { use HasPageShieldSupport; // Optional: a plugin option as the last word. protected static function canAccessFallback(): bool { return MyPlugin::get()->userCanAccess(); } }
Shield is never a hard dependency: its classes are reached behind class_exists().
Policy registration per panel
FinityLabs\FinSupport\Auth\PolicyRegistrar maps the policies a host writes at {namespace}\{Basename} onto a package's models, registering a shipped fallback when the host has none:
use FinityLabs\FinSupport\Auth\PolicyRegistrar; PolicyRegistrar::register($namespace, [ Article::class => 'ArticlePolicy', ], [ Article::class => ShippedArticlePolicy::class, ]);
Call it twice: from your service provider's boot with PolicyRegistrar::namespaceOf('my-plugin'), which reads the default panel's policyNamespace() option or falls back to App\Policies, and from your plugin's boot() with that panel's own option. That second call is what makes the option work per panel: Filament boots the current panel after the providers, so the provider alone only ever sees the default panel.
Installer helpers
Three traits for install and uninstall commands:
Console\Concerns\DiscoversPanelProvidersfinds the host's panel providers underapp/Providers/Filamentby file name:AdminPanelProvider.phpis theadminpanel.Console\Concerns\EditsPanelProvidersaddsMyPlugin::make(),to a provider's->plugins([...])block, creating the block when there is none, with the matchinguseline, and removes it again with every chained option. Both refuse to repeat themselves.Console\Concerns\EditsShieldConfigwrites a package's resources and abilities intoconfig/filament-shield.php'sresources.managearray, once, and takes them out again.
use FinityLabs\FinSupport\Console\Concerns\DiscoversPanelProviders; use FinityLabs\FinSupport\Console\Concerns\EditsPanelProviders; use FinityLabs\FinSupport\Console\Concerns\EditsShieldConfig; class InstallCommand extends Command { use DiscoversPanelProviders; use EditsPanelProviders; use EditsShieldConfig; public function handle(): int { $providers = $this->discoverPanelProviders(); // ['admin' => '/app/Providers/Filament/AdminPanelProvider.php'] $this->registerPlugin($providers['admin'], MyPlugin::class); if ($this->hasShieldConfig()) { $this->registerShieldResources([MyResource::class => ['viewAny', 'view']], 'Vendor\\MyPackage'); } return self::SUCCESS; } }
The panel user
FinityLabs\FinSupport\Panel\Concerns\ResolvesPanelUser::panelUserId() is Filament::auth()->id() narrowed to ?int, for packages that store the author in an integer column.
Testing
composer test
composer analyse
composer format
License
MIT. See LICENSE.