Administrateur PHPfrance |
3131 Messages
11 sept. 2007, 16:55
Pour le YAML, c'est une question de goût. Personnellement j'y trouve un avantage très concret : c'est *vraiment* «human-readable» (pas comme ce XML soit-disant lisible, pour peu que le cerveau du lecteur sache faire abstraction de tout le bruit verbeux de ce langage). Je peux même l'envoyer pour validation, le lecteur saura le déchiffrer sans avoir jamais lu la spécification du langage.
Le fait de devoir travailler avec des espaces (l'indentation n'est pas forcément de 2, c'est simplement la convention Symfony qui veut ça, on peut indenter à 4 espaces sans souci aucun) ne m'a pas gêné, j'ai déjà cette habitude (le choix de l'indentation est un débat sans fin car on ne peut plus subjectif, n'ayons pas ce débat ici SVP). Cependant si on bosse avec un vrai éditeur, il y a des chances qu'il propose une config selon le type de fichier, il suffit donc de lui dire de faire une exception pour les .yml.
Concernant la doc, franchement, soyons honnête, l'Anglais est
obligatoire dans notre métier, à l'écrit il s'agit d'être bilingue sur l'anglais technique (l'oral compte généralement moins, mais ça aide).
Perso je ne fais aucune différence entre une doc en Français ou en Anglais. J'aurais compris que ce soit bloquant si elle était disponible uniquement en Allemand ou en Mandarin

mais là franchement…
Quant au SQL, Propel n'est pas forcément le plus ergonomique des sytèmes d'abstraction (note qu'on peut utiliser Doctrine, ou même ezPdo si ça te chante). Personnellement j'ai eu beaucoup de mal avec… Mais une fois qu'on fait l'effort de se cramponner au système on trouve vite les solutions. Pour faire une requête «custom», c'est vraiment typique. Prenons un exemple concret : j'ai ma table "profil" qui a une relation 1-1 avec ma table "user" et un million de colonnes (au moins), et je ne voudrais que récupérer les informations d'identité (civilite, nom, prenom) pour des user_id donnés.
1. Identifier à quelle classe du modèle cette requête appartient : User ou Profil ? Profil bien sûr. Dans d'autres cas c'est moins trivial, donc il faut toujours se poser la question.
2. Identifier à quelle partie du modèle cette requête appartient : il ne s'agit pas d'un travail sur un seul objet, mais d'une sélection concernant un groupe d'objets. On utilisera donc ProfilPeer (et pas Profil).
3. Nommer la méthode

on va l'appeler "getIdentities()" et elle recevra en paramètre un id ou une liste d'ids.
4. Coder

ce n'est peut-être pas la partie la plus triviale, et c'est pénible à expliquer car comme je l'ai dit Propel/Creole ne sont pas ce qu'il y a de plus facile à prendre en main, c'est
très verbeux dès qu'on sort des sentiers battus, mais ça marche toutefois très bien :
lib/model/ProfilPeer.php
<?php
/**
* Subclass for performing query and update operations on the 'profil' table.
*
*
*
* @package lib.model
*/
class ProfilPeer extends BaseProfilPeer
{
function getIdentities($id) {
if (!is_array($id)) {
$id = array($id);
}
// Préparer la requête
$c = new Criteria;
// Les champs que l'on souhaite sélectionner
$c->addSelectColumn(self::CIVILITE);
$c->addSelectColumn(self::NOM);
$c->addSelectColumn(self::PRENOM);
// Le critère de sélection (user_id IN (...))
$c->add(self::USER_ID, $id, Criteria::IN);
// Exécuter la requête : on récupère un ResultSet
$res = self::doSelectRS($c);
// On parcourt le ResultSet pour en extraire les identités
$identities = array();
while ($res->next()) {
// Note : on passe par une classe supplémentaire du modèle, mais rien n'empêche de se passer de cette étape
$identity = new UserIdentity;
$identity->hydrate($res);
$identities[] = $identity;
}
return $identities;
}
}
lib/model/UserIdentity.php
<?php
class UserIdentity
{
// Tout le bordel habituel des get/set
protected $civilite;
protected $prenom;
protected $nom;
function getCivilite() { return $this->civilite; }
function getPrenom() { return $this->prenom; }
function getNom() { return $this->nom; }
function setCivilite($civilite) { return $this->civilite = $civilite; }
function setPrenom($prenom) { return $this->prenom = $prenom; }
function setNom($nom) { return $this->nom = $nom; }
// La vraie fonction intéressante, tirée du code généré par Propel, la méthode hydrate()
// qui a pour rôle de "remplir" l'objet à partir d'un ResultSet
// Ordre des colonnes : civilite, nom, prenom (il y a moyen de travailler avec les noms plutôt
// qu'avec l'ordre, mais comme BasePeer::doSelectRS() marche avec l'ordre des colonnes,
// c'est plus simple comme ça).
public function hydrate(ResultSet $rs)
{
try {
$this->civilite = $rs->getString(1);
$this->nom = $rs->getString(2);
$this->prenom = $rs->getString(3);
} catch (Exception $e) {
throw new PropelException("Error populating UserIdentity object", $e);
}
}
}
Voilà, c'est un mauvais exemple, et je comprendrais que celui qui débarque et voit ça se dise «Oh My God ! What The Fuck ! C'est quoi ce machin où il faut pondre 300 lignes et une nouvelle classe pour une pauvre requête ?».
Je lui répondrais ceci dans l'espoir de le rassurer :
- Concrètement, il y a 15 lignes utiles
- Cela répond à un besoin très spécifique du gars qui veut absolument ne pas sélectionner tous les champs de sa table (c'est tout de même assez rare, et si c'est si vital, la plupart du temps ça doit plutôt donner lieu à un refactoring du modèle). Dans le cas général, on n'aurait pas écrit tout ça, et pour récupérer les noms/prénoms des users d'id 1&2&3, on se serait contenté d'appeler "ProfilPeer::retrieveByPKs(array(1,2,3))". Et puis on aurait fait ce type de modification après coup si on avait détecté un goulot d'étranglement du au nombre de champs rapatriés inutilement à cet endroit (il y a donc des chances que ce type d'optimisation n'ait jamais lieu).
- Si on veut coller au tout objet, si on manipule une nouvelle structure de données elle doit avoir sa propre classe. On aurait bien sûr pu se passer de la classe UserIdentity et travailler avec des tableaux associatifs ou des stdClass.
- Si on veut coller à Symfony, les objets du modèle sont tous équipés de getters/setters, forcément ça rallonge (mais ça permet de jolies choses
).