- Accueil
- Programmation Web S2
- Index du sujet de TP
- Objectifs de la séance
- Introduction
- Versionnage du projet
- Copie de la base de données
- Création, édition et suppression d'entités
Artist
- Suppression d'un «
Artist
» - Test de la suppression d'un «
Artist
» - Enregistrement d'un «
Artist
» - Test de l'enregistrement d'un «
Artist
» - Création d'une instance de «
Artist
» - Test de la création d'une instance de «
Artist
» - Insertion d'un «
Artist
» - Test de l'enregistrement d'une nouvelle instance de «
Artist
»
- Suppression d'un «
- Formulaire de création et d'édition d'une entité
Artist
, traitement des données de la « query string »- Formulaire pour un «
Artist
» - Protection des chaînes de caractères issues de la base de données, trait «
StringEscaper
» - Test de la classe «
ArtistForm
» - Protection des chaînes de caractères issues de l'utilisateur
- Construire un «
Artist
» à partir de la « query string » - Test de la création d'une instance de «
Artist
»
- Formulaire pour un «
- Création, édition et suppression d'entités
Artist
à travers des pages Web - Modification de l'interface utilisateur pour proposer les opérations de modification des artistes
- Affichage de la liste des albums sous forme de grille
- Vers un menu intégré à «
AppWebPage
» - Poursuite de la réalisation
- Sujet complémentaire
Objectifs de la séance ¶
- Élaborer des conceptions simples
- Concevoir une interface utilisateur
- Développer une application Web
- Faire des essais et évaluer leurs résultats en regard des spécifications
- Mettre en place les outils de gestion de projet
- Être sensibilisé à la production de tests unitaires
Introduction ¶
L'application comporte maintenant la consultation de la liste des artistes et de leurs albums avec une interface utilisateur. L'objectif est de permettre la création, l'édition et la suppression de données. Vous réaliserez ces opérations sur les artistes.
Versionnage du projet ¶
Ce sujet est une partie du sujet principal. Vous poursuivrez avec le même dépôt Git
et la même méthodologie.
Copie de la base de données ¶
Vous utilisiez jusqu'à présent la base de données MySQL
« cutron01_music
» en lecture seule. Puisque vous allez développer de fonctionnalités nécessitan,t d'écrire dans la base de données, vous avez besoin de travailler sur votre propre copie de cette base.
Travail à réaliser
- Rendez-vous sur le serveur
phpMyAdmin
du département : http://phpmyadmin/ - Connectez-vous avec votre identifiant URCA, le mot de passe est également votre identifiant URCA si c'est votre première connexion
- Modifiez ce mot de passe par défaut en n'utilisant pas le même mot de passe que pour votre connexion au système
- Vérifiez que vous avez accès à une base donnée du même nom que votre identifiant ainsi que la base «
cutron01_music
» - Cliquez sur la base de données «
cutron01_music
» - Cliquez sur le menu « Opérations »
- Dans la partie « Copier la base de données vers », saisissez «
votre_login_music
» comme nom de base - Après quelques secondes d'attente, vérifiez que vous avez votre propre copie de la base
Information
Si vous avez de nouveau besoin de copier cette base de données (si vous avez supprimé ou modifié trop d'éléments), supprimez-la avant de refaire les opérations précédentes.
- Ajoutez «
/.mypdo.ini
» dans le fichier «.gitignore
»Remarque importanteVotre identifiant et mot de passe
MySQL
doivent rester confidentiels. Pour cela, vous allez exclure «.mypdo.ini
» de l'indexGit
. - Supprimez le fichier «
.mypdo.ini
» de l'indexGit
avec la commande :git rm --cached .mypdo.ini
- Effectuez un
commit
pour valider le fichier «.gitignore
» et la suppression de «.mypdo.ini
» de l'indexGit
- Modifiez le fichier «
.mypdo.ini
» pour remplacer «cutron01_music
» par «votre_login_music
» et saisir votre identifiant et votre tout nouveau mot de passeMySQL
- Vérifiez que l'application est toujours fonctionnelle dans votre navigateur
Création, édition et suppression d'entités Artist
¶
La couche d'abstraction d'accès à la base de données pour les artistes ne comporte actuellement que l'opération de lecture. Pour fournir une interface complète d'accès aux données, il faut encore implémenter la création, la modification et la suppression d'une entité Artist
.
La classe « Artist
» va évoluer au fil de cette partie pour devenir :
Suppression d'un « Artist
»
¶
L'opération la plus simple est certainement la suppression dans la base de données. En effet, un objet « Artist
» possédant un identifiant est supprimé de la base de données en une requête. Elle demande cependant quelques ajustements. En effet, il convient de répercuter la suppression sur l'objet PHP
, en « effaçant » la valeur de l'identifiant dans l'instance. Pour cela, il faut pouvoir interagir avec les propriétés de l'objet, c'est-à-dire avoir accès à des mutateurs (« setters »), qui n'existent pas encore dans la classe. Dernière subtilité, la propriété « id
» doit être « nullable » et ceci doit être propagé à l'accesseur et au mutateur de la propriété. Pour faciliter la modification de la classe, vous allez supprimer les accesseurs et les générer à nouveau à l'aide de PhpStorm
, et vous générerez des mutateurs fluides par la même occasion.
Travail à réaliser
- Effacez les accesseurs de la classe «
Artist
» - Modifiez le type de la propriété «
id
» pour le rendre « nullable » - Utilisez
PhpStorm
pour générer les accesseurs et les modificateurs fluides (« fluent » en anglais) de propriétés «id
» et «name
»InformationLe code généré sera inséré à l'endroit où se situe le curseur texte. Visez bien !
- Modifiez la visibilité du mutateur «
setId()
» pour le rendre privéInformationL'identifiant est une donnée sensible pour les interactions avec la base de données. Seule la classe doit être autorisée à le modifier.
- Ajoutez la méthode d'instance «
delete
» qui a pour objectifs de :- supprimer la ligne correspondante à l'«
id
» dans la base de données - mettre «
null
» dans la propriété «id
» de l'instance - retourner l'instance courante pour permettre le chaînage des méthodes
Remarque importantePour des raisons de performance, toutes vos requêtes doivent être préparées, et si nécessaire paramétrées, pour des raisons de sécurité. Toute substitution de variable dans une requête est une faille de sécurité potentielle !
- supprimer la ligne correspondante à l'«
Test de la suppression d'un « Artist
»
¶
La méthode de suppression que vous venez d'écrire doit être testée.
Travail à réaliser
- Ajoutez la méthode suivante au « Cest » «
Crud
» dédié à la classe «Artist
» :public function delete(CrudTester $I) { $artist = Artist::findById(4); $artist->delete(); $I->cantSeeInDatabase('artist', ['id' => 4]); $I->cantSeeInDatabase('artist', ['name' => 'Slipknot']); $I->assertNull($artist->getId()); $I->assertSame('Slipknot', $artist->getName()); }
- Vérifiez que les tests passent
Enregistrement d'un « Artist
»
¶
Lorsque le nom d'un artiste est modifié, ce changement doit être enregistré en base de données et une requête base de données doit donc être exécutée. Pour l'instant, seuls des « Artist
» dont les données sont issues de la base de données peuvent exister. L'opération d'enregistrement consiste donc en une mise à jour de la ligne correspondante dans la table « artist
».
Travail à réaliser
- Ajoutez la méthode d'instance «
save()
» qui a pour objectifs de :- mettre à jour le «
name
» de la table «artist
» pour la ligne dont l'«id
» est celui de l'instance courante - retourner l'instance courante pour permettre le chaînage des méthodes
Remarque importantePour des raisons de performance, toutes vos requêtes doivent être préparées, et si nécessaire paramétrées, pour des raisons de sécurité. Toute substitution de variable dans une requête est une faille de sécurité potentielle !
- mettre à jour le «
Test de l'enregistrement d'un « Artist
»
¶
La méthode d'enregistrement que vous venez d'écrire doit être testée.
Travail à réaliser
- Ajoutez la méthode suivante au « Cest » «
Crud
» dédié à la classe «Artist
» :public function update(CrudTester $I) { $artist = Artist::findById(4); $artist->setName('Nœud Coulant'); $artist->save(); $I->canSeeNumRecords(1, 'artist', [ 'id' => 4, 'name' => 'Nœud Coulant' ]); $I->assertSame(4, $artist->getId()); $I->assertSame('Nœud Coulant', $artist->getName()); }
- Vérifiez que les tests passent
Création d'une instance de « Artist
»
¶
Pour l'instant, seuls des « Artist
» dont les données sont issues de la base de données peuvent exister. Ceci empêche donc toute création d'un nouvel artiste. La combinaison du constructeur et des mutateurs permettrait de construire une nouvelle entité. Malheureusement, la récupération des données de la base de données selon la méthode « PDO::FETCH_CLASS
» appelle obligatoirement le constructeur avant ou après l'affectation des propriétés par « PDO
» et contraint la modélisation. Vous allez donc opter pour une méthode de classe qui construira une instance de « Artist
» et rendre le constructeur inaccessible en changeant sa visibilité en privée.
Travail à réaliser
- Ajoutez la méthode de classe «
create()
» qui a pour objectifs de :- créer une instance de «
Artist
» - Affecter «
name
» avec le premier paramètre de la méthode - Affecter «
id
» avec le second paramètre facultatif de la méthode - retourner l'instance créée
- créer une instance de «
- Ajoutez un constructeur privé à la classe «
Artist
»
Test de la création d'une instance de « Artist
»
¶
La méthode de création d'instance que vous venez d'écrire doit être testée.
Travail à réaliser
- Ajoutez les méthodes suivantes au « Cest » «
Crud
» dédié à la classe «Artist
» :public function createWithoutId(CrudTester $I) { $artist = Artist::create('Nœud Coulant'); $I->assertNull($artist->getId()); $I->assertSame('Nœud Coulant', $artist->getName()); } public function createWithId(CrudTester $I) { $artist = Artist::create('Nœud Coulant', 4); $I->assertSame(4, $artist->getId()); $I->assertSame('Nœud Coulant', $artist->getName()); }
- Vérifiez que les tests passent
Insertion d'un « Artist
»
¶
La méthode « save()
» précédemment écrite effectue une requête « UPDATE
». Puisqu'il est maintenant possible de créer de nouvelles instance de « Artist
», la requête d'enregistrement dans la base de données doit être de type « INSERT
». Le choix entre « UPDATE
» et « INSERT
» est fait sur la présence ou non d'un identifiant non nul dans l'instance. Vous allez donc proposer deux méthodes, « insert()
» et « update()
», entre lesquelles il faudra choisir dans la méthode « save()
» selon la valeur « null
» ou non de « id
».
Travail à réaliser
- Renommez la méthode «
save()
» en «update()
» - Ajoutez la méthode d'instance «
insert()
» qui a pour objectifs de :- exécuter la requête d'insertion dans la table «
artist
» - mettre à jour l'identifiant de l'instance courante avec le dernier identifiant créé par la base de données
- retourner l'instance courante pour permettre le chaînage des méthodes
- exécuter la requête d'insertion dans la table «
- Ajoutez la méthode d'instance «
save()
» qui a pour objectifs de :- déclencher «
insert()
» ou «update()
» selon que la valeur de «id
» est respectivement «null
» ou non - retourner l'instance courante pour permettre le chaînage des méthodes
- déclencher «
Test de l'enregistrement d'une nouvelle instance de « Artist
»
¶
La méthode d'enregistrement que vous venez d'écrire doit être testée.
Travail à réaliser
- Ajoutez les méthodes suivantes au « Cest » «
Crud
» dédié à la classe «Artist
» :/** * @after createWithoutId */ public function insert(CrudTester $I) { $artist = Artist::create('Nœud Coulant'); $artist->save(); $I->canSeeNumRecords(1, 'artist', [ 'id' => 90, 'name' => 'Nœud Coulant' ]); $I->assertSame($artist->getId(), 90); $I->assertSame('Nœud Coulant', $artist->getName()); }
- Vérifiez que les tests passent
Formulaire de création et d'édition d'une entité Artist
, traitement des données de la « query string »
¶
La couche d'abstraction d'accès à la base de données pour les artistes supporte maintenant toutes les opérations « CRUD ». L'interface de l'application doit s'enrichir pour proposer toutes ces fonctionnalités. Dans un premier temps, vous allez uniquement vous intéresser à la partie formulaire HTML
et au traitement des données de la « query string » dans une classe dédiée.
Formulaire pour un « Artist
»
¶
La création ou la modification d'un artiste nécessite une interface de saisie du nom de l'artiste. L'identifiant n'est pas directement géré par l'utilisateur. La saisie d'un artiste peut être réalisée dans formulaire HTML
avec un champ caché contenant l'identifiant et un champ de type texte pour le nom, sans oublier un bouton de validation de la saisie. La différence entre la création ou la modification d'un artiste réside dans la présence ou non d'un identifiant et d'une valeur existante pour le texte du nom. Dans un cadre orienté objet, vous allez définir une classe « ArtistForm
» dont la première mission sera de produire le code HTML
du formulaire, avec des valeurs préremplies en fonction des caractéristiques de l'utilisateur dans le cas d'une modification.
Travail à réaliser
- Créez la classe «
ArtistForm
» à l'aide dePhpStorm
- Ajoutez la propriété «
artist
» issue de la relation avec la classe «Artist
», sachant qu'un artiste n'est pas nécessairement présent - Utilisez
PhpStorm
pour générer le constructeur - Utilisez
PhpStorm
pour l'accesseur sur la propriété «artist
» - Écrivez la méthode «
getHtmlForm()
» :- le paramètre représente l'
URL
de l'action - le formulaire utilisera la méthode
POST
- les champs portent le nom de la propriété correspondante de «
Artist
» - le champ dédié à l'identifiant est caché et reçoit la valeur de l'identifiant de l'instance de «
Artist
» - le champ dédié au nom est obligatoire et reçoit la valeur du nom de l'instance de «
Artist
»InformationPuisque l'objet «
Artist
» contenu dans le «ArtistForm
» peut êtrenull
, il est important d'effectuer des contrôles avant d'essayer d'accéder à ses accesseurs. Pour une syntaxe plus simple et élégante, vous pouvez utiliser l'opérateur « nullsafe » «?->
» - le champ dédié au nom comporte un «
label
» « Nom » - le bouton d'envoi porte le texte « Enregistrer »
- le paramètre représente l'
Protection des chaînes de caractères issues de la base de données, trait « StringEscaper
»
¶
Si le formulaire HTML
produit par « ArtistForm
» fonctionne normalement, le nom d'un artiste existant doit se trouver dans l'attribut « value="…"
» d'une balise « <input
». Si le nom de l'artiste contient le caractère guillemet « "
», le champ de saisie généré devient incohérent avec « <input … value="…"…"
». Comme vous l'avez fait par le passé, il faut échapper le nom de l'artiste avec l'équivalent de la méthode « escapeString()
» de « WebPage
». Cette fonctionnalité n'est pas accessible à la classe « ArtistForm
» qui n'a pas accès à « WebPage
». Cependant, la fonctionnalité de « WebPage
», désirée dans « ArtistForm
», est strictement la même. Aucun mécanisme d'héritage simple ne permet de lier naturellement les deux classes. Dans ce type de situation, où la fonctionnalité doit être mise en commun sans utiliser l'héritage, la solution est apportée par les traits. La méthode « escapeString
» va donc être extraite de « WebPage
» vers un trait
« StringEscaper
». Le trait sera ensuite utilisé dans « WebPage
» et « ArtistForm
».
Travail à réaliser
- Créez le trait «
Html\StringEscaper
» à l'aide dePhpStorm
- Déplacez la méthode «
escapeString()
» de la classe «WebPage
» vers le trait «StringEscaper
» - Modifiez la méthode pour que son paramètre puisse être «
null
» et que la chaîne retournée soit vide dans ce cas - Utilisez le trait «
Html\StringEscaper
» dans la classe «WebPage
» - Utilisez le trait «
Html\StringEscaper
» dans la classe «ArtistForm
» - Protégez la chaîne du nom de l'artiste avant de l'utiliser dans «
ArtistForm::getHtmlForm()
»
Test de la classe « ArtistForm
»
¶
La méthode « getHtmlForm()
» de la classe « ArtistForm
» produit du code HTML
qui devrait être testé. Ce code HTML
est cependant partiel et inaccessible depuis serveur Web de test. Il demande donc une méthodologie de test particulière. Nous avons développé un assistant Codeception
dédié à ce type de tâche.
Travail à réaliser
- Placez le fichier de l'assistant «
Dom
» (télécharger) dans «tests/_support/Helper/
» - Ouvrez ce nouveau fichier dans
PhpStorm
et corrigez les avertissements en ajoutant automatiquement «ext-dom
» et «ext-libxml
» dans «require-dev
» du fichier «composer.json
» - Créez une nouvelle suite de « Cest » «
Form
»php vendor/bin/codecept generate:suite Form
- Modifiez le fichier «
Form.suite.yml
» de configuration de la suite pour activer l'assistant «Dom
» - Placez le fichier de « Cest » «
ArtistForm
» (télécharger) dans «tests/Form/
» - Lancez les tests de la suite «
Form
» :php vendor/bin/codecept run Form
- Corrigez votre classe si nécessaire
- Ajoutez un script «
test:form
» dans «composer.json
» - Mettez à jour la documentation du projet dans «
README.md
»
Protection des chaînes de caractères issues de l'utilisateur ¶
Lorsque l'utilisateur aura la possibilité de saisir un nom d'artiste, il est primordial de contrôler et de maîtriser ce qu'il transmet avant de l'insérer dans la base de données. Vous effectuerez un nettoyage du nom de l'artiste et, à titre purement arbitraire et par choix applicatif une suppression des balises, avant de l'insérer dans la base de données. Plus précisément, ce traitement aura lieu au moment de l'affectation des valeurs dans l'entité « Artist
» issue des données utilisateur. Les transformations s'apparentant à de l'échappement de chaîne de caractères, elles seront mises en œuvre dans le trait « StringEscaper
» sous la forme de la méthode d'instance « stripTagsAndTrim()
» dont le nom est hautement explicite.
Travail à réaliser
Dans le trait « StringEscaper
», ajoutez la méthode d'instance « stripTagsAndTrim()
» qui a pour objectifs de :
- supprimer les balises
- supprimer les espaces en tête et en queue de chaîne
- retourner une chaîne vide si la valeur est «
null
»
Construire un « Artist
» à partir de la « query string »
¶
Le formulaire HTML produit par la classe « Artistform
» propose une interface de saisie à l'utilisateur. Les données saisies, une fois transmises au serveur Web, doivent être contrôlées et traitées pour permettre la modification de la base de données. Puisque la tâche de contrôle et de traitement est symétrique et complémentaire à la production du formulaire HTML
, elle va être placée sous la responsabilité de la classe « ArtistForm
» qui va s'enrichir d'une méthode « setEntityFromQueryString()
». Son rôle sera de contrôler les données de la « query string », de construire une entité « Artist
» et de l'affecter à la propriété « artist
» :
Travail à réaliser
Dans la classe « ArtistForm
», ajoutez la méthode d'instance « setEntityFromQueryString()
» qui a pour objectifs de :
- Extraire les données constitutives d'un artiste depuis la « query string »
POST
- l'identifiant de l'artiste s'il est présent et numérique, «
null
» sinon - le nom de l'artiste s'il est présent, lever une «
ParameterException
» sinon
- l'identifiant de l'artiste s'il est présent et numérique, «
- Créer un artiste avec les données extraites et nettoyées
- Affecter l'artiste créé à la propriété d'instance
Test de la création d'une instance de « Artist
»
¶
La méthode « setEntityFromQueryString()
» que vous venez d'écrire doit être testée.
Travail à réaliser
- Activez le module «
Asserts
» dans «Form.suite.yml
» - Ajoutez les méthodes suivantes au « Cest » «
Form
» dédié à la classe «ArtistForm
» :/** * @dataProvider artistNameProvider */ public function getNewArtistDataFromQueryString(FormTester $I, Example $example) { $_POST['id'] = ''; $_POST['name'] = $example['name']; $form = new ArtistForm(); $form->setEntityFromQueryString(); $I->assertInstanceOf(Artist::class, $form->getArtist()); $I->assertNull($form->getArtist()->getId()); $I->assertSame($example['expectedName'], $form->getArtist()->getName()); } /** * @dataProvider artistNameProvider */ public function getExistingArtistDataFromQueryString(FormTester $I, Example $example) { $_POST['id'] = '90'; $_POST['name'] = $example['name']; $form = new ArtistForm(); $form->setEntityFromQueryString(); $I->assertInstanceOf(Artist::class, $form->getArtist()); $I->assertSame(90, $form->getArtist()->getId()); $I->assertSame($example['expectedName'], $form->getArtist()->getName()); } protected function artistNameProvider(): array { return [ ['name' => 'Artist', 'expectedName' => 'Artist'], ['name' => ' Artist ', 'expectedName' => 'Artist'], ['name' => '
Artist
', 'expectedName' => 'Artist'], ['name' => 'Artist
', 'expectedName' => 'Artist'], ]; } public function missingArtistNameFromQueryStringThrowsException(FormTester $I) { $I->expectThrowable(ParameterException::class, function () { $_POST['id'] = ''; $_POST['name'] = ''; (new ArtistForm())->setEntityFromQueryString(); }); } - Vérifiez que les tests passent
Création, édition et suppression d'entités Artist
à travers des pages Web
¶
La couche d'abstraction d'accès à la base de données pour les artistes supporte toutes les opérations « CRUD ». La classe « ArtistForm
» fournit les fonctionnalités de production du formulaire HTML
et son traitement poour l'ajout ou la modification d'un « Artist
». Il ne reste plus qu'à écrire les programmes qui utilisent ces composants. Ils seront localisés dans « public/admin/
».
Interface de création ou d'édition d'un « Artist
»
¶
Le programme « artist-form.php
» va permettre de proposer le formulaire de création ou de modification d'un artiste. Pour cela, il admet un paramètre HTTP
facultatif « artistId
» qui désigne l'identifiant de l'artiste à éditer. Si ce paramètre est absent, le programme propose la création d'un nouvel artiste.
Travail à réaliser
- Créez le programme «
public/admin/artist-form.php
» dont la structure de base sera la même que ce qui vous a été fourni pour «cover.php
» : - Testez la présence du paramètre
GET
«artistId
» :- S'il est absent, poursuivez en considérant que l'artiste est «
null
» - S'il est présent
- testez sa forme numérique et levez une «
ParameterException
» en cas de non conformité - recherchez l'artiste correspondant à l'identifiant dans la base de données
- testez sa forme numérique et levez une «
- S'il est absent, poursuivez en considérant que l'artiste est «
- Construisez une instance de «
ArtistForm
» que vous utiliserez pour produire un formulaireHTML
soumettant les données vers «artist-save.php
»
Test de « artist-form.php
»
¶
Vérifions si votre programme passe les tests.
Travail à réaliser
- Placez le fichier de « Cest » pour l'édition d'un artiste (télécharger) dans «
tests/Browse/
» - Lancez les tests de la suite «
Browse
» :composer test:browse
- Corrigez votre programme et vos classes si nécessaire
Création ou édition d'un artiste ¶
L'interface utilisateur est fonctionnelle. Il faut à présent écrire le programme « artist-save.php
» qui reçoit et traite les données soumises par l'utilisateur.
Travail à réaliser
- Reprenez la structure de base du programme précédent pour «
artist-save.php
» - Supprimez la gestion des exceptions de type «
EntityNotFoundException
» qui n'ont pas de sens ici - Effectuez les actions nécessaires au traitement des données contenues dans la « query string »
POST
:- Construisez un «
ArtistForm
» - Utilisez-le pour construire l'entité «
Artist
» à partir de la « query string » - Enregistrez l'«
Artist
» obtenu - Redirigez vers l'accueil du site
- Construisez un «
Test de « artist-save.php
»
¶
La validité du programme « artist-save.php
» doit être testée. Cependant, puisque cette opération modifie le contenu de la base de données, cette dernière doit être réinitialisée avant chaque test. Pour cela, le module « Db
» de Codeception
doit être activé.
Travail à réaliser
- Activez le module «
Db
» deCodeception
dans le fichier «tests/Browse.suite.yml
» - Ajoutez les méthodes suivantes au « Cest » «
Browse
» dédié à la modification des artistes :/** * @depends loadNewArtistFormPage */ public function insertArtist(BrowseTester $I) { $I->stopFollowingRedirects(); $I->amOnPage('/admin/artist-form.php'); $I->submitForm('form', ['name' => 'NewArtist']); $I->seeInCurrentUrl('/admin/artist-save.php'); $I->seeResponseCodeIs(302); $I->seeNumRecords(1, 'artist', ['name' => 'NewArtist']); } /** * @depends loadNewArtistFormPage */ public function insertArtistWithMissingName(BrowseTester $I) { $I->amOnPage('/admin/artist-form.php'); $I->submitForm('form', ['name' => '']); $I->seeInCurrentUrl('/admin/artist-save.php'); $I->seeResponseCodeIs(400); $I->seeNumRecords(0, 'artist', ['name' => '']); } /** * @depends loadExistingArtistFormPage */ public function updateArtist(BrowseTester $I) { $I->stopFollowingRedirects(); $I->amOnPage('/admin/artist-form.php?artistId=4'); $I->submitForm('form', ['name' => 'UpdatedArtist']); $I->seeInCurrentUrl('/admin/artist-save.php'); $I->seeResponseCodeIs(302); $I->seeNumRecords(1, 'artist', [ 'id' => 4, 'name' => 'UpdatedArtist' ]); } /** * @depends loadExistingArtistFormPage */ public function updateArtistWithMissingName(BrowseTester $I) { $I->amOnPage('/admin/artist-form.php?artistId=4'); $I->submitForm('form', ['name' => '']); $I->seeInCurrentUrl('/admin/artist-save.php'); $I->seeResponseCodeIs(400); $I->seeNumRecords(1, 'artist', [ 'id' => 4, 'name' => 'Slipknot' ]); }
- Vérifiez que les tests passent
Suppression d'un artiste ¶
La suppression d'un artiste ne nécessite pas d'interface utilisateur particulière. Il faut néanmoins écrire le programme « artist-delete.php
» qui supprime l'utilisateur dont l'identifiant est passé dans la « query string » GET
.
Travail à réaliser
- Reprenez la structure de base du programme précédent pour «
artist-delete.php
» - Gérez le contrôle de présence et de validité du paramètre
GET
«artistId
» - Chargez l'«
Artist
» depuis la base de données - Supprimez l'«
Artist
» sélectionné - Redirigez vers l'accueil du site
Test de « artist-delete.php
»
¶
Contrôlons la validité de « artist-delete.php
».
Travail à réaliser
- Ajoutez les méthodes suivantes au « Cest » «
Browse
» dédié à la modification des artistes :public function deleteArtist(BrowseTester $I) { $I->stopFollowingRedirects(); $I->amOnPage('/admin/artist-delete.php?artistId=4'); $I->seeResponseCodeIs(302); $I->seeNumRecords(0, 'artist', [ 'id' => 4, ]); } public function deleteArtistWithoutId(BrowseTester $I) { $I->amOnPage('/admin/artist-delete.php'); $I->seeResponseCodeIs(400); $I->seeNumRecords(8, 'artist'); } /** * @example { "id": "", "code": 400 } * @example { "id": "1000", "code": 404 } * @example { "id": "id", "code": 400 } */ public function deleteArtistWithWrongId(BrowseTester $I, Example $example) { $I->amOnPage('/admin/artist-delete.php?artistId=' . $example['id']); $I->seeResponseCodeIs($example['code']); $I->seeNumRecords(8, 'artist'); }
- Vérifiez que les tests passent
Modification de l'interface utilisateur pour proposer les opérations de modification des artistes ¶
Les nouvelles fonctionnalités de création, d'édition et de suppression d'un artiste doivent trouver leur place dans l'interface utilisateur. Une première approche simple va consister à modifier les programmes « index.php
» et « artist.php
» pour insérer un menu rudimentaire dans le conteneur « .content
» :
Travail à réaliser
- Ajoutez la structure du menu dans «
index.php
» en respectant la maquette fournie - Ajoutez la structure du menu dans «
artist.php
» en respectant la maquette fournie - Modifiez la feuille de style pour que le menu s'approche du rendu désiré dans les maquettes
Affichage de la liste des albums sous forme de grille ¶
La liste des albums d'un artiste serait plus appropriée sous forme de grille :
Travail à réaliser
- Modifiez temporairement «
artist.php
» pour que la liste des albums appartienne à la classeCSS
«list
» et «grid
» - Modifiez la feuille de style associée à la classe
CSS
«.grid
» pour que la liste des albums ressemble à la maquette - Ajoutez un lien dans le menu permettant de passer de l'affichage liste à l'affichage grille en modifiant la classe
CSS
de la listeInformationLes titres d'albums trop longs peuvent être tronqués en
CSS
à l'aide de la propriété «text-overflow: ellipsis
» associée à «overflow: hidden;
» et «white-space: nowrap;
». - Supprimez la classe
CSS
«grid
» temporairement ajoutée à la liste des albums dans «artist.php
»
Vers un menu intégré à « AppWebPage
»
¶
Les menus de « index.php
» et « artist.php
» sont cohérents mais mériteraient d'être intégrés partiellement à la classe « AppWebPage
». Ceci permettrait également d'homogénéiser l'utilisation du menu dans l'ensemble des pages du site.
Travail à réaliser
- Modifiez la classe «
AppWebPage
» pour qu'elle gère un menu :- Stockage du contenu du menu
- Ajout de contenu au menu
- Structuration
HTML
du menu dans un conteneur «.menu
» entre «.header
» et «.content
»
- Modifiez «
index.php
» et «artist.php
» pour qu'ils utilisent les nouvelles fonctionnalités de «AppWebPage
» concenant le menu
Poursuite de la réalisation ¶
Les bases qui ont été posées vous permettent d'écrire les classe et les programmes qui serviront à poursuivre l'exploration et l'édition de la base de données des morceaux de musique.
Travail à réaliser
- Listez les pistes et morceaux d'un album
- Complétez les fonctionnalités des classes, par exemple pour la classe «
Album
» : - Donnez les possibilités d'édition des albums
- Listez les genres et albums associés
- Donnez les possibilités d'édition d'un morceau, d'un genre ou d'une piste
- …
Sujet complémentaire ¶
Vous pouvez approfondir vos connaissances en vous initiant à la manipulation d'images en PHP
.