Routing in a PHP application. Class example open

Routing in a PHP application. Class example

Approved. Code works!
This is exactly the working code that is verified by the moderator or site administrators
Tested: PHP 7

When a request to the server is received, it is primarily processed by the Router, which analyzes the url address and transmits the request to the desired controller, which can process it. If the controller is missing it shows a 404 or other error.

First of all we will create the table of routes which will consist of regular expressions. In the /config folder, create a new file that will contain a table of routes, call it routes.php

We will add to the file:

use core\Router;

//create a rule for the admin panel of our site. 
//If admin is found in the url then the controller from the admin folder will be activated. The fact that this request to the admin panel will indicate an additional parameter 'admin_prefix' => 'admin'
Router::add('^admin/?$', ['controller' => 'Main', 'action' => 'index', 'admin_prefix' => 'admin']);

//If the page is of type admin/somethings
//^(?P<controller>[a-z-]+)/(?P<action>[a-z-]+)/?$ - a regular expression in which variables controller and action will be passed
Router::add('^admin/(?P<controller>[a-z-]+)/?(?P<action>[a-z-]+)?$', ['admin_prefix' => 'admin']);


//['controller' => 'Main', 'action' => 'index'] - in the parameters specify the controller and action
Router::add('^$', ['controller' => 'Main', 'action' => 'index']);


//^(?P<controller>[a-z-]+)/(?P<action>[a-z-]+)/?$ - a regular expression in which the variables will be passed controller and action
Router::add('^(?P<controller>[a-z-]+)/(?P<action>[a-z-]+)/?$');

now we can connect our router to the main file /public/index.php to which all requests are sent:

require_once dirname(__DIR__) . '/config/routes.php';

We will also need to get the request url for the router. To do this, add the following code to the /vendor/core/app.php file:

$query = trim(urldecode($_SERVER['QUERY_STRING']), '/');
Router::dispatch($query);//pass our processed url to the dispatch method of the Router class

Now we can write the router class /vendor/core/Router.php

namespace core;

class Router
{
    //array in which the route table will be stored
    protected static array $routes = [];
    //the route being performed
    protected static array $route = [];

    //method to add to the route table
    public static function add($regexp, $route = [])
    {
        //take an array of all routes and add a new one with the key $regexp and route $route
        self::$routes[$regexp] = $route;
    }

    //method that will return all routes
    public static function getRoutes(): array
    {
        return self::$routes;
    }

    //the current route
    public static function getRoute(): array
    {
        return self::$route;
    }



    public static function dispatch($url)
    {
        //a method that will not take into account the get parameters in our url
        $url = self::removeQueryString($url);
        if (self::matchRoute($url)) {

            //create a route to our controller
            $controller = 'app\controllers\\' . self::$route['admin_prefix'] . self::$route['controller'] . 'Controller';//the name of the controllers will consist of the name + Controller
            //if the controller class exists
            if (class_exists($controller)) {//the controller is a class, so the class_exists function is suitable
                //create a new controller object
                $controllerObject = new $controller(self::$route);//transfer to the __constructor route which in the future we will need
                $controllerObject->get_Model();//call the model
                //add a method to our controller that will act as an action
                $action = self::lowerCamelCase(self::$route['action'] . 'Action');//the name Action will consist of the name + Action
                if (method_exists($controllerObject, $action)) {//Action is a method, so the method_exists function is suitable
                    $controllerObject->$action();//call our method Action in class
                } else {
                  //throw an exception if our controller does not have such a method
                    throw new \Exception("{$controller} {$action} not found", 404);
                }
            } else {
//if the controller is not found
                throw new \Exception("{$controller} not found      ", 404);
            }

        } else {
            throw new \Exception("Page not found", 404);
        }
    }
    
     // a method that will not take into account the get parameters in our url
     protected static function removeQueryString($url)
     {
         if ($url) {
             $params = explode('&', $url, 2);
             //if in url there is no character "=" we will take away / from the end
             if (false === str_contains($params[0], '=')) {
                 return rtrim($params[0], '/');
             }
         }
         return '';
     }

    // function that will compare the query with the regular expression template (/config/routes.php) and return true or false to matchRoute
    public static function matchRoute($url): bool
    {
        //paths are placed in the array $ routes, we will walk on it using a loop
        foreach (self::$routes as $pattern => $route) {

            if (preg_match("#{$pattern}#", $url, $matces)) {//# - regular expression template border
                foreach ($matches as $k => $v) {
                    // remove the extra elements from the array
                    if (is_string($k)) {
                        $route[$k] = $v;
                    }
                }
                //if no action
                if (empty($route['action'])) {
                    $route['action'] = 'index';
                }
                //if the admin prefix is removed
                if (!isset($route['admin_prefix'])) {
                    $route['admin_prefix'] = '';
                } else {
                    $route['admin_prefix'] = '\\';//required for namespace
                }
                //transform the names of our controllers into the CamelCase style
                $route['controller'] = self::upperCamelCase($route['controller']);
                
                return true;
            }
        }
        return false;
    }

    //a method that will translate our url to CamelCase for class naming
    protected static function upperCamelCase($name): string
    {
        return str_replace(' ', '', ucwords(str_replace('-', '', $name)));
    }

    //method which will translate action for naming of methods of classes in style camelCase for methods
    protected static function lowerCamelCase($name): string
    {
        return lcfirst(self::upperCamelCase($name));
    }

}
0

More

Leave a Reply

Your email address will not be published. Required fields are marked *

How many?: 22 + 22

lil-code© | 2022 - 2024
Go Top
Authorization
*
*
Registration
*
*
*
*
Password generation