XV. Chapitre 15 : Les bases de données 3/3▲
Maintenant que nous savons mettre en place la structure d'une base de données et intervenir sur les enregistrements que nous reste-t-il à voir ? Et bien Laravel nous propose un ORM vraiment efficace nommé Eloquent. Qu'est-ce qu' un ORM ? C'est un « Object Relational Mapper ». Mapper parce qu'on va « mapper » des objets PHP sur les tables et les colonnes d'une base. Relational parce qu'on va aussi pouvoir gérer les relations de notre base. Mais tout cela va devenir plus clair avec des exemples. Vous n'avez pas besoin d'un ORM pour gérer une base, mais vous le ferez avec beaucoup plus de facilité avec lui.
Je pars du principe que vous avez une base nommée laravel telle que décrite lors du chapitre précédent avec deux tables : auteurs et livres. Vous avez aussi correctement configuré le fichier app/config/database.php pour accéder à la base.
XV-A. Créer un modèle avec Eloquent▲
Voyons comment créer un modèle avec Eloquent. Par exemple pour notre table auteurs. Créez un fichier avec ce code et enregistrez-le dans app/models/Auteur.php :
<?php
class
Auteur extends
Eloquent {}
Et voilà vous avez créé un modèle et vous pouvez maintenant l'utiliser . Bon il a quand même fallu prendre quelques précautions : j'ai nommé la classe Auteur, autrement dit le nom de la table avec le « s » en moins. En effet la table peut contenir plusieurs auteurs mais la classe s'adresse à un auteur à chaque fois. D'autre part il est impératif que la table contienne une clé nommée « primaire id », ce qui est notre cas.
XV-A-1. Extraire des données▲
Il ne nous reste plus qu'à utiliser notre nouvelle classe. Dans une route entrez ce code :
On demande l'enregistrement avec l'index 1. Voyons ce que nous avons en retour :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
object(Auteur)[
118
]
protected '
connection
'
=>
null
protected '
table
'
=>
null
protected '
primaryKey
'
=>
string '
id
'
(length=
2
)
protected '
perPage
'
=>
int 15
public '
incrementing
'
=>
boolean true
public '
timestamps
'
=>
boolean true
protected '
attributes
'
=>
array (size=
4
)
'
id
'
=>
int 1
'
nom
'
=>
string '
Flaubert
'
(length=
8
)
'
prenom
'
=>
string '
Gustave
'
(length=
7
)
'
naissance
'
=>
string '
1821-12-12
'
(length=
10
)
protected '
original
'
=>
array (size=
4
)
'
id
'
=>
int 1
'
nom
'
=>
string '
Flaubert
'
(length=
8
)
'
prenom
'
=>
string '
Gustave
'
(length=
7
)
'
naissance
'
=>
string '
1821-12-12
'
(length=
10
)
protected '
relations
'
=>
array (size=
0
)
empty
protected '
hidden
'
=>
array (size=
0
)
empty
protected '
fillable
'
=>
array (size=
0
)
empty
protected '
guarded
'
=>
array (size=
0
)
empty
protected '
dates
'
=>
array (size=
0
)
empty
public '
exists
'
=>
boolean true
Maintenant nous comprenons mieux la notion de mappage : Nous obtenons un objet que nous pouvons exploiter pour extraire des informations. Ce qui est bien pratique aussi, c'est que tout ce que nous avons vu au chapitre précédent concernant la gestion des enregistrements reste valable. Ainsi nous pouvons écrire :
Ce qui donne :
string '
Saulers
'
(length=
7
)
Eloquent nous renvoie une collection qui implémente l'interface IteratorAggregate. Nous pouvons donc agir comme si nous avions un tableau en retour. En effet notre requête est susceptible de renvoyer plusieurs lignes, contrairement au cas précédent où on appelait juste une ligne en précisant son index. Il devient alors facile de traiter les lignes lorsqu'elles nous arrivent sous cette forme :
$auteurs
=
Auteur::
where('
nom
'
,
'
>
'
,
'
q
'
)->
get();
foreach ($auteurs
as $auteur
) var_dump($auteur
->
nom);
Ce qui donne :
string '
Raspail
'
(length=
7
)
string '
Sibran
'
(length=
6
)
string '
Saulers
'
(length=
7
)
XV-A-2. Insérer des données▲
Nous allons voir qu'il est aussi très facile d'insérer de nouvelles données. Mais auparavant je dois vous donner encore une petite indication. Par défaut Eloquent gère deux colonnes dans chaque table de type DateTime nommées respectivement updated_at et created_at. Ces colonnes sont automatiquement mises à jour à chaque création ou modification. Mais vous n'êtes pas obligé de les avoir. Si ces informations ne vous intéressent pas il suffit de compléter le modèle ainsi :
2.
3.
4.
5.
<?php
class
Auteur extends
Eloquent
{
public
$timestamps
=
false
;
}
C'est ce que nous allons faire dans notre cas parce que nous n'avons pas prévu ces colonnes dans nos tables. Sachez juste que cette possibilité existe et nous l'utiliserons dans un article ultérieur sur la création d'un blog. Maintenant voilà le code pour faire une insertion :
On vérifie dans la base :
Apparemment tout se passe bien. Vous pouvez aussi passer un tableau au constructeur :
XV-A-3. Modifier et supprimer des données▲
Pour modifier une donnée existante la syntaxe est tout aussi simple, voici un exemple :
Pour supprimer des données c'est tout aussi simple :
XV-A-4. Les relations▲
Par définition dans une base de données relationnelle nous avons des… relations. Celles-ci peuvent être explicites dans la base ou implicites (comme c'est le cas dans notre exemple où on a juste introduit une ligne dans la table des livres pour préciser l'id de l'auteur mais sans demander à MySQL de vérifier l'intégrité de cette relation. On aurait pu le faire en précisant que nous utilisons le moteur InnoDB et en déclarant cette ligne comme clé étrangère).
Eloquent a une façon très élégante de gérer les relations. Nous allons prendre comme exemple celle qui existe entre nos deux tables. Mais auparavant il nous faut créer aussi un modèle pour la table des livres (app/models/Livre.php) :
2.
3.
4.
class Livre extends
Eloquent
{
public
$timestamps
=
false
;
}
Il existe trois sortes de relations : « un vers un », « un vers plusieurs » et « plusieurs vers plusieurs ». Notre cas est le plus classique avec une relation « un vers plusieurs », en effet un auteur peut écrire plusieurs livres et on admet qu'un livre n'est écrit que par un auteur (bon on oublie les coauteurs ).
Pour qu'Eloquent reconnaisse automatiquement la clé étrangère dans une table il faut qu'elle réponde à une certaine syntaxe : le nom de la table suivi d'un soulignement puis de « id ». Manque de chance j'ai fait juste l'inverse dans la table des livres. On va corriger ça :
Cette norme n'est pas une contrainte absolue parce que d'une part on peut préciser le nom de la clé étrangère comme paramètre des méthodes relationnelles, d'autre part elle n'est pas toujours respectée par Eloquent (par exemple pour belongsTo c'est le nom de la méthode qui sert de référence). Pour avoir une vue d'ensemble du sujet, référezvous au chapitre 33Chapitre 33 : Les relations avec Eloquent 1/2.
Maintenant nous pouvons utiliser toute la puissance et l'élégance d'Eloquent. Nous modifions la classe Auteur pour déclarer la relation :
2.
3.
4.
5.
6.
7.
8.
class Auteur extends
Eloquent
{
public
$timestamps
=
false
;
public
function
livres()
{
return
$this
->
hasMany('Livre'
);
}
}
Et maintenant ça devient facile :
Résultat :
string '
Secouons le cocotier
'
(length=
20
)
string '
Les Royaumes de Borée
'
(length=
22
)
On peut mettre en œuvre toutes les possibilités de manipulation de données. Par exemple si on ne veut que le premier livre :
Résultat :
string '
Secouons le cocotier
'
(length=
20
)
XV-A-5. Inverse d'une relation▲
Considérons à nouveau notre relation en la regardant dans l'autre sens. Nous avons dit qu'un auteur peut écrire plusieurs livres. Nous avons traduit cela dans la classe Auteur par ce code :
On pourrait aussi dire qu'un livre appartient à un auteur. Cette fois au lieu de renseigner la relation dans la classe Auteur on le fait dans la classe Livre :
2.
3.
4.
5.
6.
7.
8.
9.
<?php
class
Livre extends
Eloquent
{
public
$timestamps
=
false
;
public
function
auteur()
{
return
$this
->
belongsTo('Auteur'
);
}
}
Testons cela :
Résultat :
string '
Raspail
'
(length=
7
)
XV-A-6. Chargement dynamique▲
Avec la relation précédente, considérez ce code :
foreach(Livre::
all() as $livre
)
echo '
"
'
.
$livre
->
titre.
'
" a été écrit par
'
.
$livre
->
auteur->
nom.
'
<br>
'
;
Et son résultat :
2.
3.
4.
"Secouons le cocotier" a été écrit par Raspail
"Pêcheurs de Lune" a été écrit par Avril
"Les Royaumes de Borée" a été écrit par Raspail
"Le Salon des artistes" a été écrit par July
Le résultat correspond à notre attente mais… nous ne sommes pas très efficaces parce que nous multiplions les requêtes. Il y en a une pour récupérer tous les livres, et ensuite une pour chaque livre afin de trouver l'auteur. Imaginez que nous ayons des milliers de livres ! Heureusement il existe une solution :
foreach(Livre::
with('
auteur
'
)->
get() as $livre
)
echo '
"
'
.
$livre
->
titre.
'
" a été écrit par
'
.
$livre
->
auteur->
nom.
'
<br>
'
;
Cette fois on a une seule requête dans la boucle, qui prend la forme :
SELECT
*
FROM
auteurs WHERE
id IN
(
2
,3
,7
)
;
Il y aurait encore beaucoup à dire sur Eloquent. Je vous renvoie encore une fois à la documentation. Vous pouvez également consulter le chapitre 33Chapitre 33 : Les relations avec Eloquent 1/2 qui est consacré à ce sujet.