Een simpele URL rewriter maken

Door Pieter Jansen, 5 jaar geleden, 9.698x bekeken

Een simpele, doch effectieve manier om URL`s te herschrijven. Een klein beetje HTACCESS en een simpele URL class.

Let wel: de klasse die ik gemaakt heb, is niet verplicht. Het kan ook procedureel. Maar om toch OO te leren aan de mensen die hier belang bij hebben, heb ik er een klasse van gemaakt.

Gesponsorde koppelingen

Inhoudsopgave

  1. HTACCES gebruiken
  2. De index.php maken
  3. De URL class schrijven
  4. De URL class af maken
  5. Ter afsluiting de code

 

Er zijn 36 reacties op 'Een simpele url rewriter maken'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Ronald Van Zon
Ronald Van Zon
5 jaar geleden
 
0 +1 -0 -1
He mooie tutorial!
Erg uitgebreid en duidelijk voor iemand die voor het eerst URL rewrite gaat gebruiken.

om een vraag van jou te beantwoorden:
'Ik weet niet eens of een private constructor wel werkt in PHP... Anyone?'

dit werkt! word ook wel singleton patroon genoemd.
google het en je krijgt zat voorbeelden, het is aan te raden om in de DB class het te gebruiken.
- Aar  -
- Aar -
5 jaar geleden
 
0 +1 -0 -1
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

class UrlDispatcher
{
  private $Uri;
  private $nodes;
  private $firstNode;
  private $lastNode;
  private $root;

public function UrlDispatcher ()
{

  // body van de constructor
}

}

?>

Wat is er mis met de constructor

__constructor() ?
Pim -
Pim -
5 jaar geleden
 
1 +1 -0 -1
Drie dingen:
- Waarom niet met HTAccess de query in een GET param meegeven? Scheelt je dat gedoe met PHP_SELF:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?rt=$1 [L,QSA]

- Waarom maak je geen mogelijkheid een zelf opgegeven string te parsen?

- Wat doet je klasse nou eigenlijk voor nuttigs buiten het volgende?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<?php $parts = explode('/', trim($string, '/')); ?>


Wat vaak gebruikt wordt in dit soort situaties is een router, die kijkt of verschillende routes passen op de string. Wanneer dit het geval is, parsed zo'n route de string en haalt er data uit als de aan te roepen actie en eventueel parameters.
Karl Karl
Karl Karl
5 jaar geleden
 
0 +1 -0 -1
Ik vind hem niet echt mooi. Ben het dus ook voornamelijk eens met Pim's punten. Verder vraag ik mij ook af waarom je al je functies public hebt gemaakt. Je wilt eigenlijk al je constructor private hebben, maar volgens mij zou je eigenlijk ook een aantal methodes private willen hebben (mag iets van buitenaf de laatste en eerste node instellen?).
Ook zijn die optionele en die eerste en laatste node variabelen een beetje onzinnig. Als je bij spl had gekeken had je vast wel iets leuks gevonden, waarmee je een object als array had kunnen laten voordoen.
Verder vraag ik mij ook af waarom je nu nog met php4 aan komt zetten (zie die constructor vraag van Aar).
Ook heb ik nog een opmerking t.a.v. Ronald Van Zon men gebruikt wel vaak en snel een singleton. Je moet dus goed kijken of dat wel per se nodig is.
Het idee van een singleton is dat je maar precies één bepaald object kan hebben. Zou je in dit geval dan dus een signleton nodig hebben? Niet echt, want waar zou je nog meer deze klasse moeten aanroepen? Alleen in het begin.
Verder zijn er ook nog wel wat andere opmerkingen.
Ronald Van Zon
Ronald Van Zon
5 jaar geleden
 
0 +1 -0 -1
Karl karl, ik gaf alleen antwoord op z'n vraag.
'Ik weet niet eens of een private constructor wel werkt in PHP... Anyone?'
Dit werkt natuurlijk gewoon maar om die class aan te roepen mag je hem niet direct laden. Dit principe word singleton genoemd. Ik zeg niet dat je het blind moet gebruiken dat is totaal aan jezelf of het nuttig is of niet.
Karl Karl
Karl Karl
5 jaar geleden
 
0 +1 -0 -1
Een singleton is dus niet per definitie een klasse met private constructor. Een singleton heeft alleen maar een private constructor om te zorgen dat de compiler bij bijvoorbeeld bij java en C# geen public constructor toevoegt en dus dat er niet zomaar een instantie van een klasse kan gemaakt worden door new Object(); te doen.
Pieter Jansen
Pieter Jansen
5 jaar geleden
 
0 +1 -0 -1
@Ronald: Bedankt voor die informatie! Ik ken het singleton principe wel, maar dat is een self invoking object. Ofwel het blijft een object. Wat ik bedoelde te zeggen is dat je een constructor ook private kan maken zodat het juist niet geinstantieerd kan worden. Abstracte klasses alsook statische klasses.

@Aar: Je hebt gelijk, __constructor() werkt ook, maar waarom zou je dat gebruiken? Nu werkt het in zowel PHP4 alsook 5.

Bijkomend iets is dat je een regel hanteert dat de constructor over het algemeen de naam de klasse mee geeft. Denk maar aan java of C#.

Waarom de setters publiek maken? In dit geval totaal overbodig!

Waarom de PHP_SELF gebruiken? Omdat ik nu 10 parameters mee kan geven zonder dat ik continu mijn HTACCESS loop aan te passen.

Over het hele OO verhaal, ik heb al aangegeven dat het eigenlijk vrij weinig voorstelt, dat het niet in een klasse hoeft, maar om mensen die niet bekend zijn met OO toch maar in gezet.

Oh 1 klein ding nog: een klasse moet slechts 1 ding doen, en dat ene ding heel goed. Je kunt deze klasse wel flink uitbreiden, maar goed OO design houdt in dat je alles zo veel mogelijk los haalt van elkaar. Dus ja, deze klasse doet niet bijzonder veel, maar dat hoeft ook niet
Karl Karl
Karl Karl
5 jaar geleden
 
0 +1 -0 -1
Merijn Venema 7 minuten geleden:
Waarom de setters publiek maken? In dit geval totaal overbodig!

Waarom doe je dat dan wel?

Merijn Venema 7 minuten geleden:
Waarom de PHP_SELF gebruiken? Omdat ik nu 10 parameters mee kan geven zonder dat ik continu mijn HTACCESS loop aan te passen.

Kijk eens naar hoe bijvoorbeeld cakephp het doet en welke flags je aan je htacces kan meegeven.
Ik gebruik ook maar één parameter naar mijn index.php toe, maar toch kan ik velen parameters opgeven.
Pieter Jansen
Pieter Jansen
5 jaar geleden
 
0 +1 -0 -1
Omdat je wil dat ze private worden, maak ik ze private voor je :)

Jij ook weer blij, voor de werking blijft het gewoon hetzelfde, maar dan is dat uit de weg!

Over het CakePHP voorbeeld, daar ben ik om eerlijk te zijn niet bekend mee. Ik dacht: laat ik een URL dispatcher schrijven als tutorial. Iets waar VEEL mensen altijd vragen over hebben. Dat er meer wegen naar Rome leiden is me wel bekend, maar deze methode moet ook goed werken.
Ronald Van Zon
Ronald Van Zon
5 jaar geleden
 
0 +1 -0 -1
We moeten natuurlijk niet vergeten dat het om een simpel URL rewritter gaat. Natuurlijk kan het zo complex worden als we willen! Voor een beginners tutorial vind ik hem goed gedaan.
Misschien helpt dit mensen om een 'clean-url' te gebruiken.
Karl Karl
Karl Karl
5 jaar geleden
 
0 +1 -0 -1
Merijn:
Omdat je wil dat ze private worden, maak ik ze private voor je :)


Jij ook weer blij, voor de werking blijft het gewoon hetzelfde, maar dan is dat uit de weg![/quote]
Waarom ga je het dan over visibility hebben als je er toch niks mee doet? De code blijft misschien wel hetzelfde functioneren (als je alles aan zou kunnen roepen), maar dat is dus niet het idee van visibility.
Bovendien gebruiken n00bs simpele dingen als voorbeelden. Dit is een simpel ding, dus gaan ze dat waarschijnlijk wel als voorbeeld gebruiken. Dan moet je het niet verkeerd gaan doen.

Eigenlijk had je er gewoon beter geen klasse van kunnen maken.
Pieter Jansen
Pieter Jansen
5 jaar geleden
 
0 +1 -0 -1
Nee, ik heb er ook al spijt van dat ik dat gedaan heb :D

Maar waar ik wel over hekel is dat jullie aannemen dat ik er een singleton van wil maken. Nergens in de code valt er te lezen dat ik er een singleton van wil maken, was alleen nieuwsgierig of PHP ook een private constructor accepteert.

Verder worden er continu dingen aangenomen, als het niet in de tekst staat.. trek je conclusies ;0
Pim -
Pim -
5 jaar geleden
 
0 +1 -0 -1
@Karl, niets mis met simpele, maar goede voorbeelden.

Niet om mezelf te prijzen, maar zo zou ik het doen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
interface Route
{
    public function isMatch($query);
    public function process($query);
}


class RegexRoute implements Route
{
    protected $regex;
    protected $defaults;
    protected $results;

    public function __construct($regex, array $defaults = array())
    {

        $this->regex = $regex;
        $this->defaults = $defaults;
    }


    public function isMatch($query)
    {

        return preg_match($this->regex, $query, $this->results);
    }


    public function process($query)
    {

        // Verwijder hele match, we willen alleen parameters
        array_shift($this->results);
        
        // Mix met defaults
        return array_merge($this->defaults, $this->results);
    }
}


class Router
{
    protected $routes = array();

    public function addRoute(Route $route)
    {

        $this->routes[] = $route;
    }


    public function process($query)
    {

        foreach($this->routes as $route)
            if($route->isMatch($query))
                return $route->process($query);

        throw new NoRouteFoundException;
    }
}


$router = new Router;
$router->addRoute(
    new
RegexRoute('regex', array('controller'=>'HomeController'))
);

$data = $router->process( $_GET['route'] );
?>

Zal vast tikfouten bevatten
Karl Karl
Karl Karl
5 jaar geleden
 
0 +1 -0 -1
Pim, dat zeg ik, de voorbeelden moeten goed zijn. En dat is / was het nu niet.
Pieter Jansen
Pieter Jansen
5 jaar geleden
 
0 +1 -0 -1
LOL, geen woorden voor. Ik neem aan dat je wel snapt wat ik bedoel. En dat heeft niets met de foute code te maken die je gepost hebt, Pim :)
Pim -
Pim -
5 jaar geleden
 
0 +1 -0 -1
Hmm 1 haakje en een keer this vergeten, vrij goede score.

Maar verder wou ik je slechts laten zien hoe het ook kan. Je opmerking begrijp ik niet helemaal...
Niels Kieviet
Niels Kieviet
5 jaar geleden
 
0 +1 -0 -1
Waarom mis ik nu altijd PHPDoc?

Toevoeging op Pim

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php

/**
 * Interface.php. Dit bestand bevat alle interfaces die in de package Router thuishoren.
 * De interfaces in de package Router zorgen ervoor dat afgedwongen wordt hoe een URL afgehandeld dient te worden.
 *
 * @package Router
 * @throws RouterException
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v.100$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/exception.php';

/**
 * Deze interface zorgt ervoor dat wordt afgedwongen hoe een Router eruit dient te zien.
 */

interface Router
{
    /**
     * Methode om de route en die actie bij de opgegeven URL te vinden.
     *
     * @param String $url De URL waarbij een route en een actie gevonden moet worden.
     * @return String De actie die bij de route hoort.
     */

    public function find( $url );
}


/**
 * De Route interface dwingt een specifieke Route af die door de Router gebruikt kan worden
 * om een actie te bepalen bij een bepaalde URL. De Router houdt een Array bij en loopt de Array
 * met Routes door totdat een passende Route is gevonden.
 */

interface Route
{
    /**
     * Methode om te controleren of de actie van deze Route bij de URL hoort.
     *
     * @param String $url De URL Die gecontroleerd moet worden.
     * @return String De actie, NULL als er geen actie gevonden is.
     */

    public function control( $url );
}


/**
 * De Dispatcher interface zorgt ervoor dat die Actie die door
 * de Router is ontdekt uitgevoerd wordt.
 */

interface Dispatcher
{
    /**
     * Deze methode zorgt ervoor dat de Action uitgevoerd wordt.
     *
     * @param String $action De actie die uitgevoerd dient te worden.
     * @return Void
     */

    public function dispatch( $action );
}


/**
 * De Action interface. Een actie is een specifieke actie binnen de website.
 * Op een pagina kunnen meerdere acties uitgevoerd worden. Doormiddel
 * van de Dispatcher worden Actions gekoppeld aan de URL's
 */

interface Action
{
    /**
     * Methode om de actie uit te voeren
     *
     * @return Void
     */

    public function dispatch( );
}


?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php

/**
 * Router. Dit bestand bevat alle klassen die in het Router package horen.
 * De klassen in de router klassen zorgen ervoor dat de URL opgevangen wordt
 * in een specifieke actie en vervolgens wordt omgeleid naar een specifieke handeling.
 *
 * @package Router
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v.100$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/exception.php';
require_once dirname( __FILE__ ) . '/interface.php';

/**
 * De DefaultRouter klasse is de standaart versie van de Router.
 * De DefaultRouter zoekt met behulp van specifieke Route klassen naar de juiste
 * actie bij een URL.
 */

class DefaultRouter implements Router
{
    /**
     * Een Array met alle routes
     *
     * @var Array
     */

    private $routes = array( );
    
    /**
     * Methode om een route aan de Router toe te voegen. De routes worden
     * gebruikt om de juiste Action bij de URL te vinden.
     *
     * @param Route $route De nieuwe route
     * @return Void
     */

    public function add( Route $route )
    {

        $this->routes[] = $route;
    }

    
    /**
     * Methode om de route en die actie bij de opgegeven URL te vinden.
     *
     * @param String $url De URL waarbij een route en een actie gevonden moet worden.
     * @return String De actie die bij de route hoort.
     */

    public function find( $url )
    {

        $action = null;
        $i = 0;
        while( $i < count( $this->routes ) && $action == null ) {
            $action = $this->routes[$i]->control( $url );
            $i++;
        }

        return $action;
    }
}

?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
 
/**
 * Router. Dit bestand bevat alle klassen die in het Router package horen.
 * De klassen in de router klassen zorgen ervoor dat de URL opgevangen wordt
 * in een specifieke actie en vervolgens wordt omgeleid naar een specifieke handeling.
 *
 * @package Router
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v.100$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */

/**
 * De RouterException klasse. De RouterException klasse is een extentie van de standaart
 * Exception klasse en wordt gebruikt om fouten die optreden tijdens het gebruik van de URL afhandeling
 * naar voren te brengen.
 *
 * De RouterException klasse is gemaakt om het mogelijk te maken om in een try catch blok
 * het verschil te maken tussen een normale Exception en een RouterException
 */

class RouterException extends Exception { }
?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

/**
 * static.route.php. Dit bestand bevat alle klassen die in de subpackage Route van de package Router horen.
 * De klassen in de package Route zorgen ervoor dat de URL opgevangen
 * wordt in een centrale klasse en dat deze vervolgens omgeleid wordt naar
 * een specifieke actie uit de Action package
 *
 * @package Router
 * @subpackage Route
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v1.00$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/interface.php';

/**
 * De StaticRoute klasse is een Route die de URL direct vergelijkt met de opgegeven URL.
 * Dit is de snelste manier om te bepalen of de URL overheen komt.
 * Maar dit is ook de minste krachtige manier.
 * Voor de gebruiken bij statische paginas.
 */

class StaticRoute implements Route
{
    /**
     * In deze variabele wordt de URL opgeslagen
     *
     * @var String
     */

    private $url;
    
    /**
     * In deze variabele wordt de actie opgeslagen
     *
     * @var String
     */

    private $action;
    
    /**
     * Constructor construeert een nieuwe StaticRoute object met een $url
     * die vergeleken moet worden en een $actie als de vergelijking klopt.
     *
     * @param String $url De URL die overheen moet komen
     * @param String $action De uit te voeren actie als de URL overheenkomt
     * @return Void
     */

    public function __construct( $url, $action )
    {

        $this->url = $url;
        $this->action = $action;
    }

    
    /**
     * Methode om te controleren of de actie van deze Route bij de URL hoort.
     *
     * @param String $url De URL Die gecontroleerd moet worden.
     * @return String De actie, NULL als er geen actie gevonden is.
     */

    public function control( $url )
    {

        return $url == $this->url ? $this->action : null;
    }
}

?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?php

/**
 * regex.route.php. Dit bestand bevat de klasse die een URL vergelijkt met een regex.
 * Deze regex route is is vooral geschikt voor dynamische pagina's.
 *
 * @package Router
 * @subpackage Route
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v1.00$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/interface.php';

/**
 * De RegexRoute klasse is een geavanceerde Route. Deze Route
 * vergelijkt een URL met een regex. Deze Route is relatief traag, maar daardoor
 * ook erg krachtig. Deze Route kan vooral gebruikt worden voor dynamische
 * pagina's.
 */

class RegexRoute implements Route
{
    /**
     * In deze variabele wordt de regex opslagen die wordt gebruikt om
     * te kijken of de URL matcht.
     *
     * @param Regex
     */

    private $regex;
    
    /**
     * In deze variabele wordt de actie opgeslagen die als de URL gematched is
     * aan de URL wordt gekoppeld
     *
     * @param String
     */

    private $action;
    
    /**
     * Constructor construeert een nieuw RegexRoute object met een regex
     * waarmee de URL vergeleken moet worden en een actie aan de hand
     * van de regex gegeneerd kan worden. De actie wordt gebruikt in een
     * preg_replace icm de regex.
     *
     * @param String $regex De regex waarmee de URL moet voldoen
     * @param String $action De uit te voeren actie
     * @return Void
     */

    public function __construct( $regex, $action )
    {

        $this->regex = $regex;
        $this->action = $action;
    }

    
    /**
     * Methode om te controleren of de actie van deze Route bij de URL hoort.
     *
     * @param String $url De URL Die gecontroleerd moet worden.
     * @return String De actie, NULL als er geen actie gevonden is.
     */

    public function control( $url )
    {

        return preg_match( $this->regex, $url ) ? $this->action : null;
    }
    
}

?>

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

/**
 * default.dispatch.php. Dit bestand bevat de standaard uitvoerder.
 * De standaard uitvoerder is een uitvoerder die de actie aannemt en deze klakkeloos uitvoert.
 *
 * @package Router
 * @subpackage Dispatcher
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v1.00$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/interface.php';

/**
 * De DefaultDispatcher klasse neemt een actie aan
 * en voert deze zonder extra handelingen uit.
 */

class DefaultDispatcher implements Dispatcher
{
    /**
     * Deze methode zorgt ervoor dat de Action uitgevoerd wordt.
     *
     * @param String $action De actie die uitgevoerd dient te worden.
     * @return Void
     */

    public function dispatch( $action )
    {

        $output = new $action( );
        $output->dispatch( );
    }
}

?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php

/**
 * application.dispatch.php. Dit bestand bevat de application klasse.
 * De website klasse zorgt ervoor dat de gehele website uitgevoerd wordt.
 *
 * @package Router
 * @subpackage Dispatcher
 * @author Niels Kieviet <Nielskiev@hotmail.com>
 * @version $Revision v1.00$
 * @copyright Copyright (c) 2010, Niels Kieviet
 */


require_once dirname( __FILE__ ) . '/exception.php';
require_once dirname( __FILE__ ) . '/interface.php';
require_once dirname( __FILE__ ) . '/router.php';
require_once dirname( __FILE__ ) . '/static.route.php';
require_once dirname( __FILE__ ) . '/regex.route.php';
require_once dirname( __FILE__ ) . '/default.dispatch.php';

/**
 * De application klasse zorgt ervoor dat de gehele website uitgevoerd wordt.
 * De application klasse roept de Router aan en geeft de gevonden Action door
 * aan de Dispatcher. Deze zorgt vervolgens voor het verdere uitvoeren van de website.
 */

class Application
{
    /**
     * In deze variabele wordt de router opgeslagen
     *
     * @var Router
     */

    private $router;
    
    /**
     * In deze variabele wordt de dispatcher opgeslagen
     *
     * @var Dispatcher
     */

    private $dispatcher;
    
    /**
     * De constructor construeert een nieuwe Application object met de
     * te gebruiker Router en de Dispatcher. Deze dienen als parameter opgegeven te worden.
     *
     * @param Router De te gebruiken Router
     * @param Dispatcher De te gebruiken Dispatcher
     * @return Void
     */

    public function __construct( Router $router, Dispatcher $dispatcher )
    {

        $this->router = $router;
        $this->dispatcher = $dispatcher;
    }

    
    /**
     * Methode voor het uitvoeren van de gehele applicatie.
     *
     * @return Void
     */

    public function dispatch( )
    {

        // Bepaal de URL
        $url = $_SERVER['REQUEST_URI'];
        
        // Bepaal de uit te voeren actie (Action)
        $action = $this->router->find( $url );
        
        // Voer de actie uit als die gevonden is
        if( !is_null( $action ) ) {
            $this->dispatcher->dispatch( $action );
        }
    }
}

?>


Documentatie is wat slecht gedaan, maar goed geen tijd voor gehad, dat komt nog wel
Pim -
Pim -
5 jaar geleden
 
0 +1 -0 -1
Dat heet nou luiheid, beste Niels ;).

Maar wat opmerkingen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

interface Route
{
    /**
     * Methode om te controleren of de actie van deze Route bij de URL hoort.
     *
     * @param String $url De URL Die gecontroleerd moet worden.
     * @return String De actie, NULL als er geen actie gevonden is.
     */

    public function control( $url );
}

?>

De route moet ook in staat zijn parameters uit de string te halen ( /article/10/ ): zie mijn regexroute. Eigenlijk moet dan de route een 'controllerstring' bepalen, waar de dispatcher dan wat nuttigs van maakt. Het symfony framework maakt van die string een PHP callable. Dat vind ik persoonlijk wel erg mooi. Als je zo werkt is het veel generieker: je kan dan kiezen uit functies, actions of controllers als actie. Het geeft wel wat moeite bij het instantiëren van je controller of action.

Verder moet de query string te injecteren zijn in de application of in de dispatcher, zo maak je rerouten mogelijk.

Ook zijn includes natuurlijk nooit mooi: gebruik een autoloader, hoewel ik denk dat je dit puur voor het voorbeeld doet.

Leuk is het misschien om een builder voor je router te maken aan de hand van een config file. Daar ben ik zelf nu mee bezig. Mijn versie heeft dan ook nog variabelen in de config, zodat /article/10/ en /artiekel/10/ op hetzelfde uitkomt.

Je dispatcher moet een foutmelding (404) geven als er geen actie wordt gevonden.

Is het aanroepen van de router niet meer iets voor de dispatcher ipv je application?

Je naamgeving bij Router::find() en Route::control() vind ik niet zo mooi.

En dat was het weer.

Ohja: Maak je private velden protected: uitbreiden moet mogelijk blijven.
Pieter Jansen
Pieter Jansen
5 jaar geleden
 
0 +1 -0 -1
Beste Niels, de code ziet er leuk uit. Ik heb er nog een paar opmerkingen over, maar die laat ik achterwege.

Jongens, in het algemeen vind ik het prima dat jullie m`n klasse afschrijven, maar vergeet niet dat ik een 'simpele' dispatcher heb geprobeerd te bouwen. Ik geloof dat ik daar heel goed in geslaagd ben. Geef, als jullie commentaar hebben kritiek op de tutorial. De lees stijl, de voorbeelden en de uiteindelijke code. Iets wat Karl heeft gedaan.

