Answer the question
In order to leave comments, you need to log in
PHP router class
Hello!
I register routes in the form of regular expressions.
Below is a router class and an example of routes.
Interested in:
1. How clumsy is it?
2. how unsafe is it?
3. how slow is it?
4. Is it worth doing this at all?
5. What do you recommend?
Router class.
<?php
class DRouter {
private function setMCA($urlData, $routes) {
$str = 'controller=site&action=error';
foreach(require $routes as $pattern => $route) {
if (preg_match('/'.addcslashes($pattern, '/').'/i', $urlData['path'])) {
$str = preg_replace('/' . addcslashes($pattern, '/') . '/i', $route, $urlData['path']);
break;
}
}
parse_str($str, $data);
D::app()->request = $data;
D::app()->request['module'] = (!empty($data['module'])) ? 'modules/'.$data['module'].'/' : '';
D::app()->request['controller'] = (!empty($data['controller'])) ? $data['controller'] : 'site';
D::app()->request['action'] = (!empty($data['action'])) ? $data['action'] : 'index';
unset($data,$str);
return $this;
}
public static function run($routes) {
$oi = new self();
$oi->setMCA(parse_url($_SERVER['REQUEST_URI']), $routes);
if (!class_exists(D::app()->request['controller'].'Controller'))
throw new DException('Страница не найдена', 404);
if (!method_exists(D::app()->request['controller'].'Controller', D::app()->request['action'].'Action'))
throw new DException('Страница не найдена', 404);
$oi->forward(D::app()->request['controller'], D::app()->request['action']);
}
public static function forward($controller='site', $action='index', $data=null) {
$controller = $controller.'Controller';
$action = $action.'Action';
$oi = new $controller();
$oi->$action($data);
if (method_exists($controller, 'run'))
$controller->run();
if (method_exists($controller, 'init'))
$controller->init();
}
}
<?php
return array(
'^/$' => 'controller=site&action=index',
'^/admin(?:/|)$' => 'module=admin&controller=site&action=index',
'^/admin/([a-z0-9]{1,15})(?:/|)$' => 'module=admin&controller=$1&action=index',
'^/admin/([a-z0-9]{1,15})/([0-9]{1,15})(?:/|)$' => 'module=admin&controller=$1&action=view&id=$2',
'^/admin/([a-z0-9]{1,15})/([a-z0-9]{1,15})(?:/|)$' => 'module=admin&controller=$1&action=$2',
'^/([a-z0-9]{1,15})(?:/|)$' => 'controller=$1&action=index',
'^/([a-z0-9]{1,15})/([0-9]{1,15})(?:/|)$' => 'controller=$1&action=view&id=$2',
'^/([a-z0-9]{1,15})/([a-z0-9]{1,15})(?:/|)$' => 'controller=$1&action=$2',
'^/([a-z0-9]{1,15})/([a-z0-9]{1,15})/([0-9]{1,15})(?:/|)$' => 'controller=$1&action=$2&id=$3',
'^(.*)$' => 'controller=site&action=error',
);
Answer the question
In order to leave comments, you need to log in
It's very sloppy. one class name "D" is already enough to understand that the code is going to be shitty.
This is not OOP code, don't be fooled, you don't need classes here. If you like static methods, write functions, because static methods are procedural programming.
Have you looked for existing turnkey solutions? Here's an example: symfony.com/doc/current/components/routing.html Spend
more time reading books, less time inventing what has already been invented hundreds of times.
I am currently using Symfony2, and the old projects are on a self-written
framework, where my own router is used, but I got
it somehow much simpler and works without problems, for example, a request:
example.com/bla
launch the Controller_Bla controller and the indexAction
example.com/bla/blum
action
Check if there is a Controller_Bla controller and a method blumAction in it
If not, then it will check if there is a Controller_Bla_Blum controller and an indexAction method in it
(the sequence may be different, it’s not the essence, it will be visible in the code)
The bottom line: I don’t write paths anywhere else.
If I created a Controller_Example and testAction in it (well, plus the framework checks the template for this action),
then the /example/test page appears automatically for me.
Here is the router code:
public static function run()
{
$obj = null;
$action = false;
$pathCtrl = TS_CODE_DIR . '/Controller/';
$classCtrl = 'Controller_';
$redirect = isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL'] : '';
if ( empty ($redirect) ) {
Ts_App::showMain();
}
$items = explode('/', $redirect);
$els = array();
for ($i=0; $i < count($items); $i++) {
if ( !empty($items[$i]) ) {
if ( !preg_match('/^[a-zA-Z0-9]+$/', $items[$i]) ) {
Ts_App::show404();
}
$els[] = ucfirst(strtolower($items[$i]));
}
}
$cnt = count($els);
for ($i=0; $i < $cnt; $i++) {
if ( $i < ($cnt - 1) ) {
$pathCtrl .= $els[$i] . '/';
$classCtrl .= $els[$i] . '_';
} else {
$pathCtrl .= $els[$i] . '.php';
$classCtrl .= $els[$i];
}
}
if ( file_exists($pathCtrl) && !is_dir($pathCtrl) ) {
$obj = new $classCtrl();
} else {
// проверка наличия экшна в родительском контроллере
preg_match('~(^.+)_([^_]+)$~', $classCtrl, $_crm);
if ( isset($_crm[1]) && isset($_crm[2]) ) {
$pathCtrl = preg_replace("~\/{$_crm[2]}\.php$~", '.php', $pathCtrl);
if ( file_exists($pathCtrl) ) {
$action = strtolower($_crm[2]);
$obj = new $_crm[1]();
}
}
}
if ( empty($obj) ) {
Ts_App::show404();
}
$obj->run($action);
}
Ts_App::run();
There is only one main mistake - stupid names. What else for DRouter and MCA?
Also, why are module/action parameters written to request? Also, what for to do unset local variables? Do you think the link counter will not reset without this? Also, implicit addcslashes must be replaced with explicit escaping of special characters - or replace the slashes limiting the regular with another character.
The code is so-so, but in popular frameworks it is about the same, so it will do.
I would make an index for an accelerated search for a route without a stupid enumeration of all regular expressions. It's so primitive.
Also, I don't understand where the trend to do HTTP redirects and responses through throwing exceptions came from. Who came up with this? Which pattern does this match?
I see '^(.*)$' => 'controller=site&action=error'
in the list of routes.
I see $str = 'controller=site&action=error'
in DRouter::setMCA.
Some of them are redundant. I would leave it in the routes and remove it from the setter.
if (!class_exists(D::app()->request['controller'].'Controller'))
throw new DException('Страница не найдена', 404);
if (!method_exists(D::app()->request['controller'].'Controller', D::app()->request['action'].'Action'))
throw new DException('Страница не найдена', 404);
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question