Structuring the PHP Router class with MVC

Asked

Viewed 6,771 times

8

A friendly url of the type:

www.meusite.com.br/controlador/metodo/argumentos

Is treated in my class Request, where I "explode" the url, separating it into segments, which are respectively, $controller, $action and $args, who will be returned to my class Route, where the application’s "routing" is done. So far Ok.

Problem

The problem is that you simply add a subdirectory. (So I get all worked up, because I’m a beginner in PHP applications with MVC, mainly in the concepts of classes Route and Request).

Directory structure

Hierarquia de diretórios da aplicação

What is "picking up" is that, as I described the process in the first paragraph, the application will work perfectly without the subdirectories Usr and Adm, having only the following hierarchy.

Hierarquia de diretórios da aplicação, eliminando os subdiretórios Usr e Adm

For the whole process is in accordance with the Router and the Request.

Class Router

class Router
{
    public static function run(Request $request)
    {
        $controller= $request->getController();
        $action= $request->getAction();
        $args = (array) $request->getArgs();
        $controller = 'Application\Controller\\' . ucfirst($controller);
        $controller = new $controller();
        if (!is_callable(array($controller, $action))) {
            // Algum comando.
        }
        call_user_func_array(array($controller, $action), $args);
    }
    // Mais métodos

}

The above code is responsible for the inclusion of Controllers and the call to methods based on what was returned by Request. (this one doesn’t have much code, so I’ll just put the section that deals with the url)

Request

public function __construct()
{
    if (!isset($_GET["url"])) return false;

    $segments = explode("/", $_GET["url"]);
    $this->controller = ($controller = array_shift($segments)) ? $controller : "index";
    $this->action = ($action = array_shift($segments)) ? $action : "main";
    $this->args = (is_array($segments[0])) ? $segments : array();
}

Question

I would like to know what changes I should make to both codes so that a call to a controller, in any of the subdirectories, can be made successfully through the following format: url

www.meusite.com.br/nome_do_subdiretorio/controlador/metodo/argumentos

I apologize for the size of the question, but I tried to make it complete rsrs

Update

Controller Index

Exemplifying with this controller, it would be the standard, case a url came as follows: www.meusite.com.br/nome_do_subdominio/

namespace Application\Adm\Controller;

use MamutePost\Controller;

class Index extends Controller
{
    // ... Métodos
}

Mamutepost is a folder inside Vendor where I put my "mini-framework", which I developed to work with MVC.

  • I remember the headaches I went through when I tried to develop my own route solution, until the moment I started working with symfony then much of my problems were gone, I’m not looking to go public, but if you want to know more about it, my advice. I once did a job where the customer complained of synfony being too big for something respectively simple, the advantage is that it allows the installation of the components separately. The reference for the route component http://symfony.com/doc/current/components/routing/introduction.html

  • @kabstergo Thanks for the comment and I really believe that both symfony, or some other framework will handle the issue of routes very well, including I will take a look yes on the link, but for now I am looking for a solution without using framework. rs

  • without problems, could post the code of a controller? but specifically I mean the namespace from it, considering the first example you gave I believe your controller would be located in the namespace Application\Controller\Nome in the second case with the subfolders the namespace has changed to Application\Pasta\Controller\Nome?

  • @kabstergo I will update :)

1 answer

5


Well initially I would change your class Request because just as it’s programmed, it makes the route identification mechanism very static for just that situation. Note how the simple class below makes it possible to identify generic routes according to a regular expression.

class Router {

  private static $routes = array();

  private function __construct() {}
  private function __clone() {}

  public static function route($pattern, $callback) {
    $pattern = '/^' . str_replace('/', '\/', $pattern) . '$/';
    self::$routes[$pattern] = $callback;
  }

  public static function execute($url) {
    foreach (self::$routes as $pattern => $callback) {
      if (preg_match($pattern, $url, $params)) {
        array_shift($params);
        return call_user_func_array($callback, array_values($params));
      }
    }
  }
}

this way you record the routes of your application and use the callback function to make the call to the due controller:

//registro da rota http://www.meusite.com.br/index/main
Router::route('http://www.meusite.com.br/index/main', function(){
  print "Application\Index\Main" . "<br/>";
});

//registro da rota http://www.meusite.com.br/nome_do_subdiretorio/controlador/metodo/argumentos
Router::route('http://www.meusite.com.br/(\w+)/(\w+)/(\w+)/(\w+)', function($folder, $controller, $action, $args){
  print "Application\\" . $folder . "\\" . $controller . "<br/>";
});

thus requester would be in charge of only calling the route class by passing the url in question:

Router::execute("http://www.meusite.com.br/index/main");
Router::execute("http://www.meusite.com.br/nome_do_subdiretorio/controlador/metodo/argumentos");

a clean, simple and efficient approach to a basic route system credits: http://upshots.org/php/php-seriously-simple-router

  • I will test this solution.

  • Thanks, functional script, now I will complete some features and put on my system.

  • @Thomersonroncally cool and good luck on your projects.

  • Interestingly, where would I leave the routes? on the index? that I didn’t understand.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.