• Aucun résultat trouvé

Trouver des Articles via les Tags

Une fois que les utilisateurs ont catégorisé leurs contenus, ils voudront probablement retrouver ces contenus en fonc- tion des tags utilisés. Pour développer ces fonctionnalités, nous allons implémenter une nouvelle route, une nouvelle action de controller et une fonction de finder pour chercher les articles par tags.

Idéalement, nous voulons une URL qui ressemblera à http ://localhost :8765/articles/tagged/funny/cat/gifs. Cela nous permettra de trouver tous les articles avec le tag “funny”, “cat” ou “gifs”. Nous avons tout d’abord besoin d’ajouter une nouvelle route. Votre fichier config/routes.php devra ressembler à :

<?php

use Cake\Routing\Route\DashedRoute;

use Cake\Routing\Router;

Router::defaultRouteClass(DashedRoute::class);

// Ceci est la route à ajouter pour notre nouvelle action. // Le `*` à la fin permet de préciser à CakePHP que cette action // a des paramètres qui lui seront passés

Router::scope(

'/articles',

['controller' => 'Articles'], function ($routes) {

$routes->connect('/tagged/*', ['action' => 'tags']); }

);

Router::scope('/', function ($routes) {

// Connect the default home and /pages/* routes. $routes->connect('/', [

'controller' => 'Pages',

'action' => 'display', 'home'

]);

$routes->connect('/pages/*', [

'controller' => 'Pages',

'action' => 'display'

]);

// Connect the conventions based default routes. $routes->fallbacks();

});

Plugin::routes();

Le code ci-dessus définit une nouvelle “route” qui permet de connecter le chemin URL /articles/tagged/ à ArticlesController::tags(). En définissant une nouvelle route, vous pouvez isoler le format de vos URLs de la manière dont elles sont implémentées. Si nous venions à visiter http ://localhost :8765/articles/tagged, nous verrions une page d’erreur de CakePHP vous indiquant que l’action du controller n’existe pas. Créons de ce pas cette nouvelle méthode. Dans src/Controller/ArticlesController.php, ajoutez ce qui suit :

// Ajouter ce 'use' juste sous la déclaration du namespace pour importer // la classe Query

use Cake\ORM\Query;

public function tags() {

// La clé 'pass' est fournie par CakePHP et contient tous les // segments d'URL passés dans la requête

$tags = $this->request->getParam('pass');

// Utilisation de ArticlesTable pour trouver les articles taggés $articles = $this->Articles->find('tagged', [

'tags' => $tags ]);

// Passage des variable dans le contexte de la view du template $this->set([

'articles' => $articles,

'tags' => $tags ]);

}

Pour accéder aux autres parties des données de la requête, consultez la sectionServerRequest.

Puisque les arguments passés sont aussi fournis comme paramètres de la méthode d’action, nous pourrions également écrire l’action en utilisant les arguments variadic de PHP :

public function tags(...$tags) {

// Utilisation de ArticlesTable pour trouver les articles taggés $articles = $this->Articles->find('tagged', [

'tags' => $tags ]);

// Passage des variable dans le contexte de la view du template $this->set([

'articles' => $articles,

'tags' => $tags ]);

Création de la Méthode Finder

Dans CakePHP, nous aimons garder nos actions de controller le plus minimaliste possible et mettons la majorité de la logique de notre application dans la couche model. Si vous veniez à visiter l’URL /articles/tagged, vous verriez une erreur vous indiquant que la méthode findTagged() n’existe pas. Dans src/Model/Table/ArticlesTable.php, ajoutez le code suivant :

// Ajouter ce 'use' juste sous la déclaration du namespace pour importer // la classe Query

use Cake\ORM\Query;

// L'argument $query est une instance du Query builder.

// Le tableau $options va contenir l'option 'tags' que nous avons passé // à find('tagged') dans notre action de controller.

public function findTagged(Query $query, array $options) {

$columns = [

'Articles.id', 'Articles.user_id', 'Articles.title',

'Articles.body', 'Articles.published', 'Articles.created',

'Articles.slug', ];

$query = $query

->select($columns)

->distinct($columns);

if (empty($options['tags'])) {

// si aucun tag n'est fourni, trouvons les articles qui n'ont pas de tags $query->leftJoinWith('Tags')

->where(['Tags.title IS' => null]);

} else {

// Trouvons les articles qui ont au moins un des tags fourni $query->innerJoinWith('Tags')

->where(['Tags.title IN' => $options['tags']]); }

return $query->group(['Articles.id']); }

Nous venons d’implémenterun custom finder. Ce concept très pratique de CakePHP vous permet de définir des re- quêtes réutilisables. Les méthodes finder récupèrent toujours en paramètres un objet Query Builder et un tableau d’options. Les finders peuvent manipuler la requête et ajouter n’importe quels condition ou critère. Une fois la logique terminée, le finder doit retourner une instance modifiée de l’objet query. Dans notre finder, nous utilisons les méthodes distinct()et leftJoin() qui nous permettent de trouver les articles différents qui ont les tags correspondant.

Création de la view

Si vous visitez à nouveau /articles/tagged, CakePHP vous affichera une nouvelle erreur qui vous fait savoir qu’il manque le fichier de view. Créez le fichier src/Template/Articles/tags.ctp et ajoutez le contenu suivant :

<h1>

Articles avec les tags

<?= $this->Text->toList(h($tags), 'ou') ?> </h1>

<section>

<?php foreach ($articles as $article): ?>

<article>

<!-- Utilisation du HtmlHelper pour créer le lien --> <h4><?= $this->Html->link(

$article->title,

['controller' => 'Articles', 'action' => 'view', $article->slug] ) ?></h4>

<span><?= h($article->created) ?> </article>

<?php endforeach; ?> </section>

Dans le code ci-dessus, nous utilisons les HelpersHtmletTextpour nous aider à générer le contenu de notre view. Nous utilisons également la fonction raccourciehpour échapper le contenu HTML. Pensez à utiliser h() quand vous affichez des données pour éviter les injections de HTML.

Le fichier tags.ctp que nous venons de créer suit les conventions CakePHP pour les templates de view. La convention est d’utiliser le nom de l’action du controller en minuscule et avec un underscore en séparateur.

Vous avez peut-être remarqué que nous utilisons les variables $tags et $articles dans notre template de view. Quand nous utilisons la méthode set() dans notre controller, nous définissons les variables qui doivent être en- voyées à notre view. La classe View fera alors en sorte de passer les variables au scope du template comme variables « locales ».

Vous devriez maintenant être capable de visiter la page /articles/tagged/funny et voir tous les articles avec le tag “funny”.