Ik vind het hartstikke leuk dat jullie een dispatcher willen bouwen, dus ga daar vooral mee door, maar vergeet alsjeblieft niet dat het hier om een simpele dispatcher gaat. Eentje om je URL`s te routen naar wat je maar wil.

Lang niet iedereen weet wat MVC is, wat een controller moet zijn etc. Laat dit dan ook zeker achterwege!

@Pim: wat er mis was met je code is eigenlijk te veel. Je interface is totaal overbodig, strong typing is compleet overbodig ( en werkt geloof ik niet helemaal in PHP ) en ik geloof dat er een foute array was.

M.A.W. je 2 interfaces = overbodig, typo`s, geen documentatie, foute code ( type fouten ), je weet waar ik heen ga.

@Niels ( even terug komend op ) Je code ziet er degelijk uit. De phpdoc is ook erg goed, je code lijkt me te werken al zie ik het nut van de vele includes niet? Daar heeft Pim gelijk, een autoloader/bootstrap zou wel handig zijn. Daarnaast vind ik dat jullie enorm door drijven in het maken van interfaces.

In ieder geval, om m`n verhaal wat kort te houden; ik vind het tof dat jullie allerlei dispatcher systemen ontwikkelen, maar hou alsjeblieft rekening met het feit dat het om een simpele url handler gaat. Dispatcher is misschien een te groot woord, aan gezien dat amper voor komt :)
Pim -
Pim -
5 jaar geleden
 
0 +1 -0 -1
Hoezo is een interface voor de Route niet goed? Dit is toch exact een toepassing waar interfaces zeer geschikt voor zijn? Juist hier wil je de implementatie volledig vrij maken, maar toch de interactie formaliseren? En dat is nou een interface... Hetzelfde geldt voor strong typing, dat overigens (helaas) alleen werkt met objecten.

De typefouten waren al hersteld en verder hoor ik graag wat er verder mis mee is.

En dat jouw code simpeler is en dat onze code daarom irrelevant is, is raar, aangezien jouw code juist veel strikter is en dus een minder brede implementatie toestaat.

Verder vind ik het ook wel grappig dat je nou juist bij Niels' code niet opmerkt dat er 'te veel interfaces' zouden zijn: hij heeft er drie maal zo veel, en dat doet hij goed ;)

Ohja en @Niels: Ook interfaces horen apart in een bestand, dan zijn ze veel makkelijker te vinden en anders werkt een autoloader nooit.
Niels Kieviet
Niels Kieviet
5 jaar geleden
 
0 +1 -0 -1
Even een korte reactie.

Ik sluit me geheel aan bij Pim.
Over autoloader heb je helemaal gelijk, maar dat was even voor het voorbeeld:)

En voor de rest ook.

@pim

Al jouw commentaar klopt, maar dit was even snel snel:)
Jochanan V
Jochanan V
5 jaar geleden
 
0 +1 -0 -1
Met dit script wordt de url dus echt gereplaced, wat dus inhoud dat het volgende niet meer werkt?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$url
= $_SERVER['QUERY_STRING'];
$header = explode('/', $url);
$header = ucfirst($header[1]);
?>

Is er een soortgelijke manier die wel werkt? Want anders kan ik dus geen url rewriter gebruiken. Ik gebruik dit om te controleren of de juiste url aangeroepen is, zo ja, dan laat hij bijv. een zoekfunctie zien.
Mar cel
Mar cel
5 jaar geleden
 
0 +1 -0 -1
Waarom 2000 regels code als het met het onderstaande ook al kan? ;)

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?u=$1 [L,QSA]


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
if(isset($_GET['u'])) {
      $u = explode('/', $_GET['u']);
}
else {
      //default actie hier oid
}
?>
Joris van Rijn
Joris van Rijn
4 jaar geleden
 
0 +1 -0 -1
Omdat je dan bijvoorbeeld geen API kan maken. Of in ieder geval een stuk moeilijker.
Martijn dn
Martijn dn
4 jaar geleden
 
0 +1 -0 -1
Erg interessant! Ik heb nog nooit een url rewriter gebruikt. Maar het is me gelukt om deze te implementeren, was niet zo moeilijk. Maar nu vraag ik mij of of dit mogelijk is
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
require 'lib/class.UrlDispatcher.php';
$url = new UrlDispatcher();
$page = $url->getFirstNode().'.php';
$node = $url->getNodes();    //array

include('includes/'.$page);

?>

Dit is niet zo netjes omdat er eerst met classes gewerkt wordt en hierna bouw ik hm eigenlijk weer om. Ik ben nog helemaal niet bekend met OOP programmeren en wil dit nog eventjes zo houden. Enige tips voor mij ? :)
Mvg,
Martijn

EDIT:Eigenlijk doe je dit in je urlDispatcher.php toch?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    $index
      = strrpos( $_SERVER['PHP_SELF'] , 'index.php');
    $root       = substr( $_SERVER['PHP_SELF'] , -0 , $index );
    $argument   = str_replace( $root , '' ,$_SERVER['REQUEST_URI'] );
    $uri         = trim($argument, '/');
    $nodes        = explode('/', $uri);
    $reversedNodes = array_reverse($nodes);
    $lastNode    = $reversedNodes[0];
    if(isset($nodes[0])){
        $firstNode    = $nodes[0];
    }


?>
Pieter Jansen
Pieter Jansen
4 jaar geleden
 
0 +1 -0 -1
Zoals je het hier presenteert, moet het in principe wel te gebruiken zijn. Als jij als eerste node bijvoorbeeld
/home hebt, en je hebt een bestand genaamd home.php in je map /includes wordt deze gewoon ingeladen. Het enige waar je op moet letten is dat je vanaf je root directory werkt. Dus je /www of /httpdocs map. Zodra je
de klasse aanroept van een dieper niveau, bijvoorbeeld: /www/includes/index.php dan wordt de include ook includes/includes/.'$page. Wat je liever niet wil. Om dit simpel op te lossen is include('/includes/'.$page); te doen. De trailing / betekent standaard je root directory.
Martijn dn
Martijn dn
4 jaar geleden
 
0 +1 -0 -1
Ik zit in een subsubmenu met deze url:
http://url.nl/menu/submenu/subsubmenu/?from=1&to=80
Ik vroeg mij af of dit ook om te zetten is in friendly url's
menu/submenu/subsubmenu/1/80
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
$nodes[0] = menu_naam = menu
$nodes[1] = submenu_naam = submenu
$nodes[2] = subsubmenu_naam = subsubmenu
$nodes[3] = from = 1
$nodes[4] = to = 80


Maar wat gebeurt er als ik in een menu item zit en ik de volgende url aanvraag
menu/1/80
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
$nodes[0] = menu_naam = menu
$nodes[1] = from = 1
$nodes[2] = to = 80


dan veranderen mijn submenu_naam en subsubmenunaam $nodes[1] en $nodes[2] naar from en to
Normaal kun je deze een naam meegeven via een get en weet je precies wat wat is. Met friendly urls gaat dat dus niet meer.
Ben benieuwd hoe jullie dit probleem aanpakken :)
Mvg,
Martijn
Pieter Jansen
Pieter Jansen
4 jaar geleden
 
0 +1 -0 -1
Dat is ook mogelijk, maar dan is het waarschijnlijk makkelijker om een router te gaan gebruiken. Een simpele techniek om waardes te vergelijken en aan de hand van de waardes de juiste logica te vinden.

De meest simpele methode is om een array te hanteren waar alle routes in staan.
Arjen Steensma
Arjen Steensma
4 jaar geleden
 
0 +1 -0 -1
Wie kan mij vertellen waarom de letter i uit de resultaten gefilterd. bijvoorbeeld /nieuws/ wordt neuws
Kees Schepers
kees Schepers
4 jaar geleden
 
0 +1 -0 -1
Waarom in godsnaam zoiets gebruiken als dit al in vele frameworks zit? Buiten de leercurve om dan. Zend Framework maar ook Symfony heeft dit heel netjes geimplementeerd.
Machiel K
Machiel K
3 jaar geleden
 
Een beetje onduidelijk, excuses.
Wouter J
Wouter J
3 jaar geleden
 
En de reden waarom jij na 2 jaar nog op een oude tutorial reageert is ook onduidelijk.

PS: Jij bent waarschijnlijk niet geheel fout, want het is vreemd dat Bas (de eigenaar!) je hier naar doorstuurt :S
Machiel K
Machiel K
3 jaar geleden
 
Ik snap er niks van. Ik vind het onduidelijk omdat er niet boven een vakje staat in wat voor een bestandje ik het moet zetten. Zou iemand een zipje of heeft iemand een zipje voor me die hetzelfde uitwerkt? Alvast bedankt!
Jeroen VD
Jeroen VD
3 jaar geleden
 
ik snap ook niks van jouw reactie, vooral waarom je dit nu zo neerzet. open hier een topic voor!

bijvoorbeeld het topic waar je al in begonnen bent. vraag je hier ook even naar
Wouter J
Wouter J
3 jaar geleden
 
Machiel, nogmaals, dit is een te oud script om nog zomaar zonder problemen te kunnen gebruiken en de maker hiervan is allang verdwenen.

Offtopic:
Tevens vind ik het triest dat je reacties die niet op 1 lijn liggen met jou mening een -1 geeft...
Maargoed, je zal wel ergens je ergenis aan kwijt moeten
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Machiel K
Machiel K
3 jaar geleden
 
0 +1 -0 -1
Ik zag later ook pas dat dit script zo oud was.

Om te reageren heb je een account nodig en je moet ingelogd zijn.

Inhoudsopgave

  1. HTACCES gebruiken
  2. De index.php maken
  3. De URL class schrijven
  4. De URL class af maken
  5. Ter afsluiting de code

Labels

PHP tutorial opties