Beste Developers,

Ik zie vaak allemaal ingewikkelde routers tegen komen op internet.

Na even te zoeken kwam ik een vrij simpele router tegen hier op PHPHulp.

Wat is de reden van een uitgebreide moeilijke router? Na mijn mening is dit toch prima?

Enige probleem dat ik nu nog heb, is dat wanneer ik nu naar /artikel/bewerk/234/ dat hij de route /artikel/ pakt, hoe kan ik dit op de beste manier oplossen? Alles een prioriteit meegeven, sorteren op langste route? Wat is de beste manier hiervoor? Of gewoon een kwestie van de routes aanmaken in de goede volgorde?


<?php
class Router
{
    private $_routes;

    public function __construct()
    {
        $this->_routes = array();
    }

    public function setRoute( Route $route )
    {
        $this->_routes[] = $route;
    }

    public function match( $query )
    {
        $routes = $this->_routes;
        if( $routes )
        {
            foreach( $routes as $route )
            {
                $match = $route->match( $query );
                if( $match )
                {
                    return $match;
                }
            }
        }
        return false;
    }
}

class Route
{
    private $_regex;
    private $_controller;

    public function __construct( $pattern, $controller )
    {
        $this->_regex = preg_replace( '#:([a-z])+#','(?P<$1>[^/]+)', $pattern );
        $this->_controller = $controller;
    }

    public function match( $query )
    {
        if( !preg_match( '#'.$this->_regex.'#', $query, $matches ) )
        {
            return false;
        }

        $controller = new Controller();
        $controller->setName( $this->_controller );
        return $controller;
    }
}

class Controller
{
    private $_name;

    public function setName( $name )
    {
        $this->_name = $name;
    }
    public function getName()
    {
        return $this->_name;
    }
}

$router = new Router();
$router->setRoute( new Route( '/artikel/', 'article.view.module') );
$router->setRoute( new Route( '/artikel/bewerk/:id', 'article.edit.module') );
$router->setRoute( new Route( '/artikel/verwijder/:id', 'article.delete.module') );

$controller = $router->match( $request->server( 'REDIRECT_URL' ) );
?>


@Dos: Wat bedoel je precies?

@NOLot: Ik wacht even op wat een reactie van Wouter.

@Wouter: Wat ik eigenlijk bedoel is wanneer er geen match gevonden is, wil ik dat hij bijvoorbeeld een 404 pagina krijgt te zien. Dit zou dan een default route zijn?
Een constructor heeft als taak een object aan te maken. Daar kan je ook de $this eigenschappen een initiële waarde geven.
Een constructor heeft niet als taak dingen te returnen.

Zorg dus dat je nooooooit in een constructor iets returnt.


Het gaat om lijn 21 van FrontController
------
Edit:
Het hele concept van FrontController moet dus anders.
@Tom, en dat is dus niet een default route. Zodra de router geen match vindt retourneert hij false of gooit hij een exception (ik heb voorkeur voor dat laatste). Wanneer dit zo is roept de front controller de 404 controller aan.
Bedoel je dan zo iets?


<?php
/**
 * @author Tom Swinkels
 * @version v1.0 last edit on 09-09-2013
 */
class FrontController
{   
    public function execute( $requestUri )
    {
        $router = $this->getRouter();
        
        $route = $router->getRoute( $requestUri );
        if( $route ) 
        {
            $data = $route->getData();
            
            $controllerName = $data['controller'] . 'Controller';

            $controller = new $controllerName();
            $controller->$data['action']();
            return true;
        }
        else
        {
            //404 CONTROLLER??
        }
    }
    
    protected function getRouter()
    {
        $router = new Router();
        
        require_once( dirname(__FILE__) . '/../include/routes.inc.php' ); // laad routes

        return $router;
    }
}
?>


Wouter wat vindt jij er van om alles nog een op te splitsen naar een routerCompiler en routerMatcher?
oops, iets te vlug gereageerd

Ja, dat bedoel ik. Behalve dat de FrontController gewoon het hele request moet krijgen en niet alleen de URI. Want hoe kun je van buiten nou weten dat hij de URI nodig heeft? Je weet alleen dat hij informatie uit de Request nodig heeft.

Het gebruiken van een Compiler lijkt me niet nodig, het gebruiken van een UrlMatcher oid lijkt me wel een tof plan.
Dat gedeelte heb ik aangepast.

UrlMatcher kan altijd nog.

Er gaan op dit moment nog iets mis met de match hij matcht namelijk alles.


<?
    public function match( $query )
    {
        // ADD EXPESSION FOR MATCHING.
        $route = '#^' . $query . '$#';
        
        // CHECK FOR NUMERIC ROUTE
        $route = preg_replace( '/\<\#(.*?)\>/', '(?P<\1>[0-9]+)', $route );

        // CHECK FOR ALPHA NUMERIC ROUTE
        $route = preg_replace( '/\<\:(.*?)\>/', '(?P<\1>[A-Za-z0-9\-\_]+)', $route );

        if( preg_match( $route, $query, $matches ) )
        {
            return $route;
        }
        return false;
    }
?>


[size=xsmall]Toevoeging op 09/09/2013 23:45:31:[/size]

Probleem is opgelost.

Ik match de query met de query, maar ik moet natuurlijk de query matchen met de route.


<?
    public function match( $query )
    {
        // ADD EXPESSION FOR MATCHING.
        $route = '#^' . $this->_pattern . '$#';
        
        // CHECK FOR NUMERIC ROUTE
        $route = preg_replace( '/\<\#(.*?)\>/', '(?P<\1>[0-9]+)', $route );

        // CHECK FOR ALPHA NUMERIC ROUTE
        $route = preg_replace( '/\<\:(.*?)\>/', '(?P<\1>[A-Za-z0-9\-\_]+)', $route );

        if( preg_match( $route, $query, $matches ) )
        {
            return $route;
        }
        return false;
    }
?>


[size=xsmall]Toevoeging op 10/09/2013 00:11:10:[/size]

Wat ik nu nog mis is een Registry zoals hier http://phpro.org/tutorials/Model-View-Controller-MVC.html wordt beschreven.

Zouden jullie dit op de zelfde manier doen? Of is het een slecht voorbeeld?
Wat stel jij dan voor?

Verder had ik nog een vraagje over wanneer er geen route gevonden is.
Is het logisch om dan in de FrontController te bepalen dat er geen route gevonden is en dan een conytollrt aan te roepen die bijvoorbeeld een 404 error geeft?
De router is toch verantwoordelijk voor alle routes, het lijkt mij dus toch logisch om daarvoor een default route te maken?
-

Reageren