Automatic Routing
Created 10 months ago by ryanthompson

Something that is SUPER wasteful with resources and just not necessary.. the majority of our routing.

The idea here is to automate CRUD and define a best case for control panel routing. Here is my proposal:

admin/* // Engages automatic routing

admin/{slug} // Defines the module to use which will use same name stream for controller by default (pages/pages), otherwise first stream defined if none match the namespace/slug

admin/{slug}/{stream} // Defines the stream to access CRUD for based on the slug / namespace and the index method.

admin/{slug}/{stream}/{action} // Defines all as well as the controller action

Anything past this it will look into subdirectories, then a controller, then index method OR method if provided.

Let's open this up for discussion and point out any best cases you know of and pick it apart!

ryanthompson  —  3 months ago Best Answer

This is done and in 3.7 - HUGE thanks to you @frednwt thank you!

ryanthompson  —  10 months ago

https://pyrocms.com/forum/channels/roadmap/manual-loader

https://pyrocms.com/forum/channels/roadmap/automatic-routing

Just opened up a couple roadmap discussions on this. I can push up initial code I've got lying around at home later tonight if anyone is open to digging in and helping test / profile.

frednwt  —  10 months ago

I agree, it is how I build my admin routes usually (on custom app). I don't see any down for the admin part, and the manual routing can still be keep if needed.

ryanthompson  —  3 months ago

@frednwt care to share some code on how you handle route patterns to controllers?

frednwt  —  3 months ago

A very basic routing for that. I'm using a anonymous function but it should be move in a class (else it cannot be cached).

        $router->any(
            'admin/{module}/{stream?}/{action?}/{id?}',
            function ($module, $stream = null, $action = null, $id = null) use ($router) {
                if (!$module = app('module.collection')->get($module)) {
                    abort(404);
                } else {
                    $namespace = (new \ReflectionClass($module))->getNamespaceName();
                }

                if (!$stream) {
                    // TODO: How to make that generic?
                    $stream = 'contents';
                }

                $controller = vsprintf('%sController', [ucfirst($stream)]);

                if (!$action) {
                    $action = 'index';
                }

                $action = vsprintf('%s\Http\Controller\Admin\%[email protected]%s', [
                    $namespace,
                    $controller,
                    $action,
                ]);

                $route = $router->current();

                return $route
                    ->uses($action)
                    ->run();
            }
        );

The only thing we currently cannot guess is the default $stream if we are on the default route (e.g. /admin/contents).

frednwt  —  3 months ago

Note that mine is a bit more complex because I'm checking if the controller exists. If not I'm using a default controller with basic CRUB.

ryanthompson  —  3 months ago

@frednwt I think this might be best served somewhere earlier up the request chain right? (see last line here for my concern). Like near/in the kernel. But yes you'd have to check for a controller regardless - there will be two class checks I think. One for the literal path to class mapping. And one for the use case where stream == module so no stream would be listed in the URI.

I would also like to allow crawling into other controller directories like Admin/Api/Controller if the path indicated it..

So, is this routed first? Last? How do you deal with when the CRUD controller stuff already exists? I would assume this needs to be first.

frednwt  —  3 months ago

Right we can just stream == module. It may not be always true but it is probably the best. And maybe adding somewhere in the Module a $defaultStream = null that can be override if needed?

No idea how to manage other directories. It will be tricky. Maybe using some naming convention like /admin/contents/api-contents/create. But using another / will be complicated.

For the order, I'm currently routing it as last. To be sure no custom routes override. And my routing is more something like:

        $controller = vsprintf('%s\Http\Controller\Admin\%s', [
            $namespace,
            $controller,
        ]);

        if (!class_exists($controller)) {
            $controller = 'App\Http\Controller\Admin\BreadController';
        }

        $action = vsprintf('%[email protected]%s', [
            $controller,
            $action,
        ]);

Then every admin controllers extends the BreadController.

ryanthompson  —  3 months ago Best Answer

This is done and in 3.7 - HUGE thanks to you @frednwt thank you!

frednwt  —  3 months ago

You're welcome ;)