SQL sait très bien faire cela, à condition de disposer d’un moyen pour rap-procher une ligne de la table Film de la l’unique ligne de la table Artiste qui contient les informations sur l
Trang 1$ r e q u e t e = " DELETE FROM S e s s i o n W e b "
" WHERE i d _ s e s s i o n = ’ { $ t h i s−>s e s s i o n −>i d _ s e s s i o n } ’ " ;
$ r e s u l t a t = $ t h i s−>bd−>execRequete ( $ r e q u e t e ) ;
$ t h i s−>s e s s i o n = n u l l ;
$ t h i s−>vue−>contenu = " Vous ê t e s maintenant déconnecté !\n " ;
}
e l s e
$ t h i s−>vue−>contenu = " Vous n ’ ê t e s pa s encore connecté !\n " ; / / R a f r a i c h i s s e m e n t d e l a p a r t i e du c o n t e n u q u i m o n t r e s o i t / / un f o r m u l a i r e d e c o n n e x i o n , s o i t un l i e n d e d é c o n n e x i o n
$ t h i s−>s t a t u t C o n n e x i o n ( ) ;
echo $ t h i s−>vue−>r e n d e r ( " page " ) ;
}
Il se peut que logout() ne soit pas appelé par un internaute qui a simplement quitté le site sans passer par logout, et que l’information sur la session, bien que devenue invalide, reste dans la base On peut au choix la garder à des fins statistiques,
ou nettoyer régulièrement les sessions obsolètes
Figure 7.1 — Page d’accueil après identification d’un internaute
Trang 27.2 RECHERCHE, PRÉSENTATION, NOTATION DES FILMS
Nous en arrivons maintenant aux fonctionnalités principales du site WEBSCOPE, à savoir rechercher des films, les noter et obtenir des recommandations Tout ce qui suit fait partie du contrôleur Notation Nous utilisons explicitement des requêtes SQL pour simplifier l’exposé, une amélioration possible étant de suivre scrupuleusement
le MVC en définissant des modèles
7.2.1 Outil de recherche et jointures SQL
La recherche repose sur un formulaire, affiché dans la figure 7.2, qui permet d’entrer des critères de recherche Ces critères sont :
• le titre du film ;
• le nom d’un metteur en scène ;
• le nom d’un acteur ;
• le genre du film ;
• un intervalle d’années de sortie
Figure 7.2 — Formulaire de recherche des films
Les quatre premiers champs ont chacun comme valeur par défaut « Tous », et l’intervalle de date est fixé par défaut à une période suffisamment large pour englober tous les films parus De plus, on accepte une spécification partielle du titre ou des noms Si un internaute entre « ver », on s’engage à rechercher tous les films contenant cette chaîne
Voici le formulaire, produit avec la classe Formulaire dans le cadre d’une
méthode privée du contrôleur Notation On aurait pu aussi créer un template avec
Trang 3le code HTML et y injecter la liste des genres, qui est la seule partie dynamique provenant de la base
Les champs sont groupés par trois, et affichés dans deux tableaux en mode horizontal
p r i v a t e f u n c t i o n f o r m R e c h e r c h e ( )
{
/ / R e c h e r c h e d e l a l i s t e d e s g e n r e s
$ r e s u l t a t = $ t h i s−>bd−>execRequete ( "SELECT code FROM Genre " ) ;
$ g e n r e s [ " Tous " ] = " Tous " ;
w h i l e ( $g= $ t h i s−>bd−>o b j e t S u i v a n t ( $ r e s u l t a t ) ) $ g e n r e s [ $g−>
c o d e ] = $g−>code ;
/ / C r é a t i o n du f o r m u l a i r e
$ f o r m = new F o r m u l a i r e ( "POST" , " ? c t r l = n o t a t i o n& ; a c t i o n =
r e c h e r c h e " ) ;
$form−>debutTable ( F o r m u l a i r e : : HORIZONTAL) ;
$form−>champTexte ( " T i t r e du f i l m " , " t i t r e " , " Tous " , 20) ;
$form−>champTexte ( " Metteur en s c è ne " , " n o m _ r e a l i s a t e u r " ,
" Tous " , 2 0 ) ;
$form−>champTexte ( " Acteur " , " nom_acteur " , " Tous " , 20) ;
$form−>f i n T a b l e ( ) ;
$form−>a j o u t T e x t e ( "<br / > " ) ;
$form−>debutTable ( F o r m u l a i r e : : HORIZONTAL) ;
$form−>champListe ( " Genre " , " g e nr e " , " Tous " , 3 , $ g e n r e s ) ;
$form−>champTexte ( " Année min " , " annee_min " , 1800 , 4) ;
$form−>champTexte ( " Année max " , " annee_max " , 2100 , 4) ;
$form−>f i n T a b l e ( ) ;
$form−>champValider ( " Rechercher " , " r e c h e r c h e r " ) ;
r e t u r n $form−>formulaireHTML ( ) ;
}
Requête sur une table
Dans le cas ó les champs nom_realisateur ou nom_acteur restent à « Tous »,
il ne faut pas les prendre en compte Les critères de recherche restant font tous
référence à des informations de la table Film On peut alors se contenter d’une
requête SQL portant sur une seule table, et utiliser la commande LIKE pour faire des recherches sur une partie des chaỵnes de caractères (voir Exemple 1.10, page 43) Voici la requête que l’on peut utiliser
SELECT t i t r e , annee , c o d e _ p a y s , g e n r e , i d _ r e a l i s a t e u r
FROM F i l m
WHERE t i t r e LIKE ’%$ t i t r e% ’
AND annee BETWEEN ’ $annee_min ’ AND ’ $annee_max ’
AND g e n r e LIKE ’ $ g e n r e ’
Trang 4Supposons maintenant que la variable $nom_realisateur ne soit pas égale à
« Tous » Il faut alors tenir compte du critère de sélection sur le nom du metteur
en scène pour sélectionner les films et on se retrouve face à un problème pas encore abordé jusqu’à présent : effectuer des ordres SQL impliquant plusieurs tables SQL sait très bien faire cela, à condition de disposer d’un moyen pour
rap-procher une ligne de la table Film de la (l’unique) ligne de la table Artiste qui
contient les informations sur le metteur en scène Ce moyen existe : c’est l’attribut
id_realisateur de Film qui correspond à la clé de la table Artiste, id Rapprocher les films de leur metteur en scène consiste donc, pour une ligne dans Film, à prendre
la valeur de id_realisateur et à rechercher dans Artiste la ligne portant cet id.
Voici comment on l’exprime avec SQL
SELECT t i t r e , annee , c o d e _ p a y s , g e n r e , i d _ r e a l i s a t e u r
FROM Film , A r t i s t e
WHERE t i t r e LIKE ’%$ t i t r e% ’
AND nom LIKE ’%$ n o m _ r e a l i s a t e u r% ’
AND g e n r e LIKE ’ $ g e n r e ’
AND i d _ r e a l i s a t e u r = A r t i s t e i d
Ce type d’opération, joignant plusieurs tables, est désigné par le terme de jointure.
La syntaxe reste identique, avec une succession de clauses SELECT-FROM-WHERE, mais le FROM fait maintenant référence aux deux tables qui nous intéressent, et le critère de rapprochement de lignes venant de ces deux tables est indiqué par l’égalité id_realisateur = id dans la clause WHERE
Les attributs auxquels on peut faire référence, aussi bien dans la clause WHERE
que dans la clause SELECT, sont ceux de la table Film et de la table Artiste Dans ce
premier exemple, tous les attributs ont des noms différents et qu’il n’y a donc aucune ambigụté à utiliser l’attribut nom ou annee sans dire de quelle table il s’agit MySQL sait s’y retrouver
Prenons maintenant le cas ó la variable $nom_realisateur est égale à « Tous », tandis qu’un critère de sélection des acteurs a été spécifié Le cas est un peu plus
complexe car pour rapprocher la table Film de la table Artiste, il faut impliquer également la table Role qui sert d’intermédiaire (voir chapitre 4, page 195).
Voici la requête SQL effectuant la jointure
SELECT F i l m t i t r e , annee , c o d e _ p a y s , g e n r e , i d _ r e a l i s a t e u r
FROM Film , A r t i s t e , Role
WHERE F i l m t i t r e LIKE ’%$ t i t r e% ’
AND nom LIKE ’%$ n o m _ a c t e u r% ’
AND annee BETWEEN ’ $annee_min ’ AND ’ $annee_max ’
AND g e n r e LIKE ’ $ g e n r e ’
AND i d _ a c t e u r = A r t i s t e i d
AND Role i d _ f i l m = F i l m i d
Trang 5Comme dans le cas de la jointure entre Film et Artiste pour rechercher le metteur
en scène, la jointure entre ces trois tables se fonde sur les attributs communs qui sont :
1 les attributs id et id_film dans Film et Role ;
2 les attributs id et id_acteur dans, respectivement, Acteur et Role.
Il y a ambigụté sur id puisque MySQL ne peut pas déterminer, quand on utilise
cet attribut, si on fait référence à Film ou à Artiste Pour lever cette ambigụté, on
préfixe donc le nom de l’attribut par le nom de la table d’ó il provient
Dans le cas le plus général, l’utilisateur entre une valeur pour le metteur en scène
et une pour le nom de l’acteur En indiquant par exemple « itch » dans le champ nom_realisateur et « ewa » dans le champ nom_acteur, on devrait obtenir (au
moins) le film Vertigo, dirigé par Alfred Hitchcock, et joué par James Stewart.
Il faut donc à la fois faire la jointure Film-Artiste pour le metteur en scène, et Film-Role-Artiste pour les acteurs On recherche en fait, simultanément, deux lignes dans la table Artiste, l’une correspondant au metteur en scène, l’autre à l’acteur Tout
se passe comme si on effectuait une recherche d’une part dans une table contenant tous les acteurs, d’autre part dans une table contenant tous les metteurs en scène C’est exactement ainsi que la requête SQL doit être construite On utilise deux
fois la table Artiste dans la clause FROM, et on la renomme une fois en Acteur, l’autre fois en MES avec la commande SQL AS Ensuite on utilise le nom approprié pour
lever les ambigụtés quand c’est nécessaire
SELECT F i l m t i t r e , annee , c o d e _ p a y s , g e n r e , i d _ r e a l i s a t e u r
FROM Film , A r t i s t e AS A c t e u r , A r t i s t e AS MES , Role
WHERE F i l m t i t r e LIKE ’%$ t i t r e% ’
AND A c t e u r nom LIKE ’%$ n o m _ a c t e u r% ’
AND MES nom LIKE ’%$ n o m _ r e a l i s a t e u r% ’
AND annee BETWEEN ’ $annee_min ’ AND ’ $annee_max ’
AND g e n r e LIKE ’ $ g e n r e ’
AND i d _ a c t e u r = A c t e u r i d
AND i d _ r e a l i s a t e u r = MES i d
AND Role i d _ f i l m = F i l m i d
Cette requête est d’un niveau de complexité respectable, même si on peut aller plus loin Une manière de bien l’interpréter est de raisonner de la manière suivante
L’exécution d’une requête SQL consiste à examiner toutes les combinaisons possibles de lignes provenant de toutes les tables de la clause FROM On peut alors
considérer chaque nom de table dans le FROM comme une variable qui pointe sur une des lignes de la table Dans l’exemple ci-dessus, on a donc deux variables, Acteur et
MES qui pointent sur deux lignes de la table Artiste, et deux autres, Film et Role qui pointent respectivement sur des lignes des tables Film et Role.
Étant données les lignes référencées par ces variables, la clause SELECT renvoie
un résultat si tous les critères de la clause WHERE sont vrais simultanément Le résultat est lui-même construit en prenant un ensemble d’attributs parmi ces lignes