Thursday, February 2, 2017

Mapping multiple routes (controller) using a router

Leave a Comment

I am looking at danny vankooten router library here. This looks good (though not sure how will it handle project from medium to large, example an ecommerce site). Now, going by the example this is mapping

$router->map('GET','/', 'home.php', 'home'); $router->map('GET','/home/', 'home.php', 'home-home'); $router->map('GET','/plans/', 'plans.php', 'plans'); $router->map('GET','/about/', 'about.php', 'about'); $router->map('GET','/contact/', 'contact.php', 'contact'); $router->map('GET','/tos/', 'tos.html', 'tos'); 

Let say I have a scenario where my website has 20-30 static pages or near about 50 controllers with 2-3 action/method each.

How do I map them all. If I use the above method of mapping I will probably end up having more than 100 lines of mapping and this does not looks right.

I believe there should be a way or short cuts/wildcard like check if there is a page or controller available,then load it or else throw a 404.

How do I map all the routes the right way?.

PS. Giving out a bounty of 50 to anyone who is willing to answer on how to use the up said router using wildcard to match controller/method.

4 Answers

Answers 1

What you can do to lighten your router file is to move the route definition in a YAML file. You will still have many lines in your YAML but it will be more readable.

In your router.php file, use this code :

Don't forget to add the symfony YAML parser to your composer.json

use Symfony\Component\Yaml\Yaml; $yaml_file = 'routes.yaml'; $routes = Yaml::parse(file_get_contents($yaml_file)); foreach ($routes as $route_name => $params) {     $router->map($params[0],$params[1], $params[2].'#'.$params[3], $route_name); }   // match current request $match = $router->match(); 

Your file routes.yaml will look like this

index:      ["GET", "/", "home_controller", "display_item"] content:    ["GET", "/content/[:parent]/?[:child]?", "content_controller", "display_item"] article:    ["GET", "/article/[:page]", "article_controller", "display_item"] 

An other thing you can do to get smaller files is to separate your route definition in many small YAML files. For example, one for static files, one for admin area, one for front...

To do something like this, you have to change the router.php code to something like this :

use Symfony\Component\Yaml\Yaml; $yaml_files = ['front.yaml', 'static.yaml', 'admin.yaml']; foreach ($yaml_files as $yaml_file) {     $routes = Yaml::parse(file_get_contents($yaml_file));     foreach ($routes as $route_name => $params) {         $router->map($params[0],$params[1], $params[2].'#'.$params[3], $route_name);     }  }  // match current request $match = $router->match(); 

Danny Van Kooten also made PHP-Router which has a built-in support for YAML files. (If you look at the source code, you will see that he uses the Symfony parser so both methods are quite similar)

From the doc

YAML route definition

base_path: /blog  routes:   index: [/index, someClass.indexAction, GET]   contact: [/contact, someClass.contactAction, GET]   about: [/about, someClass.aboutAction, GET] 

Router.php

require __DIR__.'/vendor/autoload.php';  use PHPRouter\RouteCollection; use PHPRouter\Config; use PHPRouter\Router; use PHPRouter\Route;  $config = Config::loadFromFile(__DIR__.'/router.yaml'); $router = Router::parseConfig($config); $router->matchCurrentRequest(); 

Answers 2

in the library there is no function which do something like you wanted but there's an alternative way to do it, is to store those page on database by that you will have something like this below

//your query // "SELECT `method`, `route`, `page`, `name` FROM `static_pages` $pages = (query); //your executed query if(count($pages) > 0){   foreach($pages as $page){     $router->map($page['method'],$page['route'], $page['target'], (($page['name'] !== null || !empty($page['name']) ) ? $page['name'] : null));   } } 

I hope this helps

Answers 3

As part of the bootstrap phase tell your controllers to map themselves onto a router:

// bootstrap $router = new AltoRouter();  FooController::mapRoutes($router); BarController::mapRoutes($router); // etc. 

Each controller is allowed to produce however many routes it needs.

Answers 4

If you use a pre-built router like Silex you can do something like this:

$app->get('{route}', function($route) {     $dir = "/path/to/my/static/files/";     $file = $dir . $route . '.php';     if (file_exists($file)) {         require $file;     } else {         require '/path/to/custom/404.php';     } }); 

Note that Silex and many similar routers require routes to be by order of preference. When I need to use a router like this, I put it at the bottom so that it doesn't accidentally catch anything else.

Note that, if you want to build something like this custom, you can do this - keeping in mind I don't know what your code currently looks like or what logic you need - by substituting out your regular expression (in Silex's example, it is with curly brackets) and checking the $_SERVER['REQUEST_URI'] against your formulated regular expression.

If this is a custom application, you may not really need to over engineer this.

// routing class foreach ($routes as $route) {     if ($route != self::DEFAULT_ROUTE) {         // do your normal routing logic     } else {         // check if file exists (as with code above), else send to error 404     } } 

Then call with something like:

$router->map('GET',Router::DEFAULT_ROUTE, 'legacyRouter.php', 'legacy'); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment