Bonjour tous le monde,
Je suis confronté à un problème pour mes routes que je n'arrive pas à résoudre.
Je voudrais simplement pointer l'url de mes posts vers:
appname/blog/:slug

Cependant dans mon controller pour que la recherche dans la bdd soit plus rapide je passe l'id en paramètre pour ma fonction view (et non pas le slug).

Y'a t-il donc un moyen de le faire avec cake3 ?
J'ai essayé ça (mais ça ne marche pas):

//Je fait un scope puis:
$routes->connect('/:slug', ['controller' => 'Posts', 'action' => 'view', 'slug' => '[0-9a-z\-]'], ['id' => '\d+', 'pass' => ['id']]);

Merci pour votre aide

14 réponses


Mais si tu ne passe que le slug comment tu pourras obtenir l'ID ?

Daniel68
Auteur

Merci pour ta réponse si rapide.
Peut-on passer l'id en le masquant ? (c'est peut-être pas possible ?)
Si grafikart.fr est codé sous cake3, comment as-tu fait pour que tes urls ne contiennent que le slug de tes blog posts. Tu as passé le slug comme param dans ta fonction view ?
En tout cas merci pour ton aide (et bravo pour tes tutos qui sont super)

Le site de Graf n'est pas en Cake3.
Sachant qu'un slug est unique (en théorie), tu peux donc faire une find sur le slug, ca ne pose aucun problème.
Après faut voir au niveau de l'indexation au niveau de la base pour bien optimiser la requête, mais je vois pas de problème :)

Daniel68
Auteur

Merci pour ta réponse,
Je voulais passer par l'idée car il ne s'agit que d'un nombre; alors que le slug est une suite de caractères (parfois long).
Pour chercher dans la BDD c'est pas idéal, la requête sera bien plus longue. Nan ?

Oui en effet tu as raison.
Je te laisse ce post : http://stackoverflow.com/questions/5501961/query-by-slug-or-query-by-id . Le type répond plutôt bien à la question :)

Daniel68
Auteur

Merci,
En effet ça le mérite d'être clair sur la necessité d'utiliser l'id.
En revanche ça n'arrange pas mon problème.
Pour le moment je me vois donc obliger d'afficher l'id dans l'url (ce qui n'est pas du tout l'idéal car j'ai absolument besoin d'url avec le moins d'infos possible).

Si tu veux du rapide, tu met l'URL, si tu veux du "moins" rapide (a l'oeil nu ca se verra pas) tu utilise le slug.
Si tu ne veux pas montrer l'ID, tu peux utiliser un HASH d'id, que tu unHash avant ta requête.

Daniel68
Auteur

Bon tant pis. Je vais donc partir sur une url : /blog/id/slug
Merci quand même pour ton aide,

PS: Si jamais quelqu'un passe par là et trouve la solution je suis preneur.

Tu as pas de solution, si tu a un appel en GET, c'est la seul solution si tu veux la "performance".
Et encore j'imagine qu'avec ta solution peut importe le slug ca fonctionnera toujours ?
Sinon faut faire du post.

Daniel68
Auteur

Oui avec ma solution peut importe que le slug change ou pas, qu'il soit long ou pas... ça ne change rien.
Mais on voit l'id :(
Même si je peux le hacher. Ce que je voulais c'était pas de chiffre dans l'url.

Question bête qui n'a rien à voir avec le sujet (enfin presque) mais en quoi ça pose problème d'avoir l'ID en clair dans l'URL ?
Il y a plein de sites où tu vois l'ID dans l'URL...

Daniel68
Auteur

J'ai fait ce choix pas par securité mais pour une question d'architecture coherente dans mes urls. D'autant plus que je pense que niveau SEO c'est un plus.

Si tu choisis de te baser sur le slug, comme c'est le cas sur grafikart pour la partie blog, tu dois alors faire ton select sur le champs slug :

  • Mettre slug en index pour accélérer les SELECT de SQL
  • T'assurer à 8000% que les slugs resteront unique (mettre une condition unique au niveau de MySQL pour être sûr)
  • Ne pas changer le slug après coup sinon les anciens liens seront cassé.

C'est très contraignant du coup c'est un choix que je ne conseille pas forcément si tu compte avoir bcp d'articles car tu sera tenté de vouloir répété un même slug de temps en temps. L'ID te permet d'avoir un identifiant unique pour tes contenus et du coup tu peux changer le slug après coup et toujours te baser sur l'ID.

Si jamais tu tiens absolument à utiliser le slug, je m'étais créé une petite fonction à glisser dans AppModel à l'époque de Cake 2.
Elle doit toujours être valable sous Cake 3, en l'adaptant bien sûr aux nouveaux objets, clés, et à l'ORM en général.

    public function beforeSave() {
        if(empty($this->data[$this->alias][$this->primaryKey]) || !isset($this->data[$this->alias][$this->primaryKey])):
            $Model =  $this->alias;
            if($Model::hasField('slug')):
                if(empty($this->data[$Model]['slug']) || !isset($this->data[$Model]['slug'])):
                    $slug = Inflector::slug($this->data[$Model]['name'], '-');
                    $slug = strtolower($slug);
                    $count = $Model::find('count', array('conditions' => array($Model.'.slug LIKE' => $slug.'%')));
                    if($count):
                        $slug = $slug.'-'.($count+1);
                    endif;
                    $this->data[$Model]['slug'] = $slug;
                endif;
            endif;
        endif;

        return true;
    }

Le script se lance uniquement au create (pas de clé primaire renseignée). On récupère alors le modèle courant, et si celui-ci possède un champ slug, alors on se prépare à le remplir avec le name passé à l'inflector slug et au strtolower.
Ensuite, on va récupérer le nombre d'enregistrement qui ont le même slug, et s'il y en a, on va simplement ajouter un "-+1" en fin de chaîne.
Ainsi, si j'ai par exemple un slug "post-trop-cool", le deuxième article possédant le même nom sera "post-trop-cool-2", puis "post-trop-cool-3" et ainsi de suite...
Ca fait le boulot plutôt bien avec un index sur la colonne slug.