Doctrine: quelques petits secrets
Oui, je commence à parler de Doctrine de plus en plus vu que je commence à l’utiliser à grande échelle au boulot. Et il y a un détail où j’ai encore du mal, c’est l’opacité de cet ORM comparé à son prédécesseur dans Symfony, Propel.
On se rappelle tous (enfin je parle au passé, mais Propel n’est pas mort hein :p) qu’on avait tout à disposition dans le BasePeer de notre modèle, les accesseurs, les modificateurs et quasi toutes les méthodes dont on pouvait avoir besoin. Avec Doctrine, la donne a changé, tant cet ORM est codé différemment.
On se retrouve du coup un peu perdu parfois, sans trop savoir ce qu’on peut utiliser. Et là, il faut bien sûr jeter un œil à l’API Doctrine. Mais on le sait tous, on a pas toujours le temps! Du coup, au travers de mes recherches, j’ai trouvé quelques petites méthodes que j’utilise régulièrement et dont je vais vous parler.
Le modèle d’exemple
Afin d’illustrer au mieux les différentes fonctions, je vais prendre en exemple un modèle basique, une liste de lien:
MyLink:
columns:
name: { type: string(100), notnull: true }
link: { type: string(255), notnull: true }
description: { type: string(4000) }Un save qui retourne un booléen
Parfois, lors de petites modifications, on a pas toujours le courage de faire un try/catch sur notre transaction. TrySave répond à cette problématique, en incluant directement le try catch sur le save et en retournant un booléen, true si l’enregistrement a bien été commité, false si une exception a été levée. Bien pratique!
- Documentation trySave
- Exemple:
public function saveMyLink() { $link = new MyLink(); $link->name = 'Amicalement-web'; $link->url = 'http://www.amicalement-web.net'; return $link->trySave(); // Retournera true si la sauvegarde a été effectuée, false sinon }
Le nom de la clé primaire
Oui des fois, quand on veut généraliser une méthode, on a besoin du nom de la clé primaire de notre model. (Dans le cas d’un unset en vue d’un embedForm par exemple).
- Documentation getIdentifier
- Exemple:
$link = new MyLink(); $link->getTable()->getIdentifier();
Exporter votre modèle en différents formats
Que se soit pour générer des XML destinés à une application tiers, ou du json pour votre module javascript, on a souvent besoin de nos modèles dans un format d’échange. Et bien Doctrine intègre cette fonctionnalité de base, en permettant des export en tableau php, xml, yml et json.
- Documentation exportTo
- Exemple
$link = new MyLink(); $link->name = 'Symfony Project'; $link->link = 'http://www.symfony-project.org'; $link->save(); echo $link->exportTo('xml'); // Attention par défaut exporte aussi les relations de l'objets. Il faut mettre à false, le 2e argument si on veut conserver seulement notre objet en question
-
Rendu:
<?xml version="1.0" encoding="utf-8"?> <data> <id>1</id> <name>Symfony Project</name> <url>http://www.symfony-project.org</url> <description></description> </data>
Importer votre modèle en différents formats
Et oui parce que Doctrine fait les choses biens, la réciproque existe aussi et est toute aussi utile. Vous pouvez ainsi hydrater un objet à partir d’un xml, json, ou yml grâce à la méthode importFrom
- Documentation importFrom
- Exemple:
$json = '{"id":"5","name":"Doctrine Project","url":"http:\/\/www.doctrine-project.org","description":"Orm PHP"}'; $link = new MyLink(); $link->importFrom('json',$json); echo $link->name; // Affiche "Doctrine Project"
Pour ce qui est d’hydrater à partir d’un tableau php, il y a 2 méthodes pour ça: fromArray et hydrate. Leurs différences, c’est la façon de faire. La première utilise les modificateurs de notre modèle (permettant ainsi de passer par des modifications qu’on aurait pu apporter à ces méthodes « set ») alors que la seconde remplie directement les attributs de notre modèle.
- Documentation fromArray
- Documentation hydrate
-
Exemple:
// On surcharge le modificateur de la propriété $url pour rajouter 'http://' devant class MyLink extends BaseMyLink { public function setUrl($url) { parent::_set('url','http://'.$url); } }
Puis maintenant nos 2 appels:
$data = array('name' => 'Amicalement Web', 'url' => 'www.amicalement-web.net'); $link1 = new MyLink(); $link1->fromArray($data); echo 'link1='.$link1->url; // Affiche http://www.amicalement-web.net $link2 = new MyLink(); $link2->hydrate($data); echo 'link2='.$link2->url; // Affiche www.amicalement-web.net
Post/Pre methodes
Comme je l’avais utilisé dans l’exemple du behavior Geographical, Doctrine met à disposition toute une série de méthodes en post et pré traitement de nombreuses fonctionnalités comme
- Sérialisation
- Désérialisation
- Sauvegarde
- Suppression
- Mise à jour
- Insertion
- Validation
- Hydratation
Leur documentation à la suite les unes des autre.
Libérer de la mémoire
La performance, sans être un axe principal a mon goût, doit rester dans la tête de chacun. Pour ça, Doctrine propose une méthode pour effacer un objet ainsi que toutes ses références de la mémoire de l’ORM. A utiliser principalement dans des boucles quand on veut juste faire un traitement sur un ensemble d’objets dont on ne voudra pas se resservir ensuite.
- Documentation free
- Exemple:
// Exemple tiré de la documentation doctrine for ($i = 0; $i < 1000; $i++) { $object = createBigObject(); $object->save(); $object->free(true); // true pour libérer même les relations }
Hydrater plus efficacement
Et oui, on le crie pas sur tous les toits, mais on est pas obligé de récupérer des objets complets quand on fait une requête avec doctrine même si c’est le comportement par défaut.
Quand on veut simplement faire de l’affichage, parfois seules les données nous intéresse et donc dans un gain de mémoire, on peut changer le mode d’hydratation:
- Doctrine::HYDRATE_RECORD
- Doctrine::HYDRATE_ARRAY
- Doctrine::HYDRATE_NONE
- Exemple:
$q = Doctrine_Query::create()->from('MyLink'); // Comportement par défaut, retourne un tableau d'objet $results = $q->execute(array(),Doctrine::HYDRATE_RECORD); // Retourne un tableau associatif où les clés sont les noms des champs $results = $q->execute(array(),Doctrine::HYDRATE_ARRAY); // Retourne un simple tableau où les champs sont dans l'ordre qu'ils ont été appelés $results = $q->execute(array(),Doctrine::HYDRATE_NONE);
Cela reste le fruit de mes tests et études, si vous avez des remarques ou des corrections n’hésitez pas!
Et vous, vous avez quelque chose à partager sur les méandres de Doctrine?
Tags: astuce, doctrine, orm, Symfony
16 Réponses
Laisser un message

Plus qu’intéressant et utile ! A bookmarker aux côtés de la doc officielle de Doctrine :)
Merci.
<Ctrl> + D dans delicious. ;)
Merci beaucoup pour l’article !
J’aime vraiment beaucoup tes billets !
Merci
Très intéressant.
Merci !
Indeed, very interesting!
Gracias!
Excellent trucs et astuces ! Merci
Bonjour,
as eu l’occasion de tester la fonction exportTo() sur des collections ?
Car j’ai du faire des imports CSV sur des grosses listes (+100000 objets) et je me retrouvais avec un problème de mémoire dû au garbage collector de PHP. La méthode free est censé pouvoir régler ce problème mais pour les grosses collections cela reste problèmatique.
ps: très bon post.
J’ai eu l’occasion de le tester lors d’un export XML mais avec beaucoup moins d’objet (~2000) et c’est passé après avoir rajouté le free. (memory size limit avant, mémoire à 64M)
Mais de toute manière, un si gros export posera des problèmes à PHP quelque se soit le framework je pense.
Très bon billet, bravo !
A question, do you have your tree nested set implemented for doctrine?
Thanks for your tutorial!
Hi Jaime.
There is already a tutorial on tree nested set for doctrine on:
http://redotheoffice.com/?p=74
Salut !
Quelle version de Doctrine as-tu utilisé pour réaliser ce billet ?
Merci d’avance pour ta réponse.
@+
Hello,
Sauf erreur de ma part, c’est la 1.0!
Je suis switcheur depuis Propel, bien content de trouver ton article !
C’est cool que des gens comme toi prennent le temps d’aider les autres…
Merci,