diff --git a/config/filament-library.php b/config/filament-library.php index cb93f80..1aa277d 100644 --- a/config/filament-library.php +++ b/config/filament-library.php @@ -1,5 +1,10 @@ env('FILAMENT_LIBRARY_USER_MODEL', 'App\\Models\\User'), + /* + |-------------------------------------------------------------------------- + | Model class overrides + |-------------------------------------------------------------------------- + | + | Extend package models in your application and register the classes here + | when you need custom behavior. Each class must extend the corresponding + | Tapp\FilamentLibrary\Models\* model. + | + | Example (in your app's config/filament-library.php): + | + | 'models' => [ + | 'LibraryItem' => \App\Models\LibraryItem::class, + | 'LibraryItemPermission' => \App\Models\LibraryItemPermission::class, + | 'LibraryItemTag' => \App\Models\LibraryItemTag::class, + | ], + | + */ + 'models' => [ + 'LibraryItem' => LibraryItem::class, + 'LibraryItemPermission' => LibraryItemPermission::class, + 'LibraryItemTag' => LibraryItemTag::class, + ], + + /* + |-------------------------------------------------------------------------- + | Filament resource class overrides + |-------------------------------------------------------------------------- + | + | Use this option to custom Filament Resource classes + | + | Example (in your app's config/filament-library.php): + | + | 'resources' => [ + | 'LibraryItemResource' => \App\Filament\Resources\Library\LibraryItemResource::class, + | ], + | + */ + 'resources' => [ + 'LibraryItemResource' => LibraryItemResource::class, + ], + + /* + |-------------------------------------------------------------------------- + | Personal folder provisioning + |-------------------------------------------------------------------------- + | + | When enabled, the plugin registers a listener that creates a personal + | library folder when a user is created. Disable this when your app + | provisions personal folders itself (for example with tenant checks). + | + */ + 'personal_folder' => [ + 'auto_create_on_user_created' => env('FILAMENT_LIBRARY_AUTO_CREATE_PERSONAL_FOLDER', true), + ], + /* |-------------------------------------------------------------------------- | Video Link Support diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5eec57e..25bc19d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -11,6 +11,22 @@ parameters: count: 1 path: database/seeders/LibrarySeeder.php + # FilamentLibraryPlugin - App\Models\User is application-specific (default user model) + - + message: "#^Class App\\\\Models\\\\User not found\\.$#" + count: 1 + path: src/FilamentLibraryPlugin.php + + - + message: "#^PHPDoc tag @var for variable \\$userModel contains unknown class App\\\\Models\\\\User\\.$#" + count: 1 + path: src/FilamentLibraryPlugin.php + + - + message: "#^Call to an undefined static method App\\\\Models\\\\User\\:\\:created\\(\\)\\.$#" + count: 1 + path: src/FilamentLibraryPlugin.php + # Config file - env() is allowed in config files - message: "#^Called 'env' outside of the config directory which returns null when the config is cached, use 'config'\\.$#" diff --git a/src/FilamentLibraryPlugin.php b/src/FilamentLibraryPlugin.php index d882128..16d2f73 100644 --- a/src/FilamentLibraryPlugin.php +++ b/src/FilamentLibraryPlugin.php @@ -8,12 +8,25 @@ use Filament\Panel; use Illuminate\Contracts\Auth\Authenticatable; use Tapp\FilamentLibrary\Models\LibraryItem; +use Tapp\FilamentLibrary\Models\LibraryItemPermission; +use Tapp\FilamentLibrary\Models\LibraryItemTag; use Tapp\FilamentLibrary\Resources\LibraryItemResource; class FilamentLibraryPlugin implements Plugin { protected static $libraryAdminCallback = null; + protected static bool $personalFolderListenerRegistered = false; + + /** + * @var array + */ + protected static array $defaultModels = [ + 'LibraryItem' => LibraryItem::class, + 'LibraryItemPermission' => LibraryItemPermission::class, + 'LibraryItemTag' => LibraryItemTag::class, + ]; + public function getId(): string { return 'filament-library'; @@ -60,47 +73,111 @@ public static function isLibraryAdmin($user): bool return false; } + /** + * @return class-string + */ + public static function libraryItemResourceClass(): string + { + /** @var class-string $resourceClass */ + $resourceClass = config( + 'filament-library.resources.LibraryItemResource', + LibraryItemResource::class, + ); + + return $resourceClass; + } + + /** + * @return class-string + */ + public static function modelClass(string $model): string + { + /** @var class-string $modelClass */ + $modelClass = config( + "filament-library.models.{$model}", + static::$defaultModels[$model] ?? throw new \InvalidArgumentException("Unknown filament-library model [{$model}]."), + ); + + return $modelClass; + } + + /** + * @return class-string + */ + public static function libraryItemModelClass(): string + { + /** @var class-string $modelClass */ + $modelClass = static::modelClass('LibraryItem'); + + return $modelClass; + } + + /** + * @return class-string + */ + public static function libraryItemPermissionModelClass(): string + { + /** @var class-string $modelClass */ + $modelClass = static::modelClass('LibraryItemPermission'); + + return $modelClass; + } + + /** + * @return class-string + */ + public static function libraryItemTagModelClass(): string + { + /** @var class-string $modelClass */ + $modelClass = static::modelClass('LibraryItemTag'); + + return $modelClass; + } + public function register(Panel $panel): void { $panelId = $panel->getId(); + $libraryItemResourceClass = static::libraryItemResourceClass(); $panel - ->resources([ - LibraryItemResource::class, - ]) + ->resources( + array_values(config('filament-library.resources', [ + LibraryItemResource::class, + ])), + ) ->navigationItems([ NavigationItem::make('Library') - ->url(fn () => LibraryItemResource::getUrl('index')) + ->url(fn () => $libraryItemResourceClass::getUrl('index')) ->icon('heroicon-o-building-library') ->group('Resource Library') ->sort(1) ->isActiveWhen(fn () => request()->routeIs("filament.{$panelId}.resources.library.index")), NavigationItem::make('Search All') - ->url(fn () => LibraryItemResource::getUrl('search-all')) + ->url(fn () => $libraryItemResourceClass::getUrl('search-all')) ->icon('heroicon-o-magnifying-glass') ->group('Resource Library') ->sort(2) ->isActiveWhen(fn () => request()->routeIs("filament.{$panelId}.resources.library.search-all")), NavigationItem::make('My Documents') - ->url(fn () => LibraryItemResource::getUrl('my-documents')) + ->url(fn () => $libraryItemResourceClass::getUrl('my-documents')) ->icon('heroicon-o-folder') ->group('Resource Library') ->sort(3) ->isActiveWhen(fn () => request()->routeIs("filament.{$panelId}.resources.library.my-documents")), NavigationItem::make('Shared with Me') - ->url(fn () => LibraryItemResource::getUrl('shared-with-me')) + ->url(fn () => $libraryItemResourceClass::getUrl('shared-with-me')) ->icon('heroicon-o-share') ->group('Resource Library') ->sort(4) ->isActiveWhen(fn () => request()->routeIs("filament.{$panelId}.resources.library.shared-with-me")), NavigationItem::make('Created by Me') - ->url(fn () => LibraryItemResource::getUrl('created-by-me')) + ->url(fn () => $libraryItemResourceClass::getUrl('created-by-me')) ->icon('heroicon-o-user') ->group('Resource Library') ->sort(5) ->isActiveWhen(fn () => request()->routeIs("filament.{$panelId}.resources.library.created-by-me")), NavigationItem::make('Favorites') - ->url(fn () => LibraryItemResource::getUrl('favorites')) + ->url(fn () => $libraryItemResourceClass::getUrl('favorites')) ->icon('heroicon-o-star') ->group('Resource Library') ->sort(6) @@ -110,9 +187,24 @@ public function register(Panel $panel): void public function boot(Panel $panel): void { - // Ensure users have personal folders when they access the library - User::created(function ($user) { - LibraryItem::ensurePersonalFolder($user); + if (! config('filament-library.personal_folder.auto_create_on_user_created', true)) { + return; + } + + if (static::$personalFolderListenerRegistered) { + return; + } + + static::$personalFolderListenerRegistered = true; + + /** @var class-string $userModel */ + $userModel = config('filament-library.user_model', User::class); + + $libraryItemModel = static::libraryItemModelClass(); + + // Optionally provision a personal folder when a user is created + $userModel::created(function ($user) use ($libraryItemModel): void { + $libraryItemModel::ensurePersonalFolder($user); }); } diff --git a/src/FilamentLibraryServiceProvider.php b/src/FilamentLibraryServiceProvider.php index 245cdf5..e81d0b2 100644 --- a/src/FilamentLibraryServiceProvider.php +++ b/src/FilamentLibraryServiceProvider.php @@ -80,8 +80,11 @@ public function packageBooted(): void // Register middleware $this->app['router']->pushMiddlewareToGroup('web', RedirectToCorrectEditPage::class); - // Register the policy - $this->app['Illuminate\Contracts\Auth\Access\Gate']->policy(LibraryItem::class, LibraryItemPolicy::class); + // Register the policy for the default package model only; host apps + // provide their own policy when overriding models.LibraryItem. + if (FilamentLibraryPlugin::libraryItemModelClass() === LibraryItem::class) { + $this->app['Illuminate\Contracts\Auth\Access\Gate']->policy(LibraryItem::class, LibraryItemPolicy::class); + } // Handle Stubs if (app()->runningInConsole()) { @@ -180,10 +183,13 @@ protected function registerLibraryFileStoredEvent(): void Media::created(function (Media $media): void { $model = $media->model; - if (! $model instanceof LibraryItem) { + $libraryItemModel = FilamentLibraryPlugin::libraryItemModelClass(); + + if (! is_object($model) || ! is_a($model, $libraryItemModel)) { return; } + /** @var LibraryItem $item */ $item = $model; if ($item->type !== 'file') { diff --git a/src/Middleware/RedirectToCorrectEditPage.php b/src/Middleware/RedirectToCorrectEditPage.php index 231cdb7..5154c89 100644 --- a/src/Middleware/RedirectToCorrectEditPage.php +++ b/src/Middleware/RedirectToCorrectEditPage.php @@ -5,7 +5,7 @@ use Closure; use Filament\Facades\Filament; use Illuminate\Http\Request; -use Tapp\FilamentLibrary\Models\LibraryItem; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; class RedirectToCorrectEditPage { @@ -27,7 +27,7 @@ public function handle(Request $request, Closure $next) $recordId = $request->route('record'); if ($recordId) { - $libraryItem = LibraryItem::find($recordId); + $libraryItem = FilamentLibraryPlugin::libraryItemModelClass()::find($recordId); if ($libraryItem) { // Redirect to the correct edit page based on type diff --git a/src/Models/LibraryItem.php b/src/Models/LibraryItem.php index 5ef3546..6219dbd 100644 --- a/src/Models/LibraryItem.php +++ b/src/Models/LibraryItem.php @@ -116,7 +116,9 @@ protected static function boot(): void */ public function parent(): BelongsTo { - return $this->belongsTo(LibraryItem::class, 'parent_id'); + $libraryItemModel = config('filament-library.models.LibraryItem', static::class); + + return $this->belongsTo($libraryItemModel, 'parent_id'); } /** @@ -124,7 +126,9 @@ public function parent(): BelongsTo */ public function children(): HasMany { - return $this->hasMany(LibraryItem::class, 'parent_id'); + $libraryItemModel = config('filament-library.models.LibraryItem', static::class); + + return $this->hasMany($libraryItemModel, 'parent_id'); } /** @@ -163,7 +167,7 @@ public function updater(): BelongsTo */ public function permissions(): HasMany { - return $this->hasMany(LibraryItemPermission::class); + return $this->hasMany(config('filament-library.models.LibraryItemPermission', LibraryItemPermission::class)); } /** @@ -637,7 +641,7 @@ public static function getGeneralAccessOptions(): array */ public function tags(): BelongsToMany { - return $this->belongsToMany(LibraryItemTag::class, 'library_item_tag_pivot') + return $this->belongsToMany(config('filament-library.models.LibraryItemTag', LibraryItemTag::class), 'library_item_tag_pivot') ->withTimestamps(); } diff --git a/src/Models/LibraryItemPermission.php b/src/Models/LibraryItemPermission.php index 96d48fe..57a4929 100644 --- a/src/Models/LibraryItemPermission.php +++ b/src/Models/LibraryItemPermission.php @@ -41,7 +41,7 @@ class LibraryItemPermission extends Model */ public function libraryItem(): BelongsTo { - return $this->belongsTo(LibraryItem::class); + return $this->belongsTo(config('filament-library.models.LibraryItem', LibraryItem::class)); } /** diff --git a/src/Resources/LibraryItemResource.php b/src/Resources/LibraryItemResource.php index f1d4f1d..5fd5549 100644 --- a/src/Resources/LibraryItemResource.php +++ b/src/Resources/LibraryItemResource.php @@ -20,6 +20,7 @@ use Filament\Schemas\Schema; use Filament\Tables; use Filament\Tables\Table; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Models\LibraryItem; use Tapp\FilamentLibrary\Resources\RelationManagers\LibraryItemPermissionsRelationManager; @@ -27,6 +28,14 @@ class LibraryItemResource extends Resource { protected static ?string $model = LibraryItem::class; + /** + * @return class-string + */ + public static function getModel(): string + { + return FilamentLibraryPlugin::libraryItemModelClass(); + } + protected static ?int $deletedParentId = null; protected static ?string $slug = 'library'; @@ -48,7 +57,7 @@ public static function getTenantOwnershipRelationshipName(): string return 'tenant'; } - return LibraryItem::getTenantRelationshipName(); + return static::getModel()::getTenantRelationshipName(); } public static function getNavigationIcon(): ?string @@ -318,7 +327,7 @@ public static function table(Table $table): Table ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() - ->visible(fn (): bool => auth()->user() && auth()->user()->can('deleteAny', LibraryItem::class)) + ->visible(fn (): bool => auth()->user() && auth()->user()->can('deleteAny', static::getModel())) ->successRedirectUrl(function () { // For bulk actions, redirect to current folder (maintain current location) $currentParent = request()->get('parent'); @@ -326,9 +335,9 @@ public static function table(Table $table): Table return static::getUrl('index', $currentParent ? ['parent' => $currentParent] : []); }), RestoreBulkAction::make() - ->visible(fn (): bool => auth()->user() && auth()->user()->can('restoreAny', LibraryItem::class)), + ->visible(fn (): bool => auth()->user() && auth()->user()->can('restoreAny', static::getModel())), ForceDeleteBulkAction::make() - ->visible(fn (): bool => auth()->user() && auth()->user()->can('forceDeleteAny', LibraryItem::class)) + ->visible(fn (): bool => auth()->user() && auth()->user()->can('forceDeleteAny', static::getModel())) ->successRedirectUrl(function () { // For bulk actions, redirect to current folder (maintain current location) $currentParent = request()->get('parent'); diff --git a/src/Resources/Pages/CreatedByMe.php b/src/Resources/Pages/CreatedByMe.php index ab0d021..5d44b13 100644 --- a/src/Resources/Pages/CreatedByMe.php +++ b/src/Resources/Pages/CreatedByMe.php @@ -4,7 +4,7 @@ use Filament\Resources\Pages\ListRecords; use Illuminate\Database\Eloquent\Builder; -use Tapp\FilamentLibrary\Models\LibraryItem; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Resources\LibraryItemResource; class CreatedByMe extends ListRecords @@ -19,7 +19,7 @@ protected function getTableQuery(): Builder $user = auth()->user(); if ($user) { - $personalFolder = LibraryItem::getPersonalFolder($user); + $personalFolder = FilamentLibraryPlugin::libraryItemModelClass()::getPersonalFolder($user); $query->where('created_by', $user->id); // Exclude personal folder if it exists diff --git a/src/Resources/Pages/EditFile.php b/src/Resources/Pages/EditFile.php index 0099f9f..fb32821 100644 --- a/src/Resources/Pages/EditFile.php +++ b/src/Resources/Pages/EditFile.php @@ -8,8 +8,7 @@ use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Illuminate\Support\Str; -use Tapp\FilamentLibrary\Models\LibraryItem; -use Tapp\FilamentLibrary\Models\LibraryItemTag; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Resources\LibraryItemResource; use Tapp\FilamentLibrary\Rules\UniqueTagName; @@ -68,7 +67,7 @@ public function form(Schema $schema): Schema ->validationAttribute('tag name'), ]) ->createOptionUsing(function (array $data): int { - $tag = LibraryItemTag::create([ + $tag = FilamentLibraryPlugin::libraryItemTagModelClass()::create([ 'name' => $data['name'], 'slug' => Str::slug($data['name']), ]); @@ -79,7 +78,7 @@ public function form(Schema $schema): Schema Select::make('general_access') ->label('General Access') ->options(function () { - $options = LibraryItem::getGeneralAccessOptions(); + $options = FilamentLibraryPlugin::libraryItemModelClass()::getGeneralAccessOptions(); // Remove inherit option if no parent folder if (! $this->getRecord()->parent_id) { diff --git a/src/Resources/Pages/EditFolder.php b/src/Resources/Pages/EditFolder.php index 8fa43bc..4744d67 100644 --- a/src/Resources/Pages/EditFolder.php +++ b/src/Resources/Pages/EditFolder.php @@ -7,8 +7,7 @@ use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Illuminate\Support\Str; -use Tapp\FilamentLibrary\Models\LibraryItem; -use Tapp\FilamentLibrary\Models\LibraryItemTag; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Resources\LibraryItemResource; use Tapp\FilamentLibrary\Rules\UniqueTagName; @@ -50,7 +49,7 @@ public function form(Schema $schema): Schema ->validationAttribute('tag name'), ]) ->createOptionUsing(function (array $data): int { - $tag = LibraryItemTag::create([ + $tag = FilamentLibraryPlugin::libraryItemTagModelClass()::create([ 'name' => $data['name'], 'slug' => Str::slug($data['name']), ]); @@ -61,7 +60,7 @@ public function form(Schema $schema): Schema Select::make('general_access') ->label('General Access') ->options(function () { - $options = LibraryItem::getGeneralAccessOptions(); + $options = FilamentLibraryPlugin::libraryItemModelClass()::getGeneralAccessOptions(); // Remove inherit option if no parent folder if (! $this->getRecord()->parent_id) { diff --git a/src/Resources/Pages/EditLink.php b/src/Resources/Pages/EditLink.php index e6728ba..f6ecf1c 100644 --- a/src/Resources/Pages/EditLink.php +++ b/src/Resources/Pages/EditLink.php @@ -7,8 +7,7 @@ use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Illuminate\Support\Str; -use Tapp\FilamentLibrary\Models\LibraryItem; -use Tapp\FilamentLibrary\Models\LibraryItemTag; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Resources\LibraryItemResource; use Tapp\FilamentLibrary\Rules\UniqueTagName; @@ -55,7 +54,7 @@ public function form(Schema $schema): Schema ->validationAttribute('tag name'), ]) ->createOptionUsing(function (array $data): int { - $tag = LibraryItemTag::create([ + $tag = FilamentLibraryPlugin::libraryItemTagModelClass()::create([ 'name' => $data['name'], 'slug' => Str::slug($data['name']), ]); @@ -66,7 +65,7 @@ public function form(Schema $schema): Schema Select::make('general_access') ->label('General Access') ->options(function () { - $options = LibraryItem::getGeneralAccessOptions(); + $options = FilamentLibraryPlugin::libraryItemModelClass()::getGeneralAccessOptions(); // Remove inherit option if no parent folder if (! $this->getRecord()->parent_id) { diff --git a/src/Resources/Pages/ListLibraryItems.php b/src/Resources/Pages/ListLibraryItems.php index db2cb43..86506f1 100644 --- a/src/Resources/Pages/ListLibraryItems.php +++ b/src/Resources/Pages/ListLibraryItems.php @@ -28,7 +28,7 @@ public function mount(): void $this->parentId = request()->get('parent'); if ($this->parentId) { - $this->parentFolder = LibraryItem::find($this->parentId); + $this->parentFolder = FilamentLibraryPlugin::libraryItemModelClass()::find($this->parentId); } } @@ -94,7 +94,7 @@ protected function getHeaderActions(): array ->placeholder('Enter folder name'), ]) ->action(function (array $data): void { - LibraryItem::create([ + FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $data['name'], 'type' => 'folder', 'parent_id' => $this->parentId, @@ -138,7 +138,7 @@ protected function getHeaderActions(): array $fileName = basename($filePath); // Create the library item - $libraryItem = LibraryItem::create([ + $libraryItem = FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $fileName, 'type' => 'file', 'parent_id' => $this->parentId, @@ -188,7 +188,7 @@ protected function getHeaderActions(): array ->placeholder('Optional description'), ]) ->action(function (array $data): void { - LibraryItem::create([ + FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $data['name'], 'type' => 'link', 'external_url' => $data['external_url'], diff --git a/src/Resources/Pages/MyLibrary.php b/src/Resources/Pages/MyLibrary.php index 69b29b8..16191a8 100644 --- a/src/Resources/Pages/MyLibrary.php +++ b/src/Resources/Pages/MyLibrary.php @@ -8,7 +8,7 @@ use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\ListRecords; use Illuminate\Database\Eloquent\Builder; -use Tapp\FilamentLibrary\Models\LibraryItem; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Resources\LibraryItemResource; class MyLibrary extends ListRecords @@ -24,7 +24,7 @@ protected function getTableQuery(): Builder // Show only the current user's personal folder and its contents $user = auth()->user(); if ($user) { - $personalFolder = LibraryItem::getPersonalFolder($user); + $personalFolder = FilamentLibraryPlugin::libraryItemModelClass()::getPersonalFolder($user); if ($personalFolder) { $query->where('parent_id', $personalFolder->id); @@ -75,9 +75,9 @@ protected function getHeaderActions(): array ]) ->action(function (array $data): void { $user = auth()->user(); - $personalFolder = LibraryItem::ensurePersonalFolder($user); + $personalFolder = FilamentLibraryPlugin::libraryItemModelClass()::ensurePersonalFolder($user); - LibraryItem::create([ + FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $data['name'], 'type' => 'folder', 'parent_id' => $personalFolder->id, @@ -103,11 +103,11 @@ protected function getHeaderActions(): array ]) ->action(function (array $data): void { $user = auth()->user(); - $personalFolder = LibraryItem::ensurePersonalFolder($user); + $personalFolder = FilamentLibraryPlugin::libraryItemModelClass()::ensurePersonalFolder($user); $filePath = $data['file']; $fileName = basename($filePath); - $libraryItem = LibraryItem::create([ + $libraryItem = FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $fileName, 'type' => 'file', 'parent_id' => $personalFolder->id, @@ -140,9 +140,9 @@ protected function getHeaderActions(): array ]) ->action(function (array $data): void { $user = auth()->user(); - $personalFolder = LibraryItem::ensurePersonalFolder($user); + $personalFolder = FilamentLibraryPlugin::libraryItemModelClass()::ensurePersonalFolder($user); - LibraryItem::create([ + FilamentLibraryPlugin::libraryItemModelClass()::create([ 'name' => $data['name'], 'type' => 'link', 'url' => $data['url'], diff --git a/src/Resources/RelationManagers/LibraryItemPermissionsRelationManager.php b/src/Resources/RelationManagers/LibraryItemPermissionsRelationManager.php index 580809a..4e4cc41 100644 --- a/src/Resources/RelationManagers/LibraryItemPermissionsRelationManager.php +++ b/src/Resources/RelationManagers/LibraryItemPermissionsRelationManager.php @@ -15,8 +15,8 @@ use Filament\Tables\Table; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Schema as SchemaFacade; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Models\LibraryItem; -use Tapp\FilamentLibrary\Models\LibraryItemPermission; class LibraryItemPermissionsRelationManager extends RelationManager { @@ -118,7 +118,7 @@ public function form(Schema $schema): Schema Forms\Components\Select::make('role') ->label('Role') - ->options(LibraryItemPermission::getRoleOptions()) + ->options(FilamentLibraryPlugin::libraryItemPermissionModelClass()::getRoleOptions()) ->required(), ]); } @@ -169,7 +169,7 @@ public function table(Table $table): Table ]) ->filters([ Tables\Filters\SelectFilter::make('role') - ->options(LibraryItemPermission::getRoleOptions()), + ->options(FilamentLibraryPlugin::libraryItemPermissionModelClass()::getRoleOptions()), ]) ->headerActions([ CreateAction::make() diff --git a/src/Rules/UniqueTagName.php b/src/Rules/UniqueTagName.php index ede38f5..404771b 100644 --- a/src/Rules/UniqueTagName.php +++ b/src/Rules/UniqueTagName.php @@ -5,7 +5,7 @@ use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Support\Str; use Illuminate\Translation\PotentiallyTranslatedString; -use Tapp\FilamentLibrary\Models\LibraryItemTag; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; class UniqueTagName implements ValidationRule { @@ -21,7 +21,8 @@ public function validate(string $attribute, mixed $value, \Closure $fail): void } $slug = Str::slug($value); - $existingTag = LibraryItemTag::where('slug', $slug)->first(); + $libraryItemTagModel = FilamentLibraryPlugin::libraryItemTagModelClass(); + $existingTag = $libraryItemTagModel::where('slug', $slug)->first(); if ($existingTag) { $fail('A tag with this name already exists.'); diff --git a/src/Services/PermissionService.php b/src/Services/PermissionService.php index a88a5bc..0708ff2 100644 --- a/src/Services/PermissionService.php +++ b/src/Services/PermissionService.php @@ -5,8 +5,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Models\LibraryItem; -use Tapp\FilamentLibrary\Models\LibraryItemPermission; class PermissionService { @@ -53,7 +53,7 @@ public function assignPermission($user, LibraryItem $item, string $permission): default => 'viewer', }; - LibraryItemPermission::updateOrCreate( + FilamentLibraryPlugin::libraryItemPermissionModelClass()::updateOrCreate( [ 'library_item_id' => $item->id, 'user_id' => $user->id, @@ -73,7 +73,7 @@ public function assignPermission($user, LibraryItem $item, string $permission): */ public function removePermission($user, LibraryItem $item, string $permission): void { - LibraryItemPermission::where([ + FilamentLibraryPlugin::libraryItemPermissionModelClass()::where([ 'library_item_id' => $item->id, 'user_id' => $user->id, ])->delete(); diff --git a/src/Traits/HasLibraryFavorites.php b/src/Traits/HasLibraryFavorites.php index faea2b8..beedc84 100644 --- a/src/Traits/HasLibraryFavorites.php +++ b/src/Traits/HasLibraryFavorites.php @@ -3,7 +3,7 @@ namespace Tapp\FilamentLibrary\Traits; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Tapp\FilamentLibrary\Models\LibraryItem; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; trait HasLibraryFavorites { @@ -12,7 +12,7 @@ trait HasLibraryFavorites */ public function favoriteLibraryItems(): BelongsToMany { - return $this->belongsToMany(LibraryItem::class, 'library_item_favorites') + return $this->belongsToMany(FilamentLibraryPlugin::libraryItemModelClass(), 'library_item_favorites') ->withTimestamps(); } } diff --git a/src/Traits/LibraryUser.php b/src/Traits/LibraryUser.php index df9868c..f0f24bb 100644 --- a/src/Traits/LibraryUser.php +++ b/src/Traits/LibraryUser.php @@ -3,6 +3,7 @@ namespace Tapp\FilamentLibrary\Traits; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Tapp\FilamentLibrary\FilamentLibraryPlugin; use Tapp\FilamentLibrary\Models\LibraryItem; /** @@ -15,7 +16,7 @@ trait LibraryUser */ public function personalFolder() { - return $this->belongsTo(LibraryItem::class, 'personal_folder_id'); + return $this->belongsTo(FilamentLibraryPlugin::libraryItemModelClass(), 'personal_folder_id'); } /** @@ -23,7 +24,7 @@ public function personalFolder() */ public function getPersonalFolder(): LibraryItem { - return LibraryItem::ensurePersonalFolder($this); + return FilamentLibraryPlugin::libraryItemModelClass()::ensurePersonalFolder($this); } /** @@ -31,7 +32,7 @@ public function getPersonalFolder(): LibraryItem */ public function favoriteLibraryItems(): BelongsToMany { - return $this->belongsToMany(LibraryItem::class, 'library_item_favorites') + return $this->belongsToMany(FilamentLibraryPlugin::libraryItemModelClass(), 'library_item_favorites') ->withTimestamps(); } diff --git a/tests/FilamentLibraryPluginTest.php b/tests/FilamentLibraryPluginTest.php new file mode 100644 index 0000000..90d6a56 --- /dev/null +++ b/tests/FilamentLibraryPluginTest.php @@ -0,0 +1,28 @@ +set('filament-library.models', [ + 'LibraryItem' => LibraryItem::class, + 'LibraryItemPermission' => LibraryItemPermission::class, + 'LibraryItemTag' => LibraryItemTag::class, + ]); + + expect(FilamentLibraryPlugin::modelClass('LibraryItem'))->toBe(LibraryItem::class) + ->and(FilamentLibraryPlugin::libraryItemModelClass())->toBe(LibraryItem::class) + ->and(FilamentLibraryPlugin::libraryItemPermissionModelClass())->toBe(LibraryItemPermission::class) + ->and(FilamentLibraryPlugin::libraryItemTagModelClass())->toBe(LibraryItemTag::class); +}); + +test('library item resource uses configured model class', function (): void { + config()->set('filament-library.models.LibraryItem', CustomLibraryItemStub::class); + + expect(LibraryItemResource::getModel())->toBe(CustomLibraryItemStub::class); +}); + +final class CustomLibraryItemStub extends LibraryItem {}