diff --git a/src/Commands/MakeShieldGenerateCommand.php b/src/Commands/MakeShieldGenerateCommand.php index 3299e5b..1893b71 100644 --- a/src/Commands/MakeShieldGenerateCommand.php +++ b/src/Commands/MakeShieldGenerateCommand.php @@ -152,11 +152,11 @@ protected function generatablePages(): ?array return collect(FilamentShield::getPages()) ->filter(function ($page) { if ($this->excludePages) { - return ! in_array($page, $this->pages); + return ! in_array($page['class'], $this->pages); } if ($this->onlyPages) { - return in_array($page, $this->pages); + return in_array($page['class'], $this->pages); } return true; @@ -169,11 +169,11 @@ protected function generatableWidgets(): ?array return collect(FilamentShield::getWidgets()) ->filter(function ($widget) { if ($this->excludeWidgets) { - return ! in_array($widget, $this->widgets); + return ! in_array($widget['class'], $this->widgets); } if ($this->onlyWidgets) { - return in_array($widget, $this->widgets); + return in_array($widget['class'], $this->widgets); } return true; @@ -213,14 +213,14 @@ protected function generateForPages(array $pages): Collection { return collect($pages) ->values() - ->each(fn (string $page) => FilamentShield::generateForPage($page)); + ->each(fn (array $page) => FilamentShield::generateForPage($page['permission'])); } protected function generateForWidgets(array $widgets): Collection { return collect($widgets) ->values() - ->each(fn (string $widget) => FilamentShield::generateForWidget($widget)); + ->each(fn (array $widget) => FilamentShield::generateForWidget($widget['permission'])); } protected function resourceInfo(array $resources): void @@ -261,8 +261,8 @@ protected function pageInfo(array $pages): void collect($pages)->map(function ($page, $key) { return [ '#' => $key + 1, - 'Page' => Str::replace(config('filament-shield.permission_prefixes.page') . '_', '', $page), - 'Permission' => $page, + 'Page' => $page['class'], + 'Permission' => $page['permission'], ]; }) ); @@ -280,8 +280,8 @@ protected function widgetInfo(array $widgets): void collect($widgets)->map(function ($widget, $key) { return [ '#' => $key + 1, - 'Widget' => Str::replace(config('filament-shield.permission_prefixes.widget') . '_', '', $widget), - 'Permission' => $widget, + 'Widget' => $widget['class'], + 'Permission' => $widget['permission'], ]; }) ); diff --git a/src/FilamentShield.php b/src/FilamentShield.php index 54d2387..69e8ee3 100755 --- a/src/FilamentShield.php +++ b/src/FilamentShield.php @@ -8,6 +8,7 @@ use Filament\Support\Concerns\EvaluatesClosures; use Filament\Widgets\TableWidget; use Filament\Widgets\Widget; +use Filament\Widgets\WidgetConfiguration; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Lang; use Illuminate\Support\Str; @@ -124,28 +125,25 @@ public function getResources(): ?array } return collect($resources) - ->unique() - ->filter(function ($resource) { + ->reject(function ($resource) { if (Utils::isGeneralExcludeEnabled()) { - return ! in_array( + return in_array( Str::of($resource)->afterLast('\\'), Utils::getExcludedResouces() ); } - - return true; }) - ->reduce(function ($resources, $resource) { + ->mapWithKeys(function ($resource) { $name = $this->getPermissionIdentifier($resource); - $resources["{$name}"] = [ - 'resource' => "{$name}", - 'model' => Str::of($resource::getModel())->afterLast('\\'), - 'fqcn' => $resource, + return [ + $name => [ + 'resource' => "{$name}", + 'model' => Str::of($resource::getModel())->afterLast('\\'), + 'fqcn' => $resource, + ], ]; - - return $resources; - }, collect()) + }) ->sortKeys() ->toArray(); } @@ -195,16 +193,13 @@ public static function getPages(): ?array } return collect($pages) - ->filter(function ($page) { + ->reject(function ($page) { if (Utils::isGeneralExcludeEnabled()) { - return ! in_array(Str::afterLast($page, '\\'), Utils::getExcludedPages()); + return in_array(Str::afterLast($page, '\\'), Utils::getExcludedPages()); } - - return true; }) - ->reduce(function ($pages, $page) { - - $name = Str::of(class_basename($page)) + ->mapWithKeys(function ($page) { + $permission = Str::of(class_basename($page)) ->prepend( Str::of(Utils::getPagePermissionPrefix()) ->append('_') @@ -212,10 +207,13 @@ public static function getPages(): ?array ) ->toString(); - $pages["{$name}"] = "{$name}"; - - return $pages; - }, collect()) + return [ + $permission => [ + 'class' => $page, + 'permission' => $permission, + ], + ]; + }) ->toArray(); } @@ -224,13 +222,11 @@ public static function getPages(): ?array */ public static function getLocalizedPageLabel(string $page): string { - $object = static::transformClassString($page); - - $pageObject = new $object(); + $pageInstance = app()->make($page); - return $pageObject->getTitle() - ?? $pageObject->getHeading() - ?? $pageObject->getNavigationLabel() + return $pageInstance->getTitle() + ?? $pageInstance->getHeading() + ?? $pageInstance->getNavigationLabel() ?? ''; } @@ -249,16 +245,20 @@ public static function getWidgets(): ?array } return collect($widgets) - ->filter(function ($widget) { + ->reject(function ($widget) { if (Utils::isGeneralExcludeEnabled()) { - return ! in_array(Str::afterLast($widget, '\\'), Utils::getExcludedWidgets()); + return in_array( + needle: str( + static::getWidgetInstanceFromWidgetConfiguration($widget) + ) + ->afterLast('\\') + ->toString(), + haystack: Utils::getExcludedWidgets() + ); } - - return true; }) - ->reduce(function ($widgets, $widget) { - - $name = Str::of(class_basename($widget)) + ->mapWithKeys(function ($widget) { + $permission = Str::of(class_basename(static::getWidgetInstanceFromWidgetConfiguration($widget))) ->prepend( Str::of(Utils::getWidgetPermissionPrefix()) ->append('_') @@ -266,10 +266,13 @@ public static function getWidgets(): ?array ) ->toString(); - $widgets["{$name}"] = "{$name}"; - - return $widgets; - }, collect()) + return [ + $permission => [ + 'class' => static::getWidgetInstanceFromWidgetConfiguration($widget), + 'permission' => $permission, + ], + ]; + }) ->toArray(); } @@ -278,51 +281,18 @@ public static function getWidgets(): ?array */ public static function getLocalizedWidgetLabel(string $widget): string { - $class = static::transformClassString($widget, false); - - $widgetInstance = app()->make($class); + $widgetInstance = app()->make($widget); return match (true) { $widgetInstance instanceof TableWidget => (string) invade($widgetInstance)->makeTable()->getHeading(), ! ($widgetInstance instanceof TableWidget) && $widgetInstance instanceof Widget && method_exists($widgetInstance, 'getHeading') => (string) invade($widgetInstance)->getHeading(), - default => Str::of($widget) - ->after(Utils::getWidgetPermissionPrefix() . '_') + default => str($widget) + ->afterLast('\\') ->headline() ->toString(), }; } - protected static function transformClassString(string $string, bool $isPageClass = true): string - { - $pages = Filament::getPages(); - if (Utils::discoverAllPages()) { - $pages = []; - foreach (Filament::getPanels() as $panel) { - $pages = array_merge($pages, $panel->getPages()); - } - $pages = array_unique($pages); - } - - $widgets = Filament::getWidgets(); - if (Utils::discoverAllWidgets()) { - $widgets = []; - foreach (Filament::getPanels() as $panel) { - $widgets = array_merge($widgets, $panel->getWidgets()); - } - $widgets = array_unique($widgets); - } - - $prefix = Str::of($isPageClass ? Utils::getPagePermissionPrefix() : Utils::getWidgetPermissionPrefix())->append('_'); - - return (string) collect($isPageClass ? $pages : $widgets) - ->first(fn ($item) => class_basename($item) == Str::of($string)->after($prefix)->studly()); - } - - protected static function hasHeadingForShield(object | string $class): bool - { - return method_exists($class, 'getHeadingForShield'); - } - protected function getDefaultPermissionIdentifier(string $resource): string { return Str::of($resource) @@ -332,4 +302,11 @@ protected function getDefaultPermissionIdentifier(string $resource): string ->snake() ->replace('_', '::'); } + + protected static function getWidgetInstanceFromWidgetConfiguration(string | WidgetConfiguration $widget): string + { + return $widget instanceof WidgetConfiguration + ? $widget->widget + : $widget; + } } diff --git a/src/Resources/RoleResource.php b/src/Resources/RoleResource.php index 02d9202..792a071 100644 --- a/src/Resources/RoleResource.php +++ b/src/Resources/RoleResource.php @@ -319,55 +319,21 @@ public static function canGloballySearch(): bool public static function getResourceEntitiesSchema(): ?array { - if (blank(static::$permissionsCollection)) { - static::$permissionsCollection = Utils::getPermissionModel()::all(); - } + static::$permissionsCollection = static::$permissionsCollection ?: Utils::getPermissionModel()::all(); - return collect(FilamentShield::getResources())->sortKeys()->reduce(function ($entities, $entity) { - - $entities[] = Forms\Components\Section::make(FilamentShield::getLocalizedResourceLabel($entity['fqcn'])) - ->description(fn () => new HtmlString('' . Utils::showModelPath($entity['fqcn']) . '')) - ->compact() - ->schema([ - Forms\Components\CheckboxList::make($entity['resource']) - ->label('') - ->options(fn (): array => static::getResourcePermissionOptions($entity)) - ->live() - ->afterStateHydrated(function (Component $component, $livewire, string $operation, ?Model $record, Forms\Set $set) use ($entity) { - static::setPermissionStateForRecordPermissions( - component: $component, - operation: $operation, - permissions: static::getResourcePermissionOptions($entity), - record: $record - ); - - static::toggleSelectAllViaEntities($livewire, $set); - }) - ->afterStateUpdated(fn ($livewire, Forms\Set $set) => static::toggleSelectAllViaEntities($livewire, $set)) - ->selectAllAction(fn (FormAction $action, Component $component, $livewire, Forms\Set $set) => static::bulkToggleableAction( - action: $action, - component: $component, - livewire: $livewire, - set: $set - )) - ->deselectAllAction(fn (FormAction $action, Component $component, $livewire, Forms\Set $set) => static::bulkToggleableAction( - action: $action, - component: $component, - livewire: $livewire, - set: $set, - resetState: true - )) - ->dehydrated(fn ($state) => blank($state) ? false : true) - ->bulkToggleable() - ->gridDirection('row') - ->columns(FilamentShieldPlugin::get()->getResourceCheckboxListColumns()), - ]) - ->columnSpan(FilamentShieldPlugin::get()->getSectionColumnSpan()) - ->collapsible(); - - return $entities; - }, collect()) - ?->toArray() ?? []; + return collect(FilamentShield::getResources()) + ->sortKeys() + ->map(function ($entity) { + return Forms\Components\Section::make(FilamentShield::getLocalizedResourceLabel($entity['fqcn'])) + ->description(fn () => new HtmlString('' . Utils::showModelPath($entity['fqcn']) . '')) + ->compact() + ->schema([ + static::getCheckBoxListComponentForResource($entity), + ]) + ->columnSpan(FilamentShieldPlugin::get()->getSectionColumnSpan()) + ->collapsible(); + }) + ->toArray(); } public static function getResourceTabBadgeCount(): ?int @@ -445,8 +411,8 @@ public static function toggleSelectAllViaEntities($livewire, Forms\Set $set): vo public static function getPageOptions(): array { return collect(FilamentShield::getPages()) - ->flatMap(fn ($pagePermission) => [ - $pagePermission => FilamentShield::getLocalizedPageLabel($pagePermission), + ->flatMap(fn ($page) => [ + $page['permission'] => FilamentShield::getLocalizedPageLabel($page['class']), ]) ->toArray(); } @@ -454,8 +420,8 @@ public static function getPageOptions(): array public static function getWidgetOptions(): array { return collect(FilamentShield::getWidgets()) - ->flatMap(fn ($widgetPermission) => [ - $widgetPermission => FilamentShield::getLocalizedWidgetLabel($widgetPermission), + ->flatMap(fn ($widget) => [ + $widget['permission'] => FilamentShield::getLocalizedWidgetLabel($widget['class']), ]) ->toArray(); } @@ -479,8 +445,8 @@ protected static function getCustomEntities(): ?Collection }); $entitiesPermissions = $resourcePermissions - ->merge(FilamentShield::getPages()) - ->merge(FilamentShield::getWidgets()) + ->merge(collect(FilamentShield::getPages())->map(fn ($page) => $page['permission'])->values()) + ->merge(collect(FilamentShield::getWidgets())->map(fn ($widget) => $widget['permission'])->values()) ->values(); return static::$permissionsCollection->whereNotIn('name', $entitiesPermissions)->pluck('name'); @@ -496,4 +462,31 @@ public static function bulkToggleableAction(FormAction $action, Component $compo static::toggleSelectAllViaEntities($livewire, $set); }); } + + public static function getCheckBoxListComponentForResource(array $entity): Component + { + $permissionsArray = static::getResourcePermissionOptions($entity); + + return Forms\Components\CheckboxList::make($entity['resource']) + ->label('') + ->options(fn (): array => $permissionsArray) + ->live() + ->afterStateHydrated(function (Component $component, $livewire, string $operation, ?Model $record, Forms\Set $set) use ($permissionsArray) { + static::setPermissionStateForRecordPermissions( + component: $component, + operation: $operation, + permissions: $permissionsArray, + record: $record + ); + + static::toggleSelectAllViaEntities($livewire, $set); + }) + ->afterStateUpdated(fn ($livewire, Forms\Set $set) => static::toggleSelectAllViaEntities($livewire, $set)) + ->selectAllAction(fn (FormAction $action, Component $component, $livewire, Forms\Set $set) => static::bulkToggleableAction($action, $component, $livewire, $set)) + ->deselectAllAction(fn (FormAction $action, Component $component, $livewire, Forms\Set $set) => static::bulkToggleableAction($action, $component, $livewire, $set, true)) + ->dehydrated(fn ($state) => ! blank($state)) + ->bulkToggleable() + ->gridDirection('row') + ->columns(FilamentShieldPlugin::get()->getResourceCheckboxListColumns()); + } }