TD6 – Architecture MVC avancée 2/2 Vues modulaires, filtrage, formulaires améliorés
Aujourd’hui nous continuons de développer notre site-école de covoiturage. Au fur et à mesure que le projet grandit, nous allons bénéficier du modèle MVC qui va nous faciliter la tâche de conception. En attendant de pouvoir gérer les sessions d’utilisateur, nous allons développer l’interface “administrateur” du site.
Le but des TDs 5 & 6 est donc d’avoir un site qui propose une gestion minimale des voitures, utilisateurs et trajets proposés en covoiturage.
Ce TD présuppose que vous avez fini le TD précédent.
Amélioration du routeur
On veut ajouter un comportement par défaut du routeur qui est contenu dans le
contrôleur frontal. Nous allons faire en sorte qu’un utilisateur qui arrive sur
controleurFrontal.php
voit la même page que s’il était arrivé sur
controleurFrontal.php?action=afficherListe
.
Action par défaut
-
Si aucun paramètre n’est donné dans l’URL, initialisons la variable
action
avec la chaîne de caractères"afficherListe"
danscontroleurFrontal.php
. Utilisez la fonctionisset($_GET['action'])
qui teste si la variable$_GET['action']
a été initialisée, ce qui est le cas si et seulement si une variableaction
a été donnée dans l’URL. -
Testez votre site en appelant
controleurFrontal.php
sans action.
Note : De manière générale, il ne faut jamais lire la case d’un tableau
avant d’avoir vérifié qu’elle était bien définie avec un isset(...)
sous peine
d’avoir des erreurs Undefined index : ...
.
Désormais, la page http://webinfo.iutmontp.univ-montp2.fr/~votre_login/TD6/web/controleurFrontal.php doit marcher sans paramètre.
Vérification de l’action
On souhaite que le routeur vérifie que action
est le nom d’une méthode de
ControleurVoiture.php
avant d’appeler cette méthode. Sinon, nous renverrons
vers une page d’erreur.
-
Créez une action
afficherErreur(string $messageErreur = "")
dans le contrôleur voiture qui affiche une vue d’erreursrc/vue/voiture/erreur.php
contenant le message d’erreur Problème avec la voiture :$messageErreur
, ou juste Problème avec la voiture si le message est vide. -
Modifiez le code du routeur pour implémenter la vérification de l’action. Si l’action n’existe pas, appelez l’action
afficherErreur
.Notes :
- Vous pouvez récupérer le tableau des méthodes visibles d’une classe avec
la fonction
get_class_methods()
et tester si une valeur appartient à un tableau avec la fonctionin_array
. get_class_methods()
prend en argument une chaine de caractères contenant le nom de la classe qualifié, c.-à-d. avec lenamespace
.
- Vous pouvez récupérer le tableau des méthodes visibles d’une classe avec
la fonction
Séparation des données et de leur persistance
Une bonne pratique de la programmation orientée objet est de suivre des
principes de conception, notamment SOLID dont vous avez entendu parler l’an
dernier en cours de Développement Orienté Objet et que vous allez également
aborder dans le cours Qualité de développement. Le S
de SOLID signifie
Single responsibility principle (ou principe de responsabilité unique en
français) : chaque classe doit faire une seule tâche.
Actuellement, notre classe ModeleVoiture
gère 2 tâches : la gestion des
voitures et leur persistance dans une base de donnée. Ceci est contraire aux
principes SOLID. Plus concrètement, si on veut enregistrer une voiture
différemment plus tard (dans une session, dans un fichier, via un appel d’API,
ou avec une classe mock pour des tests), cela impliquera beaucoup de
réécriture de code.
Nous allons séparer les méthodes gérant la persistance des données des autres méthodes propres aux voitures (méthodes métiers). Voici le diagramme de classe UML modifié que nous allons obtenir à la fin de cette section :
Notez que dans le schéma UML ci-dessus :
ModeleVoiture
est scindé en deux classesVoitureRepository
etVoiture
.VoitureRepository
etVoiture
ont changés de dossier et denamespace
par rapport àModeleVoiture
.ajouter
est maintenant une méthode statique qui prend uneVoiture
en argument.- La classe
VoitureRepository
dépend deVoiture
, mais pas l’inverse (d’où la direction du lien de dépendance entre les deux classes).
En termes de fichiers, nous aurons l’arborescence suivante après nos modifications :
Le dossier Repository
gère la persistance des données. Le nom Repository
est
le nom du patron de conception que l’on utilise et que l’on retrouve dans les
outils professionnels (ORM Doctrine par exemple).
-
Renommez la classe
ModeleVoiture
enVoiture
.
Utilisez le refactoring de PhpStorm : Clic droit sur le nom de la classe > Refactor > Rename. -
Créez deux dossiers
DataObject
etRepository
dansModele
. - Créez une classe
VoitureRepository
dans le dossierRepository
avec lenamespace
correspondant (App\Covoiturage\Modele\Repository
). Déplacez les méthodes suivantes deVoiture
dansVoitureRepository
:getVoitures
getVoitureParImmatriculation
ajouter
construireDepuisTableau
Pour la méthode
construireDepuisTableau
, changez si nécessaire le corps de la fonction afin qu’un objetVoiture
soit correctement retourné. Pensez également à adapter le code des autres fonctions de la classeVoitureRepository
afin qu’elles appellent correctement la méthodeconstruireDepuisTableau
.Transformez la méthode
ajouter
en une méthode statique prenant en paramètre un objet de typeVoiture
. Cet objet sera la voiture à ajouter. Utilisez donc les getters de cetteVoiture
afin de retrouver les données à insérer dans la requête SQL de la méthodeajouter
. -
Déplacer
Voiture
dans le dossierDataObject
etConnexionBaseDeDonnees
dansRepository
.Attention si vous utilisez le drag & drop de PhpStorm, vous allez avoir des mauvaises surprises car les
namespace
risquent de ne pas se mettre à jour correctement…
La façon correcte de le faire : Clic droit sur le nom de la classe > Refactor > Move Class > Indiquer lenamespace
correspondant.Vérifiez que votre code correspond à celui indiqué dans le diagramme de classe évoqué précédemment.
- Faites remarcher les actions une par une :
afficherListe
:getVoitures
appartient à la classeVoitureRepository
désormais.
afficherDetail
:getVoitureParImmatriculation
appartient à la classeVoitureRepository
.
creerDepuisFormulaire
:ajouter
etgetVoitures
appartiennent à la classeVoitureRepository
désormais.ajouter
sera maintenant statique et prendra en argument un objet de la classeVoiture
; les getters deVoiture
servent à construire la requête SQL.
CRUD pour les voitures
CRUD est un acronyme pour Create/Read/Update/Delete, qui sont les quatre opérations de base de toute donnée. Nous allons compléter notre site pour qu’il implémente toutes ces fonctionnalités. Lors des TDs précédents, nous avons implémenté nos premières actions :
- Read – afficher toutes les voitures : action
afficherListe
- Read – afficher les détails d’une voiture : action
afficherDetail
- Create – afficher le formulaire de création d’une voiture : action
afficherFormulaireCreation
- Create – créer une voiture dans la BDD : action
creerDepuisFormulaire
Nous allons compléter ces opérations avec la mise à jour et une version améliorée de la suppression.
Action supprimer
Nous souhaitons ajouter l’action supprimer
aux voitures. Pour cela :
-
Écrivez dans
VoitureRepository
une méthode statiquesupprimerParImmatriculation($immatriculation)
qui prend en entrée l’immatriculation à supprimer (pensez à utiliser les requêtes préparées dePDO
). -
Créez une vue
src/vue/voiture/voitureSupprimee.php
qui affiche “La voiture d’immatriculation$immatriculation
a bien été supprimée”, suivi de la liste des voitures en appelant la vueliste.php
(de la même manière quevoitureCreee.php
). -
Écrivez l’action
supprimer
du contrôleur de voiture pour que- il supprime la voiture dont l’immatriculation est passée en paramètre dans l’URL,
- il affiche la vue
voitureSupprimee.php
en utilisant le mécanisme de vue générique, et en donnant en paramètres les variables nécessaires dans la vue.
-
Enrichissez la vue
liste.php
pour ajouter des liens HTML qui permettent de supprimer une voiture.Aide : Procédez par étape. Écrivez d’abord un lien fixe dans votre vue, puis la partie qui dépend de la voiture.
-
Testez le tout. Quand la fonctionnalité marche, appréciez l’instant.
Action afficherFormulaireMiseAJour
et mettreAJour
Nous souhaitons ajouter l’action afficherFormulaireMiseAJour
aux voitures qui affiche le
formulaire de mise à jour. Pour cela :
-
Créez une vue
src/vue/voiture/formulaireMiseAJour.php
qui affiche un formulaire identique à celui deformulaireCreation.php
, mais qui sera prérempli par les données de la voiture courante. Nous ne passerons que l’immatriculation de la voiture via l’URL ; les autres informations seront récupérées dans la BDD. Voici quelques points à prendre en compte avant de se lancer :-
L’attribut
value
de la balise<input>
permet de préremplir un champ du formulaire. Utilisez l’attribut HTMLreadonly
de<input>
pour que l’internaute ne puisse pas changer l’immatriculation. -
On pourra se servir dans le contrôleur de
getVoitureParImmatriculation
pour récupérer l’objet voiture de la bonne immatriculation. La vue devra alors remplir le formulaire avec les attributs de cet objet. -
Pensez bien à échapper vos variables PHP avant de les écrire dans l’HTML et dans les URLs.
-
Rappel : Vous souhaitez envoyer l’information
action=mettreAJour
en plus des informations saisies lors de l’envoi du formulaire. La bonne façon de faire pour un formulaire de méthodeGET
est d’ajouter un champ caché<input type='hidden' name='action' value='mettreAJour'>
.
-
-
Écrivez l’action
afficherFormulaireMiseAJour
du contrôleur de voiture pour qu’il affiche le formulaire prérempli. Vérifiez que l’actionafficherFormulaireMiseAJour
affiche bien le formulaire. -
Ajoutons les liens manquants. Enrichissez la vue
liste.php
pour ajouter des liens HTML qui permettent de mettre à jour une voiture. Ces liens pointent donc vers le formulaire de mis-à-jour prérempli. -
Astuce optionnelle : La vue
afficherFormulaireMiseAJour
peut être raccourcie en utilisant la syntaxe<?= $immatriculationHTML ?>
qui est équivalente à
<?php echo $immatriculationHTML; ?>
-
Maintenant, passons à l’action
mettreAJour
qui effectue la mise à jour dans la BDD.Créez la vue
src/vue/voiture/voitureMiseAJour.php
pour qu’elle affiche “La voiture d’immatriculation$immatriculation
a bien été mise à jour”. Affichez en dessous de ce message la liste des voitures mise à jour (à la manière devoitureSupprimee.php
etvoitureCreee.php
). -
Ajoutez à
VoitureRepository
une méthode statiquemettreAJour(Voiture $voiture)
. Cette méthode est proche deajouter(Voiture $voiture)
, à ceci près qu’elle ne renvoie pas de booléen. En effet, on va considérer qu’une mise à jour se passe toujours correctement. -
Créez l’action
mettreAJour
du contrôleur de voiture pour qu’il mette à jour la voiture dont l’immatriculation est passée en paramètre dans l’URL, puis qu’il affiche la vuesrc/vue/voiture/voitureMiseAJour.php
après l’avoir correctement initialisée. -
Testez le tout. Quand la fonctionnalité marche, appréciez de nouveau l’instant.
Gérer plusieurs contrôleurs
Maintenant que notre site propose une gestion minimale des voitures (Create / Read / Update / Delete), notre objectif est d’avoir une interface similaire pour les utilisateurs et les trajets. Dans ce TD, nous allons dans un premier temps rendre notre MVC de voitures plus générique. Cela nous permettra de l’adapter plus facilement aux utilisateurs et trajets dans un second temps.
Dans le routeur du contrôleur frontal
Pour l’instant, nous n’avons travaillé que sur le contrôleur voiture. Nous
souhaitons maintenant ajouter les contrôleurs utilisateur et trajet. Pour
gérer tous les contrôleurs à partir de notre page d’accueil unique controleurFrontal.php
,
nous avons besoin d’appeler le bon contrôleur dans le routeur.
Désormais, nous devons donc spécifier le contrôleur demandé dans le query
string. Par exemple, l’ancienne page controleurFrontal.php?action=afficherListe
du contrôleur
voiture devra s’obtenir avec controleurFrontal.php?controleur=voiture&action=afficherListe
.
-
Définissez une variable
controleur
danscontroleurFrontal.php
en récupérant sa valeur à partir de l’URL, et en mettant le contrôleur voiture par défaut.Aide : Ce bout de code est similaire à celui concernant
action
danscontroleurFrontal.php
. -
On souhaite créer le nom de la classe à partir de
controleur
. Par exemple, quand$controleur="voiture"
, nous souhaitons créer une variable$nomDeClasseControleur
qui vaut"App\Covoiturage\Controleur\ControleurVoiture"
.
Créez la variable$nomDeClasseControleur
à l’aide de la fonctionucfirst
(UpperCase FIRST letter) qui sert à mettre en majuscule la première lettre d’une chaîne de caractère. -
Testez si la classe de nom
$nomDeClasseControleur
existe à l’aide de la fonctionclass_exists
et appelez l’actionaction
de la classe$nomDeClasseControleur
le cas échéant. Autrement appelez l’actionafficherErreur
deControleurVoiture
. -
Testez votre code en appelant vos anciennes pages du contrôleur voiture.
Début du nouveau contrôleur
Maintenant que notre routeur dans le contrôleur frontal est en place, nous
pouvons créer de nouveaux contrôleurs. Pour avoir un aperçu de l’étendu du
travail, commençons par créer l’action afficherListe
de Utilisateur
.
-
Créez un contrôleur
controleur/ControleurUtilisateur.php
similaire à celui des voitures qui reprend les méthodesafficherListe()
,afficherVue()
etafficherErreur()
.Astuce : Vous pouvez utiliser la fonction de remplacement (
Ctrl+R
sous PHPStorm) pour remplacer tous lesvoiture
parutilisateur
. En cochantPréserver la casse
(Preserve case
), vous pouvez faire en sorte de respecter les majuscules lors du remplacement. -
Créez une classe
DataObject/Utilisateur.php
basé sur votre classeUtilisateur
des TDs 2 & 3. Ce modèle ne contiendra que les getter, les setter et le constructeur. -
Créez une classe
Repository/UtilisateurRepository.php
qui reprend la fonctiongetUtilisateurs()
etconstruireDepuisTableau($utilisateurTableau)
de votre ancienne classeUtilisateur
.Corrigez l’erreur : il manque un alias avec
use
pour la classeUtilisateur
. -
Créez une vue
src/vue/utilisateur/liste.php
similaire à celle des voitures (sans nécessairement de lien pour l’instant).
Idem pourutilisateur/erreur.php
. -
Testez votre action en appelant l’action
afficherListe
du contrôleurUtilisateur
(qui est accessible dans la barre de menu de votre site normalement).
Modèle générique
L’implémentation du CRUD pour les utilisateurs et les trajets est un code très similaire à celui pour les voitures. Nous pourrions donc copier/coller le code des voitures et changer les (nombreux) endroits nécessaires. Et cela contredit le principe DRY que vous connaissez depuis l’an dernier.
Création d’un modèle générique
Pour éviter la duplication de code et la perte d’un temps conséquent à
développer le CRUD pour chaque nouvel objet, nous allons mettre en commun le
code autant que possible. Commençons par abstraire les 3 classes métiers
Voiture
, Utilisateur
et Trajet
.
Créer une classe abstraite AbstractDataObject
dans le dossier DataObject
.
Faites hériter les autres classes de ce répertoire de AbstractDataObject
pour
correspondre au diagramme de classe ci-dessus.
Également, nous allons abstraire les classes Repository de façon à obtenir le schéma suivant :
Nous allons détailler ces changements dans les prochaines sections.
Déplaçons de VoitureRepository
vers un modèle générique AbstractRepository
toutes les requêtes SQL qui ne sont pas spécifiques aux voitures.
Commençons par la fonction getVoitures()
de VoitureRepository
. Les seules
différences entre getVoitures()
et getUtilisateurs()
sont le nom de la table
et le nom de la classe des objets en sortie. Voici donc comment nous allons
faire pour avoir un code générique :
-
Créez une nouvelle classe abstraite
abstract class AbstractRepository
et faites hériter la classeVoitureRepository
deAbstractRepository
(mot cléextends
comme en Java). - Pour qu’on puisse migrer la fonction
getVoitures()
deVoitureRepository
versAbstractRepository
, il faudrait que cette dernière puisse accèder au nom de la table. Pour cela elle va demander à toutes ses classes filles de posséder une méthodegetNomTable()
.
Ajoutez donc une méthode abstraitegetNomTable()
dansAbstractRepository
protected abstract function getNomTable(): string;
et une implémentation de
getNomTable()
dansVoitureRepository
.Question : pourquoi la visibilité de cette fonction est
protected
? -
Déplacez la fonction
getVoitures()
deVoitureRepository
versAbstractRepository
en la renommantrecuperer()
.Astuce : sur PhpStorm le moyen le plus simple pour déplacer la fonction serait Clic droit sur la déclaration de la méthode > Refactor > Move Members > Indiquer
AbstractRepository
comme classe de destination. De même pour le renommage, pensez à utiliser le refactoring. -
Utilisez
getNomTable()
dans la requête SQL derecuperer()
. PuisquegetNomTable()
est une méthode dynamique, enlevez lestatic
derecuperer()
./** * @return AbstractDataObject[] */ public function recuperer(): array
- De même,
AbstractRepository
va demander à toutes ses classes filles de posséder une méthodeconstruireDepuisTableau($objetFormatTableau)
.- Ajoutez donc une méthode abstraite dans
AbstractRepository
public abstract function construireDepuisTableau(array $objetFormatTableau) : AbstractDataObject;
- Enlevez le
static
duconstruireDepuisTableau()
deVoitureRepository
. - Mettez à jour l’appel à
construireDepuisTableau()
derecuperer()
. - Pensez à vérifier que l’implémentation de la méthode
construireDepuisTableau()
deVoitureRepository
déclare bien le type de retourVoiture
(sous-classe deAbstractDataObject
). - La méthode
construireDepuisTableau()
devientprotected
dans les classes filles.
- Ajoutez donc une méthode abstraite dans
-
Corrigez l’action
afficherListe
duControleurVoiture
pour faire appel à la méthoderecuperer()
deVoitureRepository
. Ici nous vous conseillons pour le moment de construire un objet anonyme afin de pouvoir appeler les fonctions dynamiques deVoitureRepository
. Par exemple, si vous souhaitez appeler la fonctionrecuperer
, vous pouvez faire ceci :(new VoitureRepository())->recuperer();
L’action
afficherListe
du contrôleur voiture doit remarcher. - Mettez à jour tous vos appels à
getVoitures()
(ourecuperer()
si la méthodegetVoitures()
a été correctement renommé par le refactoring de la question 3).
- Faites de même pour
UtilisateurRepository
:- commentez
getUtilisateurs()
, - enlevez le
static
deconstruireDepuisTableau()
, - implémentez
getNomTable()
, UtilisateurRepository
doit hériter deAbstractRepository
.
- commentez
- Corrigez l’action
afficherListe
duControleurUtilisateur
pour faire appel à la méthoderecuperer()
deUtilisateurRepository
. L’action doit remarcher.
Action afficherDetail
Pour faciliter les actions afficherDetail
des différents contrôleurs, nous allons créer
une fonction recupererParClePrimaire($valeurClePrimaire)
générique dans AbstractRepository
qui permet de faire une recherche par clé primaire dans une table. Cette
fonction a besoin de connaître le nom de la clé primaire. Nous allons donc
demander aux implémentations de AbstractRepository
de fournir une méthode
getNomClePrimaire()
.
- Commençons par déclarer la fonction suivante dans la classe
AbstractRepository
:public function recupererParClePrimaire(string $valeurClePrimaire): ?AbstractDataObject
Copiez/collez le corps de la fonction
getVoitureParImmatriculation($immatriculation)
versrecupererParClePrimaire($valeurClePrimaire)
deAbstractRepository
. Nous allons le refactoriser dans les questions suivantes pour qu’il devienne générique. - Ajoutez la méthode suivante dans
AbstractRepository
protected abstract function getNomClePrimaire(): string;
et une implémentation de
getNomClePrimaire()
dansVoitureRepository
. -
Utilisez
getNomTable()
etgetNomClePrimaire()
pour construire la requête SQL derecupererParClePrimaire()
. - Finissez de corriger
recupererParClePrimaire()
:- Changez les valeurs dans le tableau donné à
execute()
- Corrigez l’appel à
construireDepuisTableau()
qui est une méthode dynamique maintenant.
- Changez les valeurs dans le tableau donné à
- Corrigez l’action
afficherDetail
duControleurVoiture
pour faire appel à la méthoderecupererParClePrimaire()
deVoitureRepository
. L’action doit remarcher.
-
Faites de même pour
UtilisateurRepository
: implémentezgetNomClePrimaire()
. -
Créez l’action
afficherDetail
duControleurUtilisateur
en vous basant sur celle deControleurVoiture
.Rappel : Utilisez le remplacement
Ctrl+R
en préservant la casse pour vous faciliter le travail. -
Il ne vous reste plus qu’à créer la vue associée
detail.php
et à ajouter les liens vers la vue de détail dansliste.php
. L’actionafficherDetail
doit maintenant fonctionner.
Action supprimer
Pas de nouveautés.
Nous vous laissons migrer la fonction
supprimerParImmatriculation($immatriculation)
de VoitureRepository
vers
AbstractRepository
en la renommant supprimer($valeurClePrimaire)
et adapter
sa requête SQL. Adaptez également l’action supprimer
des contrôleurs
voiture et utilisateur, ainsi que leur vue associée voitureSupprimee.php
et
utilisateurSupprime.php
.
Action afficherFormulaireCreation
et afficherFormulaireMiseAJour
Pas de nouveautés.
Nous vous laissons adapter les actions afficherFormulaireCreation
et afficherFormulaireMiseAJour
de
ControleurVoiture
(et ControleurUtilisateur
), leurs vues associées formulaireCreation.php
et
formulaireMiseJour.php
et à ajouter les liens pour mettre à jour un utilisateur ou une voiture dans
detail.php
.
Action creerDepuisFormulaire
et mettreAJour
Pour ces dernières actions, il faut un peu plus travailler pour créer la fonction correspondante dans le modèle générique.
Action mettreAJour
Pour reconstituer la requête
UPDATE voiture SET marque= :marqueTag, couleur= :couleurTag, immatriculation= :immatriculationTag WHERE immatriculation= :immatriculationTag;
il est nécessaire de pouvoir lister les champs de la table voiture
. De même, il sera nécessaire de lister
les champs des tables utilisateur
et trajet
. Nous allons factoriser le code nécessaire dans AbstractRepository
.
- Déplacez la fonction
mettreAJour($immatriculation)
deVoitureRepository.php
versAbstractRepository
en la renommantpublic function mettreAJour(AbstractDataObject $object): void
- Ajoutez une méthode abstraite
getNomsColonnes()
dansAbstractRepository
protected abstract function getNomsColonnes(): array;
et une implémentation de
getNomsColonnes()
dansVoitureRepository
protected function getNomsColonnes(): array { return ["immatriculation", "marque", "couleur", "nbSieges"]; }
- Utilisez
getNomTable()
,getNomClePrimaire()
etgetNomsColonnes()
pour construire la requête SQL demettreAJour()
:UPDATE voiture SET marque= :marqueTag, couleur= :couleurTag, immatriculation= :immatriculationTag WHERE immatriculation= :immatriculationTag;
Aide : N’hésitez pas à afficher la requête générée pour vérifier votre code.
- Pour les besoins de
execute()
, nous avons besoin de transformer l’objetVoiture $voiture
en un tableauarray( "immatriculationTag" => $voiture->getImmatriculation(), "marqueTag" => $voiture->getMarque(), "couleurTag" => $voiture->getCouleur(), "nbSiegesTag" => $voiture->getNbSieges(), );
Nous allons demander à tous les
AbstractDataObject
d’implémenter une méthodeformatTableau()
qui transforme unAbstractDataObject
en tableau, qui pourrait être utilisé dans les différents appels àexecute()
. Ainsi, nous pouvons imposer cette méthode directement par contrat dansAbstractDataObject
:public abstract function formatTableau(): array;
Implémentez cette fonction dans
Voiture
avecpublic function formatTableau(): array { return array( "immatriculationTag" => $this->immatriculation, "marqueTag" => $this->marque, "couleurTag" => $this->couleur, "nbSiegesTag" => $this->nbSieges, ); }
-
Utilisez
formatTableau()
dansmettreAJour()
pour obtenir le tableau donné àexecute()
. - Corrigez l’action
mettreAJour
duControleurVoiture
pour faire appel aux méthodes deVoitureRepository
. L’action doit remarcher.
Implémentez l’action mettreAJour
du contrôleur utilisateur.
Action creerDepuisFormulaire
Répétez la question précédente avec la fonction ajouter()
des différents
modèles. Ajoutez l’action creerDepuisFormulaire
dans le contrôleur
utilisateur.
Bonus
Contrôleur trajet
Adaptez chacune des actions de ControleurTrajet.php
et les tester une à
une. Nous vous conseillons de faire dans l’ordre les actions afficherDetail
, supprimer
,
afficherFormulaireCreation
, afficherFormulaireMiseAJour
, creerDepuisFormulaire
et mettreAJour
.
Vous pouvez aussi ajouter des actions pour afficher la liste des passagers pour
un trajet, et inversement la liste des trajets pour un passager (table de
jointure passager
, cf. fin TD3).
Autres idées
- Factoriser le code des contrôleurs dans un contrôleur générique, au moins pour
la méthode
afficherVue()
- Ajouter les actions spécifiques aux requêtes SQL
getTrajets()
etsupprimerPassager()
du TD3 non utilisées :- qui liste les trajets d’un utilisateur,
- qui désinscrit un passager d’un trajet.