Skip to content

[NFR]: Initialize Router from Array (Similar to Config) #15050

Closed
@RayHughes

Description

@RayHughes

Request

It would be nice if Phalcon offered a native way to initialize the router component via an array in a similar manner that the config and providers are configured. The current implementation either requires passing around the DI and Router component or defining a file with broken references.

Reasons for Need

  • Practicality, easier to maintain and similar to other Phalcon patterns.
  • Separate files for different components, enabled.
  • Environment based route loading (feature flags).
  • Smooth integration with build, test, and sniffing tools.
  • Smooth integration with IDES. No broken references.
  • Reduce the need for file based loading if defined in a custom namespace. (require_once vs autoload)
  • Ability to collapse structure in IDE.

Work Around

Below is an extremely raw version of what has to be done to work around the feature request. (Done in 10 minutes for this NFR). By parsing over a data structure and dynamically building the Router Provider, we are able to dynamically build the $router->add() methods.

This method uses constants but in a real working version we should be able to set the config via an env file via a setter.

RouteConfig.php

<?php

namespace App\Config;

class RouteConfig
{
    const DYNAMIC = 'dynamic';
    const GET = 'get';
    const POST = 'post';
    const DELETE = 'delete';
    const PUT = 'put';
    const NOT_FOUND = 'notFound';

    const CONFIG = [
        'controllerName' => [
            [
                'route' => '/1',
                'type' => self::POST,
                'action' => 'actionName',
            ],
            [
                'route' => '/2/([0-9a-f-]+)',
                'type' => 'SELF::GET',
                'action' => 'actionName2',
                'params' => [
                    'param1' => 1,
               ],
           ],
        ],
    ];
}
<?php 

namespace App\Provider;

use App\Config\RouteConfig;

class RouterServiceProvider implements ServiceProviderInterface
{
    const ROUTE_METHOD =[
        RouteConfig::DYNAMIC => 'add',
        RouteConfig::GET => 'addGet',
        RouteConfig::POST => 'addPost',
        RouteConfig::DELETE => 'addDelete',
        RouteConfig::PUT => 'addPut',
        RouteConfig::NOT_FOUND => 'notFound',
    ];

    private Router $router;

    public function __construct()
    {
        $this->router = new Router(false);
    }

    public function register(DiInterface $di): void
    {
        foreach (RouteConfig::CONFIG as $controller => $routes) {
            $this->registerRoutes($controller, $routes);
        }

        $this->router->setDI($di);
        $this->router->removeExtraSlashes(true);
        $this->router->handle($_SERVER['REQUEST_URI']);

        $di->set('router', $this->router);
    }

    private function registerRoutes(string $controller, array $routes): void
    {
        foreach ($routes as $route) {
            $params = $route['params'] ?? [];
            $routeMethod = self::ROUTE_METHOD[$route['type']] ?? null;

            if ((!isset($route['action']) || !isset($route['route']) || is_null($routeMethod))) {
                throw new RuntimeException('Invalid Router Config');
            }

            $routeData = $this->mapRouteData($controller, $route['action'], $params);

            ($routeMethod !== RouteConfig::NOT_FOUND)
                ? $this->router->$routeMethod($route['route'], $routeData)
                : $this->router->notFound($routeData);
        }
    }

    private function mapRouteData(string $controller, string $action, array $params): array
    {
        $routeData = [
            'controller' => $controller,
            'action' => $action,
        ];

        return array_merge_recursive($routeData, $params);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementEnhancement to the framework

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions