Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
RayHughes opened this issue May 22, 2020 · 1 comment
Closed

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

RayHughes opened this issue May 22, 2020 · 1 comment
Labels
enhancement Enhancement to the framework

Comments

@RayHughes
Copy link

RayHughes commented May 22, 2020

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);
    }
}
@ruudboon ruudboon added the enhancement Enhancement to the framework label May 31, 2020
@ruudboon
Copy link
Member

Closing in favor of #14608 (comment) Will revisit if the community votes for it, or in later versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement to the framework
Projects
None yet
Development

No branches or pull requests

2 participants