RealMrHex / filament-modular

Modular support for FilamentPHP based on the popular nwidart/laravel-modules package.
https://filamentphp.com/plugins/realmrhex-modular
MIT License
54 stars 7 forks source link

php artisan module:make-filament-page get always generated in App\Filament namespace and folder #13

Open eelco2k opened 1 month ago

eelco2k commented 1 month ago

All commands work correctly except php artisan module:make-filament-page here the files will be placed into app/Filament/{choosen_panel}/Pages/

So for example i have created a Module called "Core"

and a panel generated as well with: php artisan module:make-filament-panel Core TestPanel

the command php artisan module:make-filament-page Core TestPage and selecting the TestPanel (which is in Modules/Core/Providers/Filament/Panels/TestPanelPanelProvider.php) to create it in that panel..

it generates a page in app/Filament/Core/Pages/TestPage.php and also with the wrong namespaces.

and not in the correct one: Modules/Core/Filament/Pages/TestPage.php

eelco2k commented 1 month ago

i think it has to do with the code in MakeModularPageCommand.php where if (empty($resource)) it tries to set the $path variable based on the Panel you selected. but if the Panel Provider which was created via the other command php artisan module:make-filament-panel Core TestPanel the discovery paths of pages/resources/widgets

->discoverResources(in: app_path('Filament/TestPanel/Resources'), for: 'App\\Filament\\TestPanel\\Resources')
->discoverPages(in: app_path('Filament/TestPanel/Pages'), for: 'App\\Filament\\TestPanel\\Pages')
->discoverWidgets(in: app_path('Filament/TestPanel/Widgets'), for: 'App\\Filament\\TestPanel\\Widgets')

which is not the modules package directory. but app directory.

Next if you dont even make a panel but you still want a filament-page in a module you cannot rely on those paths.

because this is a modules-filament page i assume the commands will generate the files 'always' in a module folder and not based on where the panel is located. So even with or without a selecting a panel you should then get the question whether you want to generate the page / resource / widget in at the same panels namespace or the modules namespace.

so concluding i think the part of the if( emtpy($resource)) { ... }

is not fully complete. and fills the variabels $namespace and $path incorrect.

eelco2k commented 1 month ago

i changed the code a bit and i think this should do the trick, if you can review this code and implement it, it would be nice!

MakeModularPageCommand.php (from line 103)

        if (!$panel) {
            $panels = Filament::getPanels();

            $panelOptions = array_map(
                fn (Panel $panel): string => $panel->getId(),
                $panels,

            );

            $selectedPanel = select(
                label: 'Do you want to create this page for a panel?',
                options: [true => 'Yes', false => 'No'],
                default: false,
            );

            if ($selectedPanel) {
                /** @var Panel $panel */
                $panel = (count($panels) > 1) ? $panels[select(
                    label: 'In which panel would you like to create this in?',
                    options: array_map(
                        fn (Panel $panel): string => $panel->getId(),
                        $panels,
                    ),
                    default: Filament::getDefaultPanel()->getId()
                )] : Arr::first($panels);

                $panelId = (string)str($panel->getId())->studly();
            }
        }

        if (empty($resource)) {
            if ($selectedPanel) {
                $pageDirectories = $panel->getPageDirectories();
                $pageNamespaces = $panel->getPageNamespaces();

                $pageModuleDirectory = $module->getPath() . "/Filament/$panelId/Pages/";
                $moduleNamespace = config('modules.namespace') . "\\{$module->getName()}\Filament\\$panelId\Pages";

                $namespace = (count($pageNamespaces) > 1)
                    ?
                    select(
                        label: 'Which namespace would you like to create this in?',
                        options: $pageNamespaces
                    )
                    : (Arr::first($pageNamespaces) ?? $moduleNamespace);
                $path = (count($pageDirectories) > 1)
                    ?
                    $pageDirectories[array_search($namespace, $pageNamespaces)]
                    : (Arr::first($pageDirectories) ?? $pageModuleDirectory);
            } else {
                $pageModuleDirectory = $module->getPath() . "/Filament/Pages/";
                $moduleNamespace = config('modules.namespace') . "\\{$module->getName()}\Filament\\Pages";

                $namespace = $moduleNamespace;
                $path = $pageModuleDirectory;
            }
        } else {
            if ($selectedPanel) {
                $resourceDirectories = $panel->getResourceDirectories();
                $resourceNamespaces = $panel->getResourceNamespaces();

                $resourceModuleDirectory = $module->getPath() . "/Filament/$panelId/Resources/";
                $moduleNamespace = config('modules.namespace') . "\\{$module->getName()}\Filament\\$panelId\Resources";

                $resourceNamespace = (count($resourceNamespaces) > 1)
                    ?
                    select(
                        label: 'Which namespace would you like to create this in?',
                        options: $resourceNamespaces
                    )
                    : (Arr::first($resourceNamespaces) ?? $moduleNamespace);
                $resourcePath = (count($resourceDirectories) > 1)
                    ?
                    $resourceDirectories[array_search($resourceNamespace, $resourceNamespaces)]
                    : (Arr::first($resourceDirectories) ?? $resourceModuleDirectory);
            } else {
                $resourceModuleDirectory = $module->getPath() . "/Filament/Resources/";
                $moduleNamespace = config('modules.namespace') . "\\{$module->getName()}\Filament\\Resources";

                $resourceNamespace = $moduleNamespace;
                $resourcePath = $resourceModuleDirectory;
            }
        }
eelco2k commented 1 month ago

I also changed the PanelProvider.stub a little bit to reflect on the app_path() --> to a module_path() discovery of resources, pages, clusters and widgets.

first you need to edit MakeModularPanelCommand.php

and on line: 62 add 'module' => $module_name, like so:

$this->copyStubToApp('PanelProvider', $path, [
            'class'     => $class,
            'directory' => str($id)->studly(),
            'id'        => $id,
            'module'    => $module_name,
            'namespace' => $moduleNamespace,
        ]);

then update stub like so:

PanelProvider.stub

<?php

namespace {{ namespace }};

use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;

class {{ class }} extends PanelProvider
{
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->id('{{ id }}')
            ->path('{{ id }}')
            ->login()
            ->colors([
                'primary' => Color::Amber,
            ])
            ->discoverClusters(in:module_path('{{ module }}') . '/Filament/{{ directory }}/Clusters', for: 'Modules\\{{ module }}\\Filament\\{{ directory }}\\Clusters')
            ->discoverResources(in: module_path('{{ module }}') . '/Filament/{{ directory }}/Resources', for: 'Modules\\{{ module }}\\Filament\\{{ directory }}\\Resources')
            ->discoverPages(in: module_path('{{ module }}') . '/Filament/{{ directory }}/Pages', for: 'Modules\\{{ module }}\\Filament\\{{ directory }}\\Pages')
            ->pages([
                Pages\Dashboard::class,
            ])
             ->discoverWidgets(in: module_path('{{ module }}') . '/Filament/{{ directory }}/Widgets', for: 'Modules\\{{ module }}\\Filament\\{{ directory }}\\Widgets')
            ->widgets([
                Widgets\AccountWidget::class,
                Widgets\FilamentInfoWidget::class,
            ])
            ->middleware([
                EncryptCookies::class,
                AddQueuedCookiesToResponse::class,
                StartSession::class,
                AuthenticateSession::class,
                ShareErrorsFromSession::class,
                VerifyCsrfToken::class,
                SubstituteBindings::class,
                DisableBladeIconComponents::class,
                DispatchServingFilamentEvent::class,
            ])
            ->authMiddleware([
                Authenticate::class,
            ]);
    }
}
RealMrHex commented 1 month ago

@eelco2k Hey, ill review your code in the next 48h and merge it asap. thanks

RealMrHex commented 1 month ago

@eelco2k and also, sorry for being too late, i was quite busy this week

eelco2k commented 1 month ago

@RealMrHex no worries, take your time.