Cette page décrit la migration du système d'ajout d'actions sur les listes de billets et/ou de commentaires via des plugins, depuis dotclear 2.5.X vers dotclear 2.6.
A noter : dotclear 2.6 supporte toujours l'ancienne méthode, il est toutefois recommandé de passer à la nouvelle approche.
Note :
La présente page décrit la méthode pour la gestion des actions sur les billets, mais elle est aussi applicable pour les commentaires. Nous nous appuierons sur un plugin d'example, dont l'objectif est de permettre d'autoriser ou pas les commentaires et les rétroliens sur une liste de billets.Sous dotclear 2.5.x, il faut passer par 3 behaviors distincts :
Le plugin, que nous appellerons OpenCloseComTB, se compose :
La structure du fichier _admin.php est la suivante :
<?php $core->addBehavior('adminPostsActionsCombo',array('AdminOpenCloseComTB','adminPostsActionsCombo')); $core->addBehavior('adminPostsActionsContent',array('AdminOpenCloseComTB','adminPostsActionsContent')); $core->addBehavior('adminPostsActions',array('AdminOpenCloseComTB','adminPostsActions')); class AdminOpenCloseComTB { public static function adminPostsActionsCombo($args) { [...] } public static function adminPostsActions($core,$posts,$action,$redir) { [...] } public static function adminPostsActionsContent($core,$action,$hidden_fields) { [...] } } ?>
adminPostsActionsCombo prend en paramètre la liste des combos, que nous allons enrichir, dans la section "modifier" :
public static function adminPostsActionsCombo($args) { $args[0][__('Change')] = array(__('Open/Close Comments or trackbacks') => 'openclosecomtb'); }
La soumission de l'action "Open/Close Comments or trackback" enverra donc l'action 'openclosecomtb'.
adminPostsActionsContent prend 3 arguments :
Ce qui donne :
public static function adminPostsActionsContent($core,$action,$hidden_fields) { // On s'assure que l'action en cours nous concerne bien if ($action == 'openclosecomtb') { echo '<h2>'.__('Open/close comments or trackbacos').'</h2>'. '<form action="posts_actions.php" method="post">'. '<p>'. form::checkbox('open_comm','1',''). ' <label class="classic" for="open_comm">'.__('Allow Comments').'</label></p>'. '<p>'. form::checkbox('open_tb','1',''). ' <label class="classic" for="open_comm">'.__('Allow Trackbacks').'</label></p>'. // On n'oublie pas les champs cachés, le nonce et l'action $hidden_fields. $core->formNonce(). form::hidden(array('action'),'openclosecomtb'). // le champ changestatus nous permet de tester si le formulaire a bien été soumis form::hidden(array('changestatus'),'true'). '<p><input type="submit" value="'.__('Ok').'" /></p>'. '</form>'; } }
adminPostsActions prend 4 arguments :
On s'assure ici que le formulaire a bien été soumis en testant la présence du champ "changestatus" défini plus haut. Pour d'autre cas, il est possible de tester d'autre champs, mais ici nous n'avons que des checkbox, et une checkbox non cochée n'est pas définie dans $_POST.
Ce qui donne :
public static function adminPostsActions($core,$posts,$action,$redir) { if ($action == 'openclosecomtb' && !empty($_POST['changestatus']) && $core->auth->check('contentadmin',$core->blog->id)) { try { $set_co = isset($_POST['open_comm']); $set_tb = isset($_POST['open_tb']); while ($posts->fetch()) { $cur = $core->con->openCursor($core->prefix.'post'); $cur->post_open_tb = $set_tb?1:0; $cur->post_open_comment = $set_co?1:0; $cur->update('WHERE post_id = '.(integer) $posts->post_id); } http::redirect($redir); } catch (Exception $e) { $core->error->add($e->getMessage()); } } }
Sous dotclear 2.6, un seul et unique behavior est nécessaire pour tout gérer : adminPostsActionsPage. Ce dernier véhicule un objet de contexte qui sera manipulé par les actions définies, une instance de dcPostsActionsPage.
Cet objet définit le contexte de la page en cours. il expose les méthodes suivantes (seules les méthodes utiles aux plugins qui ajoutent des actions sont décrites ici):
public function addAction ($actions,$callback) {}
Ajoute une ou plusieurs actions, associées à un callback (voir plus loin). Le callback sera appelé si et seulement si une des actions définies en entrée a été sélectionnée. Pour la syntaxe de l'action, c'est la même que pour l'action de adminPostsActionsCombo.
Paramètres :
Exemples :
# action simple sans catégorie: $ap->addAction( array(__('Myaction') => 'myaction'), array('myclass','mycallback') ); # plusieurs actions, dans le groupe "Toggle" $ap->addAction( array(__('Toggle') => array( __('enable') => 'myactionenable', __('disable') => 'myactiondisable')), array('myclass','mycallback') );
public function getIDs() {}
Retourne la liste des identifiants des entrées sélectionnées (déjà filtrés au niveau sécurité)
public function getHiddenFields($with_ids = false) {}
Retourne les champs cachés à ajouter au formulaire, s'il faut en afficher un dans le plugin. Equivalent à $hidden_fields de l'ancien behavior adminPostsActionsContent. Si $with_ids est à true, les ids des billets cochés sont aussi inclus comme champs cachés.
public function getRS() {}
Retourne le record correspondant à la requête SQL de sélection des billets cochés. Equivalent à $posts de l'ancien behavior adminPostsActionsContent.
public function redirect($with_selected_entries=false,$params=array()) {}
Redirige vers la page appelante. Il est possible : * D'ajouter de nouveaux paramètres GET (ex : array('upd'⇒1) pour avoir la notification de mise à jour) * d'ajouter les billets sélectionnés au GET, cela permet de garder les billets cochés sur la page de retour. Attention, en cas de suppression de billets, ils ne pourront plus être cochés par la suite :)
public function getURI() {}
Retourne l'uri du formulaire à utiliser, s'il faut afficher un formulaire intermédiaire.
public function getAction() {}
Retourne l'action qui a été sélectionnée (utile si plusieurs actions mènent au callback)
public function getCheckboxes() {}
Retourne un tableau contenant les billets de la sélection, qui sont à nouveau sélectionnables pour une seconde vérification
Astuce :
Si vous créez un formulaire intermédiaire, vous serez amené à utiliser getHiddenFields aussi. 2 possiblités :public function beginPage($breadcrumb='',$head='');
Affiche le début d'une page. A appeler en tout premier si vous voulez afficher un formulaire intermédiaire. $breadcrumb indique le titre de la page, $head permet d'ajouter des js ou des css à la page affichée
public function endPage();
Le pendant de beginPage, à appeler en tout dernier si vous voulez afficher un formulaire intermédiaire
Un callback doit avoir la forme suivante :
public static function doCallback($core, dcPostsActionsPage $ap, $post) {}
Attention :
Attention ! $post n'a rien à voir avec le paramètre $posts de l'ancien behavior adminPostsActionsLe traitement a une philosophie différente de l'ancien traitement :
Revenons à nos moutons. Notre _admin.php va ressembler à cela :
<?php $core->addBehavior('adminPostsActionsPage',array('AdminOpenCloseComTB','adminPostsActionsPage')); class AdminOpenCloseComTB { public static function adminPostsActionsPage($core,$ap) { // Ajout de l'action à $ap [...] } public static function doOpenCloseComTB($core, dcPostsActionsPage $ap, $post) { // traitement de l'action [...] } }
Ajoutons maintenant notre action :
public static function adminPostsActionsPage($core,$ap) { $ap->addAction( array(__('Change') => array(__('Open/Close Comments or trackbacks') => 'openclosecomtb')), array('AdminOpenCloseComTB','doOpenCloseComTB') ); }
… et le callback qui va bien
public static function doOpenCloseComTB($core, dcPostsActionsPage $ap, $post) { if (!empty($post['changestatus'])) { # changestatus non vide, le formulaire intermédiaire a été soumis # Les IDs des billets sont servis sur un plat $ids = $ap->getIDs(); # Pas de billets, pas bien! if (empty($ids)) { throw new Exception(__('No entry selected')); } # attention à utiliser $post et non $_POST $set_co = isset($post['open_comm']); $set_tb = isset($post['open_tb']); foreach ($ids as $id) { $cur = $core->con->openCursor($core->prefix.'post'); $cur->post_open_tb = $set_tb?1:0; $cur->post_open_comment = $set_co?1:0; $cur->update('WHERE post_id = '.(integer) $id); echo $id; } # Traitement fini, on redirige vers l'appelant avec une belle notification $ap->redirect(true,array('upd' => 1)); # Au diable les exceptions, c'est géré en amont :) } else { # Pas de 'changestatus', on affiche le formulaire intermédiaire # Ne pas oublier de commencer la page $ap->beginPage(); echo '<h2>'.__('Open/close comments or trackbacks').'</h2>'. '<form action="'.$ap->getURI().'" method="post">'. # Une jolie sélection des billets pour être sûr $ap->getCheckboxes(). '<p>'. form::checkbox('open_comm','1',''). ' <label class="classic" for="open_comm">'.__('Allow Comments').'</label></p>'. '<p>'. form::checkbox('open_tb','1',''). ' <label class="classic" for="open_comm">'.__('Allow Trackbacks').'</label></p>'. // On n'oublie pas les champs cachés, le nonce et l'action $ap->getHiddenFields(). $core->formNonce(). form::hidden(array('action'),'openclosecomtb'). // le champ changestatus nous permet de tester si le formulaire a bien été soumis form::hidden(array('changestatus'),'true'). '<p><input type="submit" value="'.__('Ok').'" /></p>'. '</form>'; # Et on ferme... $ap->endPage(); } } # Et c'est tout :)