Bruno (Dsls) m’a filé un bout de code qu’il avait commencé à faire au sujet d’un constructeur simplifié et du coup je l’ai intégré, un peu modifié et complété et finalement il suffira amplement pour éviter d’avoir à gérer les trucs pénibles pendant la construction.
Je reprends l’exemple d’hier avec cette fonction qui récupère un compte de billets par catégorie. Voilà la fonction originale :
private function getCategoriesCounter($params = array())
{
$strReq =
'SELECT C.cat_id, COUNT(P.post_id) AS nb_post ' .
'FROM ' . $this->prefix . 'category AS C ' .
'JOIN ' . $this->prefix . "post P ON (C.cat_id = P.cat_id AND P.blog_id = '" . $this->con->escape($this->id) . "' ) " .
"WHERE C.blog_id = '" . $this->con->escape($this->id) . "' ";
if (!$this->core->auth->userID()) {
$strReq .= 'AND P.post_status = 1 ';
}
if (!empty($params['post_type'])) {
$strReq .= 'AND P.post_type ' . $this->con->in($params['post_type']);
}
$strReq .= 'GROUP BY C.cat_id ';
$rs = $this->con->select($strReq);
$counters = array();
while ($rs->fetch()) {
$counters[$rs->cat_id] = $rs->nb_post;
}
return $counters;
}
Et voilà le même code utilisant le constructeur simplfié :
private function getCategoriesCounter($params = array())
{
$sql = new dcSelectStatement();
$sql->columns(array('C.cat_id', 'COUNT(P.post_id) AS nb_post'))
->from($this->prefix . 'category AS C')
->join('JOIN ' . $this->prefix . 'post P ' .
"ON (C.cat_id = P.cat_id AND P.blog_id = '" . $this->con->escape($this->id) . "')")
->where("C.blog_id = '" . $this->con->escape($this->id) . "'");
if (!$this->core->auth->userID()) {
$sql->where('P.post_status = 1');
}
if (!empty($params['post_type'])) {
$sql->where('P.post_type ' . $this->con->in($params['post_type']));
}
$sql->group('C.cat_id');
$query = $sql->statement();
$rs = $this->con->select($query);
$counters = array();
while ($rs->fetch()) {
$counters[$rs->cat_id] = $rs->nb_post;
}
return $counters;
}
Y’a plus qu’à utiliser ça partout où c’est nécessaire et fermer ensuite ce fichu ticket ouvert depuis quatre ans !
1 De Gilsoub -
ah ben ouais ! bon dieu mais c’est bien sur ;-) rien pigé, mais merci de faire avancer le schmilblick :-)
2 De Nicolas -
Effectivement cela doit suffire mais tu avoueras que l’apport est relativement mince.
Entre écrire, par exemple :
$strReq .= 'GROUP BY C.cat_id ';
ou
$sql->group('C.cat_id');
le gain est léger.
Cela pourrait être intéressant si tu pouvais par exemple ajouter des méthodes à ta classe pour par exemple faire :
ou
Mais comme tu disais ces jours-ci, l’important est de se faire plaisir et j’ai l’impression que c’est le cas !
p.s: le parseur wiki s’emmèle les pinceaux avec les bouts de code !
3 De Franck -
Certes Nicolas mais là on dépasse clairement la portée du constructeur de requête SELECT.
Sinon oui, le parseur wiki (côté commentaires) n’est pas trop adapté pour inclure quelques lignes de code :-)
4 De Franck -
L’autre avantage de cette classe est que c’est elle qui se charge de construire la requête en concaténant ça dans le bon ordre alors que sinon, c’est à nous de le faire et c’est parfois assez peu lisible dans le code.
Sans oublier les espaces de séparation qu’on peut oublier au passage, etc…
Je vais continuer à implémenter ça un peu partout et je verrai si finalement ça vaut le coup de garder ou de revenir en arrière.
On pourrait aussi, comme tu le suggères, basculer sur une forme paramétrique des requêtes, à la façon de
PDOStatement::execute(…)
, mais du coup on ajoute une dépendance qu’on a pour l’instant pas puisque c’est Clearbricks qui gère ça de son côté.5 De Dsls -
Hello Franck,
Bonne chance pour la suite. Concernant le code en question, je rétrocède tous les droits à l’association, tu peux normaliser l’entête du fichier et enlever mon nom :)
Je me rappelle maintenant du pourquoi du comment de cette classe (qui initialement faisait partie d’un de mes plugins) : l’idée était de permettre aux plugins d’avoir un peu plus de liberté pour manipuler les requêtes via un appel Behavior juste avant d’exécuter la requête (genre : ajouter une jointure, une colonne dans le select, une clause where, …). Il doit falloir jouer un peu avec les ArrayObject pour pouvoir modifier la requête, mais l’idée était de rendre paramétrable à l’envi ce genre de choses :)
—
Bruno
6 De Franck -
Bonne idée les behaviours pour la classe de construction, même si déjà ça rend le code plus facile à lire là où on l’utilise. J’en ai profité pour proposer idem pour les autres opérations (insert/delete/update) même si elles largement moins utilisées que le select.
D’ailleurs je ne suis même par certain qu’il faille utiliser des ArrayObject vu que je peux tout à fait fournir l’instance elle-même en paramètre du behaviour et que l’appelé peut du coup utiliser toutes ses méthodes pour compléter les éléments de la requête à construire.
Je pense que ça devrait suffire, dans un premier temps, avec un behaviour juste avant la construction et le retour du “statement”.