Grundsätzlich bietet CakePHP über Routen recht einfach konfigurierbare Urls. Als Beispiel nehme ich mal das Blog Tutorial. Die folgende Route ruft die Add Methode im PostController auf, um das Template für einen neuen Blog Beitrag zu rendern.

routes.php


$Route->connect('/beitrag/anlegen', array('controller'=>'posts', 'action'=>'add'));

posts_controller.php

function add() {
    if (!empty($this->data)) {
        ...
    }
}

Das ist also kein Problem. Jetzt möchte ich aber den neuen Beitrag in der Url nicht über seine ID referenzieren, sondern auch hier eine sprechende Url verwenden.

routes.php

$Route->connect('/beitrag/anzeigen/*', array('controller'=>'posts', 'action'=>'view'));

posts_controller.php

function view($url) {
    if ($post = $this->Post->findByUrl(urldecode($url))) {
        $this->set('data', $post);
    }
}

Falls man das ‘anzeigen’ in der Url weglassen möchte, dann müssen in der routes.php auf jeden Fall alle anderen statischen Urls vor der ‘beitrag/*’ Route stehen.

Jetzt wäre es natürlich schön wenn man neben dem Anlegen, die restlichen CRUD Funktionen auch sprechend verlinken könnte. D.h. man ruft das Editieren eines Beitrags nicht über /beitrag/editieren/nette-urls/ sondern per /beitrag/nette-urls/editieren/ (oder auch /kommentar/anlegen/nette-urls/ vs. /beitrag/nette-urls/kommentar/anlegen/) auf.

routes.php

$Route->connect('/beitrag/:post_url/editieren/', array('controller'=>'posts', 'action'=>'edit'));

posts_controller.php

function edit() {
    if ($post = $this->Post->findByUrl(urldecode($this->params['post_url']))) {
        $this->set('data', $post);
    }
}

Am besten nutzt man eine Komponente, die beim Anlegen eines Beitrags den Titel in eine valide Url konvertiert. Die Url muss natürlich auch eindeutig sein, ein UNIQUE auf das Datenbankfeld und eine entsprechende Prüfung in der Komponente sind also noch nötig. Das könnte dann z.B. so aussehen:

class UrlComponent extends Object {
    /**
     * lower case without special chars
     */
    function getNiceUrl($str, $except=array()) {
        $str = strtr($str,"ÀÁÂÃÄÅàáâãäåÇçÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ",
        "AAAAAAaaaaaaCcOOOOOOooooooEEEEeeeeIIIIiiiiUUUUuuuuyNn");

        $str = strtolower(trim ($str) ) ;

        $str = preg_replace ('/[^a-z0-9\-\.,\*]/', '-', $str) ;
        $str = preg_replace ('/([\-\.,\*]{2,})/ue', "substr('\\1', 0, 1)", $str) ;
        $str = preg_replace ('/^[^a-z0-9]|[^a-z0-9]$/', '', $str ) ;

        $i = 1;
        while(in_array($str, $except)) {
            $str = $str . '-' . $i;
            $i++;
        }
        return $str;
    }
}