Sauvegarde/Restauration de filtres Symfony
Les exemples à venir sont basés sur un modèle simple que pris sur les précédents articles que NiKo a publié précédemment, concernant l'embriquement de relations dans des formulaires Doctrine, auxquelles il va ajouter des facilitations pour ses marque-pages :
# in ./config/doctrine/schema.yml User: columns: id: type: integer(4) primary: true autoincrement: true name: type: string(255) notnull: true relations: Bookmarks: type: many class: Bookmark local: id foreign: user_id onDelete: CASCADE Bookmark: actAs: I18n: fields: [name] actAs: Sluggable: fields: [name] uniqueBy: [name, lang] columns: id: type: integer(4) primary: true autoincrement: true name: type: string(255) notnull: true url: type: string(255) notnull: true user_id: type: integer(4) notnull: true relations: User: type: one local: user_id foreign: id Tags: class: Tag refClass: BookmarkTag local: bookmark_id foreign: tag_id foreignAlias: Bookmarks Tag: columns: id: type: integer(4) primary: true autoincrement: true name: type: string(255) notnull: true BookmarkTag: columns: bookmark_id: type: integer(4) primary: true notnull: true tag_id: type: integer(4) primary: true notnull: true
Pas besoin de dire que vous devriez reconstruire votre modèle...
Le fichier de fixtures mis à jour :
# in ./data/fixtures/fixtures.yml User: niko: name: niko Bookmark: niko_bookmark1: User: niko name: Slashdot url: http://slashdot.org/ Tags: [geek_tag, tech_tag, php_tag] niko_bookmark2: User: niko name: Delicious url: http://delicious.com/ Tags: [geek_tag, tech_tag] niko_bookmark3: User: niko name: Digg url: http://digg.com/ Tags: [geek_tag, php_tag] Tag: geek_tag: name: geek php_tag: name: php tech_tag: name: tech
Sommaire
Génération de l'admin du modèle Bookmark
Générons une application "backend" et un module "Bookmark" :
$ ./symfony generate:app backend $ ./symfony doctrine:generate-admin backend Bookmark
Maintenant améliorons un peu ce module d'admin en modifiant le fichier generator.yml :
generator: class: sfDoctrineGenerator param: model_class: Bookmark theme: admin non_verbose_templates: true with_show: false singular: Bookmark plural: Bookmarks route_prefix: bookmark with_doctrine_route: true actions_base_class: sfActions config: actions: ~ fields: ~ list: display: [=name, url, User] filter: ~ form: ~ edit: ~ new: ~
Vous devriez à présent pouvoir naviguer dans l'interface d'admin ainsi générée :
Enregistrer les filtres dans une table Doctrine dédiée, et les gérer depuis le contrôleur
Nous allons utiliser Doctrine pour stocker les filtrer à enregistrer, ajoutons donc la définition d'une nouvelle table dans notre schema.yml :
SavedFilter: columns: id: type: integer(4) primary: true autoincrement: true name: type: string(255) type: type: enum values: [Bookmark, User] notnull: true filter: type: string()
Bien entendu, pas besoin de rappeler qu'il faut reconstruire votre modèle...
Ok, maintenant nous allons enregistrer les valeurs sérialisées du filtre dans la colonne "filter" de la table et la colonne "name" sera pratique pour donner un nom aux filtres. La colonne "type" va référencer la table Doctrine dont fait référence le filtre. Rien de difficile ici.
Dans le module d'admin, les filtres sont stockés dans l'attribut tableName.filters de la session utilisateur (où tableName est le nom du module d'admin d'où les paramètres du filtre sont donnés).
Donc ajoutons maintenant une méthode executeSaveFilter() dans le controlleur bookmarkActions. Et tant que nous seront là-dessus, ajoutons également les méthodes executeLoadFilter() et executeDeleteFilter()...
<?php # in apps/backend/modules/bookmark/actions/actions.class.php class bookmarkActions extends autoBookmarkActions { public function executeDeleteFilter(sfWebRequest $request) { $this->forward404Unless($filter = Doctrine::getTable('SavedFilter')->findOneByTypeAndId('Bookmark', $request->getParameter('id')), sprintf('Bookmark filter #%d not found', $request->getParameter('id'))) ; $filter->delete(); $this->getUser()->setFlash('notice', sprintf('Bookmark saved filters "%s" deleted', $filter->getName())); $this->redirect('bookmark'); } public function executeLoadFilter(sfWebRequest $request) { $this->forward404Unless($filter = Doctrine::getTable('SavedFilter')->findOneByTypeAndId('Bookmark', $request->getParameter('id'))); $this->setFilters(unserialize($filter->getFilter())); $this->getUser()->setFlash('notice', sprintf('Bookmark saved filters "%s" loaded', $filter->getName())); $this->redirect('bookmark'); } public function executeSaveFilter(sfWebRequest $request) { $name = trim($request->getGetParameter('name')); $savedFilter = new SavedFilter(); $savedFilter->fromArray(array( 'name' => $name ? $name : 'Untitled filter', 'type' => 'Bookmark', 'filter' => serialize($this->getUser()->getAttribute('bookmark.filters', array(), 'admin_module')), )); $savedFilter->save(); $this->getUser()->setFlash('notice', 'Bookmark filters saved'); $this->redirect('bookmark'); } }
Bien entendu, nous allons avoir besoin d'ajouter les routes correspondantes dans le fichier routing.yml de l'application (app/YOURAPP/config/routing.yml) :
# in apps/backend/config/routing.yml bookmark_filter_delete: url: /bookmark/filter/:id/delete param: { module: bookmark, action: deleteFilter } requirements: id: \d+ bookmark_filter_load: url: /bookmark/filter/:id/load param: { module: bookmark, action: loadFilter } requirements: id: \d+ bookmark_filter_save: url: /bookmark/filter/save param: { module: bookmark, action: saveFilter }
Attendez, nous n'avons aucun lien pour enregistrer un filtre depuis l'interface d'admin ! Ajoutons-en un près du bouton Reset de la partie Filtres, en réécrivant le partial _filters.php (dont l'original se trouve dans cache/YOURAPP/YOURENV/modules/autoBookmark/templates/_filters.php) :
// in apps/backend/modules/bookmark/templates/_filters.php from line 11 [...] <tfoot> <tr> <td colspan="2"> <?php echo $form->renderHiddenFields() ?> <a href="<?php echo url_for('@bookmark_filter_save') ?>" onclick="document.location = this.href+'?name='+prompt('Enter a name:');return false"> <?php echo __('Save') ?> </a> <?php echo link_to(__('Reset', array(), 'sf_admin'), 'bookmark_collection', array('action' => 'filter'), array('query_string' => '_reset', 'method' => 'post')) ?> <input type="submit" value="<?php echo __('Filter', array(), 'sf_admin') ?>" /> </td> </tr> </tfoot> [...]
Notez qu'un prompt javascript va vous demander un nom pour votre filtre avant de le sauvegarder...
Ainsi nous pouvons enregistrer un filtre en base de donnée. Maintenant, listons-les après le formulaire de filtres !
Lister les filtres existants
Pour moi, le meilleur endroit pour retrouver des filtres enregistrés c'est la classe bookmarkGeneratorConfiguration, qui a été générée dans le sous-répertoire lib/ du module Bookmark d'admin. Ajoutons-y une nouvelle méthode getSavedFilters() :
<?php # in apps/backend/modules/bookmark/lib/bookmarkGeneratorConfiguration.class.php class bookmarkGeneratorConfiguration extends BaseBookmarkGeneratorConfiguration { public function getSavedFilters() { return Doctrine::getTable('SavedFilter') ->createQuery() ->where('type = ?', 'Bookmark') ->execute() ; } }
Ainsi, dans le partial _filters.php, qui a déjà accès à une instance de la classe bookmarkGeneratorConfiguration, nous sommes maintenant capables d'afficher en boucle les filtres sauvegardés que nous avons récupéré afin d'en afficher la liste :
// in apps/backend/modules/bookmark/templates/_filters.php from line 11 [...] <tr> <td colspan="2"> <h3><?php echo __('Saved filters') ?><h3> <?php if (count($savedFilters = $configuration->getSavedFilters())): ?> <ul> <?php foreach ($savedFilters as $filter): ?> <li> <a href="<?php echo url_for('@bookmark_filter_load?id='.$filter['id']) ?>"> <?php echo $filter['name'] ?> </a> (<a href="<?php echo url_for('@bookmark_filter_delete?id='.$filter['id']) ?>"></a>) </li> <?php endforeach; ?> </ul> <?php else: ?> <p>No filters saved</p> <?php endif; ?> </td> </tr> </tbody>
Maintenant vous êtes donc capable de sauvegarder en base et de lister des filtres, les charger et les faire fonctionner sur votre liste d'objets, et bien entendu, supprimer les filtres existant. Si vous avez suivi méticuleusement les étapes de ce tutoriel, vous devriez voir quelque chose comme cela sous le formulaire de filtres :
20 minutes, le boulot est fait. Même si ce fût rapide et même un peu trop parfois.
Conclusion
Oui, je peux vous entendre, vous les Symfony nerds : on peut faire vraiment mieux, mieux écrit, mieux inclus dans la structure de Symfony, et probablement abstrait pour offrir une solution générique de stockage de filtres à travers l'ensemble des modules admin-generated... mais en 20 minutes ? Vraiment ? ;c) Mais alors je dirais :
- Allez-y, prouvez le !! :c)
Références
Ceci est une traduction libre de l'article datant de 2009 de NiKo sur son blog Prendre Un Café. Merci à lui pour l'original : http://prendreuncafe.com/blog/post/2009/12/02/Saving-Search-Filters-in-Symfony-s-Doctrine-Admin-Generator
[Catégorie:Informatique]