Le meilleur moyen de tester et d’apprendre CakePHP est de s’assoir et de
construire une application simple de gestion de Contenu (CMS).
Tutoriel d’un système de gestion de contenu
Ce tutoriel vous accompagnera dans la création d’une application de type
CMS. Pour commencer, nous installerons
CakePHP, créerons notre base de données et construirons un système simple
de gestion d’articles.
Voici les pré-requis:
Un serveur de base de données. Nous utiliserons MySQL dans ce tutoriel. Vous
avez besoin de connaître assez de SQL pour créer une base de données et exécuter
quelques requêtes SQL que nous fournirons dans ce tutoriel. CakePHP se chargera
de construire les requêtes nécessaires pour votre application. Puisque nous allons
utiliser MySQL, assurez-vous que pdo_mysql
est bien activé dans PHP.
Les connaissances de base en PHP.
Avant de commencer, assurez-vous que votre version de PHP est à jour:
Vous devez avoir au minimum PHP 8.1 installé (en CLI). Votre version
serveur de PHP doit au moins être aussi 8.1 et, dans l’idéal, devrait
également être la même que pour votre version en ligne de commande (CLI).
Récupérer CakePHP
La manière la plus simple d’installer CakePHP est d’utiliser Composer. Composer
est une manière simple d’installer CakePHP via votre terminal. Premièrement, vous
devez télécharger et installer Composer si vous ne l’avez pas déjà fait. Si vous
avez cURL installé, exécutez la commande suivante:
curl -s https://getcomposer.org/installer | php
Ou vous pouvez télécharger composer.phar
depuis le
site de Composer.
Ensuite, tapez la commande suivante dans votre terminal pour installer le squelette
d’application CakePHP dans le dossier cms du dossier courant:
php composer.phar create-project --prefer-dist cakephp/app:5.* cms
Si vous avez téléchargé et utilisé l’Installer de Composer pour Windows, tapez la commande suivante dans
votre terminal depuis le dossier d’installation (par exemple C:\wamp\www\dev):
composer self-update && composer create-project --prefer-dist cakephp/app:4.* cms
Utiliser Composer a l’avantage d’exécuter automatiquement certaines tâches
importantes d’installation, comme définir les bonnes permissions sur les dossiers
et créer votre fichier config/app.php.
Il existe d’autres moyens d’installer CakePHP. Si vous ne pouvez pas (ou ne
voulez pas) utiliser Composer, rendez-vous dans la section Installation.
Quelque soit la manière de télécharger et installer CakePHP, une fois que la mise
en place est terminée, votre dossier d’installation devrait ressembler à ceci:
/cms
/bin
/config
/logs
/plugins
/resources
/src
/templates
/tests
/tmp
/vendor
/webroot
.editorconfig
.gitignore
.htaccess
.travis.yml
composer.json
index.php
phpunit.xml.dist
README.md
C’est le bon moment pour en apprendre d’avantage sur le fonctionnement de la
structure des dossiers de CakePHP : rendez-vous dans la section Structure du dossier de CakePHP
pour en savoir plus.
Si vous vous perdez pendant ce tutoriel, vous pouvez voir le résultat final on GitHub.
Vérifier l’installation
Il est possible de vérifier que l’installation est terminée en vous rendant sur
la page d’accueil. Avant de faire ça, vous allez devoir lancer le serveur de
développement:
cd /path/to/our/app
bin/cake server
Note
Pour Windows, la commande doit être bin\cake server
(notez le backslash).
Cela démarrera le serveur embarqué de PHP sur le port 8765. Ouvrez
http://localhost:8765 dans votre navigateur pour voir la page d’accueil.
Tous les éléments de la liste devront être validés sauf le point indiquant si
CakePHP arrive à se connecter à la base de données. Si d’autres points ne sont
pas validés, vous avez peut-être besoin d’installer des extensions PHP supplémentaires
ou définir les bonnes permissions sur certains dossiers.
Ensuite, nous allons créer notre base de données et créer notre premier
model.
Tutoriel CMS - Création de la base de données
Maintenant que CakePHP est installé, il est temps d’installer la base de données
pour notre application CMS. Si vous ne l’avez
pas encore fait, créez une base de données vide qui servira pour ce tutoriel, avec
le nom de votre choix (par exemple cake_cms
).
Si vous utilisez MySQL/MariaDB, vous pouvez exécuter le SQL suivant pour créer le
tables nécessaires:
USE cake_cms;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
slug VARCHAR(191) NOT NULL,
body TEXT,
published BOOLEAN DEFAULT FALSE,
created DATETIME,
modified DATETIME,
UNIQUE KEY (slug),
FOREIGN KEY user_key (user_id) REFERENCES users(id)
) CHARSET=utf8mb4;
CREATE TABLE tags (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(191),
created DATETIME,
modified DATETIME,
UNIQUE KEY (title)
) CHARSET=utf8mb4;
CREATE TABLE articles_tags (
article_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (article_id, tag_id),
FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
FOREIGN KEY article_key(article_id) REFERENCES articles(id)
);
INSERT INTO users (email, password, created, modified)
VALUES
('[email protected]', 'secret', NOW(), NOW());
INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', 1, NOW(), NOW());
Si vous utilisez PostgreSQL, connectez-vous à la base de données cake_cms
et exécutez le
code SQL suivant à la place:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
created TIMESTAMP,
modified TIMESTAMP
);
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
slug VARCHAR(191) NOT NULL,
body TEXT,
published BOOLEAN DEFAULT FALSE,
created TIMESTAMP,
modified TIMESTAMP,
UNIQUE (slug),
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
title VARCHAR(191),
created TIMESTAMP,
modified TIMESTAMP,
UNIQUE (title)
);
CREATE TABLE articles_tags (
article_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (article_id, tag_id),
FOREIGN KEY (tag_id) REFERENCES tags(id),
FOREIGN KEY (article_id) REFERENCES articles(id)
);
INSERT INTO users (email, password, created, modified)
VALUES
('[email protected]', 'secret', NOW(), NOW());
INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', TRUE, NOW(), NOW());
Vous avez peut-être remarqué que la table articles_tags
utilise une clé primaire
composée. CakePHP supporte les clés primaires composées presque partout,
vous permettant d’avoir des shémas plus simples qui ne nécessitent pas de
colonnes id
supplémentaires.
Les noms de tables et de colonnes utilisés ne sont pas arbitraires. En utilisant les
conventions de nommages de CakePHP, nous allons bénéficier
des avantages de CakePHP de manière plus efficace et allons éviter d’avoir trop de
configuration à effectuer. Bien que CakePHP soit assez flexible pour supporter presque
n’importe quel schéma de base de données, adhérer aux conventions va vous faire gagner
du temps.
Configuration de la base de données
Ensuite, disons à CakePHP où est notre base de données et comment nous y connecter.
Remplacez les valeurs dans le tableau Datasources.default
de votre fichier
config/app.php avec celle de votre installation de base de données. Un exemple
de configuration complétée ressemblera à ceci:
<?php
return [
// D'autres configurations au dessus
'Datasources' => [
'default' => [
'className' => Connection::class,
// Remplacez Mysql par Postgres si vous utilisez PostgreSQL
'driver' => Mysql::class,
'persistent' => false,
'host' => 'localhost',
'username' => 'cakephp',
'password' => 'AngelF00dC4k3~',
'database' => 'cake_cms',
// Commentez la ligne ci-dessous si vous utilisez PostgreSQL
'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'cacheMetadata' => true,
],
],
// D'autres configurations en dessous
];
Une fois que vous avez sauvegardé votre fichier config/app.php, vous devriez
voir que CakePHP est capable de se connecter à la base de données sur la page d’accueil
de votre projet.
Note
Si vous avez config/app_local.php dans votre dossier d’application, vous devez
plutôt configurer votre connexion à la base de données dans ce fichier.
Création du premier Model
Les models font partie du coeur des applications CakePHP. Ils nous permettent
de lire et modifier les données, de construire des relations entre nos données,
de valider les données et d’appliquer les règles spécifiques à notre application.
Les models sont les fondations nécessaires pour construire nos actions de controllers
et nos templates.
Les models de CakePHP sont composés d’objets Table
et Entity
. Les objets
Table
nous permettent d’accéder aux collections d’entities stockées dans une
table spécifique. Ils sont stockés dans le dossier src/Model/Table. Le fichier
que nous allons créer sera sauvegardé dans src/Model/Table/ArticlesTable.php.
Le fichier devra contenir ceci:
<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config): void
{
$this->addBehavior('Timestamp');
}
}
Nous y avons attaché le behavior Timestamp qui remplira
automatiquement les colonnes created
et modified
de notre table. En
nommant notre objet Table ArticlesTable
, CakePHP va utiliser les conventions
de nommages pour savoir que notre model va utiliser la table articles
. Toujours
en utilisant les conventions, il saura que la colonne id
est notre clé primaire.
Note
CakePHP créera dynamiquement un objet model s’il n’en trouve pas un qui
correspond dans le dossier src/Model/Table. Cela veut dire que si vous
faites une erreur lors du nommage du fichier (par exemple articlestable.php ou
ArticleTable.php), CakePHP ne reconnaitra pas votre configuration et utilisera
ce model généré à la place.
Nous allons également créer une classe Entity pour nos Articles. Les Entities
représentent un enregistrement spécifique en base et donnent accès aux données
d’une ligne de notre base. Notre Entity sera sauvegardée dans src/Model/Entity/Article.php.
Le fichier devra ressembler à ceci:
<?php
// src/Model/Entity/Article.php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Article extends Entity
{
protected array $_accessible = [
'*' => true,
'id' => false,
'slug' => false,
];
}
Notre entity est assez simple pour l’instant et nous y avons seulement défini la
propriété _accessible
qui permet de contrôler quelles propriétés peuvent être
modifiées via Assignement de Masse.
Pour l’instant, nous ne pouvons pas faire grande chose avec notre model. Pour
intéragir avec notre model, nous allons ensuite créer nos premiers
Controller et Template.
Tutoriel CMS - Création du Controller Articles
Maintenant que notre model est créé, nous avons besoin d’un controller pour nos
articles. Dans CakePHP, les controllers se chargent de gérer les requêtes HTTP et
exécutent la logique métier des méthodes des models pour préparer une réponse. Nous
placerons le code de ce controller dans un nouveau fichier ArticlesController.php,
dans le dossier src/Controller. La base du controller ressemblera à ceci:
<?php
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
}
Ajoutons maintenant une action à notre controller. Les actions sont les méthodes
des controllers qui sont connectées aux routes. Par exemple, quand un utilisateur
appelle la page www.example.com/articles/index (ce qui est la même chose qu’appeler
www.example.com/articles), CakePHP appelera la méthode index
de votre controller
ArticlesController
. Cette méthode devra à son tour faire appel à la couche Model
et préparer une réponse en faisant le rendu d’un Template via la couche de View.
Le code de notre action index sera le suivant:
<?php
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
public function index()
{
$this->loadComponent('Paginator');
$articles = $this->Paginator->paginate($this->Articles->find());
$this->set(compact('articles'));
}
}
Maintenant que nous avons une méthode index()
dans notre ArticlesController
,
les utilisateurs peuvent y accéder via www.example.com/articles/index.
De la même manière, si nous définissions une méthode foobar()
, les utilisateurs
pourraient y accéder via www.example.com/articles/foobar. Vous pourriez être tenté
de nommer vos controllers et vos actions afin d’obtenir des URL spécifiques. Cependant,
ceci est déconseillé. Vous devriez plutôt suivre les Conventions de CakePHP
et créer des noms d’actions lisibles ayant un sens pour votre application. Vous pouvez
ensuite utiliser le Routing pour obtenir les URLs que vous
souhaitez et les connecter aux actions que vous avez créées.
Notre action est très simple. Elle récupère un jeu d’articles paginés dans la base de
données en utilisant l’objet Model Articles qui est chargé automatiquement via les
conventions de nommage. Elle utilise ensuite la méthode set()
pour passer les
articles récupérés au Template (que nous créerons par la suite). CakePHP va
automatiquement rendre le Template une fois que notre action de Controller sera
entièrement exécutée.
Création du Template de liste des Articles
Maintenant que notre controller récupère les données depuis le model et qu’il
prépare le contexte pour la view, créons le template pour notre action index.
Les templates de view de CakePHP sont des morceaux de PHP qui sont insérés dans
le layout de votre application. Bien que nous créerons du HTML ici, les Views
peuvent générer du JSON, du CSV ou même des fichiers binaires comme des PDFs.
Un layout est le code de présentation qui englobe la view d’une action. Les fichiers
de layout contiennent les éléments communs au site comme les headers, les footers et les
éléments de navigation. Votre application peut très bien avoir plusieurs layouts et
vous pouvez passer de l’un à l’autre. Mais pour le moment, utilisons seulement le
layout par défaut.
Les fichiers de template de CakePHP sont stockés dans templates et dans
un dossier au nom du controller auquel ils sont attachés. Nous devons donc
créer un dossier nommé “Articles” dans notre cas. Ajoutez le code suivant
dans ce fichier:
<!-- Fichier : templates/Articles/index.php -->
<h1>Articles</h1>
<table>
<tr>
<th>Titre</th>
<th>Créé le</th>
</tr>
<!-- C'est ici que nous bouclons sur notre objet Query $articles pour afficher les informations de chaque article -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
Dans la précédente section, nous avons assigné la variable “articles” à la view en
utilisant la méthode set()
. Les variables passées à la view sont disponibles dans
les templates de view comme des variables locales, comme nous l’avons fait ci-dessus.
Vous avez peut-être remarqué que nous utilisons un objet appelé $this->Html
.
C’est une instance du HtmlHelper. CakePHP inclut
plusieurs helpers de view qui peuvent créer des liens, des
formulaires et des éléments de paginations. Vous pouvez en apprendre
plus à propos des Helpers (Assistants) dans le chapitre de la documentation qui
leur est consacré, mais le plus important ici est la méthode link()
, qui générera
un lien HTML avec le texte fourni (le premier paramètre) et l’URL (le second paramètre).
Quand vous spécifiez des URLs dans CakePHP, il est recommandé d’utiliser des
tableaux ou des routes nommées. Ces syntaxes vous permettent
de bénéficier du reverse routing fourni par CakePHP.
A partir de maintenant, si vous accédez à http://localhost:8765/articles/index,
vous devriez voir votre view qui liste les articles avec leur titre et leur lien.
Création de l’action View
Si vous cliquez sur le lien d’un article dans la page qui liste nos articles,
vous tombez sur une page d’erreur vous indiquant que l’action n’a pas été implémentée.
Vous pouvez corriger cette erreur en créant l’action manquante correspondante:
// Ajouter au fichier existant src/Controller/ArticlesController.php
public function view($slug = null)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
$this->set(compact('article'));
}
Bien que cette action soit simple, nous avons utilisé quelques-unes des fonctionnalités
de CakePHP. Nous commençons par utiliser la méthode findBySlug()
qui est un
finder dynamique. Cette méthode nous permet de créer
une requête basique qui permet de récupérer des articles par un « slug » donné.
Nous utilisons ensuite la méthode firstOrFail()
qui nous permet de récupérer
le premier enregistrement ou lancera une NotFoundException
si aucun article
correspondant n’est trouvé.
Notre action attend un paramètre $slug
, mais d’où vient-il ? Si un utilisateur
requête /articles/view/first-post
, alors la valeur “first-post” sera passée
à $slug
par la couche de routing et de dispatching de CakePHP. Si nous rechargeons
notre navigateur, nous aurons une nouvelle erreur, nous indiquant qu’il manque un template
de View; corrigeons cela.
Création du Template View
Créons le template de view pour notre action « view » dans
templates/Articles/view.php.
<!-- Fichier : templates/Articles/view.php -->
<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>Créé le : <?= $article->created->format(DATE_RFC850) ?></small></p>
<p><?= $this->Html->link('Modifier', ['action' => 'edit', $article->slug]) ?></p>
Vous pouvez vérifier que tout fonctionne en essayant de cliquer sur un lien de
/articles/index
ou en vous rendant manuellement sur une URL de la forme
/articles/view/first-post
.
Ajouter des articles
Maintenant que les views de lecture ont été créées, il est temps de rendre possible
la création d’articles. Commencez par créer une action add()
dans le
ArticlesController
. Notre controller doit maintenant ressembler à ceci:
// src/Controller/ArticlesController.php
namespace App\Controller;
use App\Controller\AppController;
class ArticlesController extends AppController
{
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Paginator');
$this->loadComponent('Flash'); // Inclusion du FlashComponent
}
public function index()
{
$articles = $this->Paginator->paginate($this->Articles->find());
$this->set(compact('articles'));
}
public function view($slug)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
$this->set(compact('article'));
}
public function add()
{
$article = $this->Articles->newEmptyEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->getData());
// L'écriture de 'user_id' en dur est temporaire et
// sera supprimée quand nous aurons mis en place l'authentification.
$article->user_id = 1;
if ($this->Articles->save($article)) {
$this->Flash->success(__('Votre article a été sauvegardé.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Impossible d\'ajouter votre article.'));
}
$this->set('article', $article);
}
}
Note
Vous devez inclure le Flash dans tous les controllers
où vous avez besoin de l’utiliser. Il est souvent conseillé de le charger
directement dans le AppController
.
Voici ce que l’action add()
fait:
Si la méthode HTTP de la requête est un POST, cela tentera de sauvegarder les données
en utilisant le model Articles.
Si pour une quelconque raison la sauvegarde ne se fait pas, cela rendra juste la view.
Cela nous donne ainsi une chance de montrer les erreurs de validation ou d’autres
messages à l’utilisateur.
Toutes les requêtes de CakePHP incluent un objet request qui est accessible via
$this->request
. L’objet request contient des informations à propos de la
requête qui vient d’être reçue. Nous utilisons la méthode
Cake\Http\ServerRequest::is()
pour vérifier que la requête possède
bien le verbe HTTP POST.
Les données passées en POST sont disponibles dans $this->request->getData()
.
Vous pouvez utiliser les fonctions pr()
ou debug()
pour
afficher les données si vous voulez voir à quoi elles ressemblent. Pour sauvegarder
les données, nous devons tout d’abord « marshaller » les données du POST en une
Entity Article. L’Entity sera ensuite persistée en utilisant la classe ArticlesTable
que nous avons créée plus tôt.
Après la sauvegarde de notre article, nous utilisons la méthode success()
du
FlashComponent pour définir le message en Session. La méthode success
est
fournie via les méthodes magiques de PHP.
Les messages Flash seront affichés sur la page suivante après redirection. Dans
notre layout, nous avons <?= $this->Flash->render() ?>
qui affichera un message
Flash et le supprimera du stockage dans la session. Enfin, après la sauvegarde, nous
utilisons Cake\Controller\Controller::redirect
pour renvoyer
l’utilisateur à la liste des articles. Le paramètre ['action' => 'index']
correspond à l’URL /articles
, c’est-à-dire l’action index du ArticlesController
.
Vous pouvez vous référer à la méthode Cake\Routing\Router::url()
dans
la documentation API pour voir les formats dans lesquels
vous pouvez spécifier une URL.
Création du Template Add
Voici le code de notre template de la view « add »:
<!-- File: templates/Articles/add.php -->
<h1>Ajouter un article</h1>
<?php
echo $this->Form->create($article);
// Hard code the user for now.
echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Sauvegarder l\'article'));
echo $this->Form->end();
?>
Nous utilisons le FormHelper pour générer l’ouverture du formulaire HTML.
Voici le HTML que $this->Form->create()
génère:
<form method="post" action="/articles/add">
Puisque nous appelons create()
sans passer d’option URL, le FormHelper
va partir du principe que le formulaire doit être soumis sur l’action courante.
La méthode $this->Form->control()
est utilisée pour créer un élément de
formulaire du même nom. Le premier paramètre indique à CakePHP à quel champ
il correspond et le second paramètre vous permet de définir un très grand nombre
d’options - dans notre cas, le nombre de lignes (rows) pour le textarea. Il y a
un peu d’instrospection et de conventions utilisées ici. La méthode control()
affichera des éléments de formulaire différents en fonction du champ du model
spécifié et utilisera une inflection automatique pour définir le label associé.
Vous pouvez personnaliser le label, les inputs ou tout autre aspect du formulaire
en utilisant les options. La méthode $this->Form->end()
ferme le formulaire.
Retournons à notre template templates/Articles/index.php pour ajouter
un lien « Ajouter un article ». Avant le <table>
, ajoutons la ligne
suivante:
<?= $this->Html->link('Ajouter un article', ['action' => 'add']) ?>
Ajout de la génération de slug
Si nous sauvons un article tout de suite, la sauvegarde échouerait car nous ne
créons pas l’attribut « slug » et la colonne correspondante est définie comme
NOT NULL
. Un slug est généralement une version « URL compatible » du titre
d’un article. Nous pouvons utiliser le callback beforeSave()
de l’ORM pour créer notre slug:
<?php
// dans src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
// la classe Text
use Cake\Utility\Text;
// la classe EventInterface
use Cake\Event\EventInterface;
// Ajouter la méthode suivante
public function beforeSave($event, $entity, $options)
{
if ($entity->isNew() && !$entity->slug) {
$sluggedTitle = Text::slug($entity->title);
// On ne garde que le nombre de caractère correspondant à la longueur
// maximum définie dans notre schéma
$entity->slug = substr($sluggedTitle, 0, 191);
}
}
Ce code est simple et ne prend pas en compte les potentiels doublons de slug.
Mais nous nous occuperons de ceci plus tard.
Ajout de l’action Edit
Notre application peut maintenant sauvegarder des articles, mais nous ne pouvons
pas modifier les articles existants. Rectifions cela maintenant. Ajoutez l’action suivante
dans votre ArticlesController
:
// dans src/Controller/ArticlesController.php
// Ajouter la méthode suivante.
public function edit($slug)
{
$article = $this->Articles
->findBySlug($slug)
->firstOrFail();
if ($this->request->is(['post', 'put'])) {
$this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Votre article a été mis à jour.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Impossible de mettre à jour l\'article.'));
}
$this->set('article', $article);
}
Cette action va d’abord s’assurer que l’utilisateur essaie d’accéder à un
enregistrement existant. Si vous n’avez pas passé de paramètre $slug
ou que
l’article n’existe pas, une NotFoundException
sera lancée et le ErrorHandler
de CakePHP rendra la page d’erreur appropriée.
Ensuite l’action va vérifier si la requête est une requête POST ou PUT. Si c’est le cas,
nous utiliserons alors les données du POST/PUT pour mettre à jour l’entity de l’article
en utilisant la méthode patchEntity()
. Enfin, nous appelons la méthode save()
,
nous définissons un message Flash approprié et soit nous redirigeons, soit nous affichons
les erreurs de validation en fonction du résultat de l’opération de sauvegarde.
Création du Template Edit
Le template edit devra ressembler à ceci:
<!-- Fichier : templates/Articles/edit.php -->
<h1>Modifier un article</h1>
<?php
echo $this->Form->create($article);
echo $this->Form->control('user_id', ['type' => 'hidden']);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Sauvegarder l\'article'));
echo $this->Form->end();
?>
Ce template affiche le formulaire de modification (avec les valeurs déjà remplies),
ainsi que les messages d’erreurs de validation nécessaires.
Vous pouvez maintenant mettre à jour notre view index avec les liens pour modifier
les articles:
<!-- Fichier : templates/Articles/index.php (liens de modification ajoutés) -->
<h1>Articles</h1>
<p><?= $this->Html->link("Ajouter un article", ['action' => 'add']) ?></p>
<table>
<tr>
<th>Titre</th>
<th>Créé le</th>
<th>Action</th>
</tr>
<!-- C'est ici que nous bouclons sur notre objet Query $articles pour afficher les informations de chaque article -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('Modifier', ['action' => 'edit', $article->slug]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
Mise à jour des règles de validation pour les Articles
Jusqu’à maintenant, nos Articles n’avaient aucune validation de données. Occupons-nous
de ça en utilisant un validator:
// src/Model/Table/ArticlesTable.php
// Ajouter ce "use" juste sous la déclaration du namespace pour importer
// la classe Validator
use Cake\Validation\Validator;
// Ajouter la méthode suivante.
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('title')
->minLength('title', 10)
->maxLength('title', 255)
->notEmptyString('body')
->minLength('body', 10);
return $validator;
}
La méthode validationDefault()
indique à CakePHP comment valider les données
quand la méthode save()
est appelée. Ici, il est spécifié que les champs title
et body ne peuvent pas être vides et qu’ils ont aussi des contraintes sur la longueur.
Le moteur de validation de CakePHP est à la fois puissant et flexible. Il vous fournit
un jeu de règles sur des validations communes comme les adresses emails, les adresses IP,
etc. mais aussi la flexibilité d’ajouter vos propres règles de validation. Pour plus
d’informations, rendez-vous dans la section Validation de
la documentation.
Maintenant que nos règles de validation sont en place, utilisons l’application
et essayons d’ajouter un article avec un title ou un body vide pour voir ce qu’il
se passe. Puisque nous avons utiliser la méthode Cake\View\Helper\FormHelper::control()
du FormHelper pour créer les éléments de formulaire, nos messages d’erreurs de
validation seront affichés automatiquement.
Ajout de l’Action de Suppression
Donnons maintenant la possibilité à nos utilisateurs de supprimer des articles.
Commencez par créer une action delete()
dans ArticlesController
:
// src/Controller/ArticlesController.php
// Ajouter la méthode suivante.
public function delete($slug)
{
$this->request->allowMethod(['post', 'delete']);
$article = $this->Articles->findBySlug($slug)->firstOrFail();
if ($this->Articles->delete($article)) {
$this->Flash->success(__('L\'article {0} a été supprimé.', $article->title));
return $this->redirect(['action' => 'index']);
}
}
Ce code va supprimer l’article ayant le slug $slug
et utilisera la méthode
$this->Flash->success()
pour afficher un message de confirmation à l’utilisateur
après l’avoir redirigé sur /articles
. Si l’utilisateur essaie d’aller supprimer
un article avec une requête GET, la méthode allowMethod()
lancera une exception.
Les exceptions non capturées sont récupérées par le gestionnaire d’exception de CakePHP
qui affichera une belle page d’erreur. Il existe plusieurs Exceptions
intégrées qui peuvent être utilisées pour remonter les différentes erreurs HTTP
que votre application aurait besoin de générer.
Avertissement
Permettre de supprimer des données via des requêtes GET est très dangereux, car
il est possible que des crawlers suppriment accidentellement du contenu. C’est
pourquoi nous utilisons la méthode allowMethod()
dans notre controller.
Puisque nous exécutons seulement de la logique et redirigeons directement sur une
autre action, cette action n’a pas de template. Vous devez ensuite mettre à jour
votre template index pour ajouter les liens qui permettront de supprimer les
articles:
<!-- Fichier : templates/Articles/index.php (ajout des liens de suppression) -->
<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
<tr>
<th>Titre</th>
<th>Créé le</th>
<th>Action</th>
</tr>
<!-- C'est ici que nous bouclons sur notre objet Query $articles pour afficher les informations de chaque article -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('Modifier', ['action' => 'edit', $article->slug]) ?>
<?= $this->Form->postLink(
'Supprimer',
['action' => 'delete', $article->slug],
['confirm' => 'Êtes-vous sûr ?'])
?>
</td>
</tr>
<?php endforeach; ?>
</table>
Utiliser postLink()
va créer un lien
qui utilisera du JavaScript pour faire une requête POST et supprimer notre article.
Note
Ce code de view utilise également le FormHelper
pour afficher à l’utilisateur
une boîte de dialogue de confirmation en JavaScript avant la suppression
effective de l’article.
Maintenant que nous avons un minimum de gestion sur nos articles, il est temps
de créer des actions basiques pour nos tables Tags et Users.