Upload
mauger-normand
View
109
Download
0
Embed Size (px)
Citation preview
symfony
generators
contexte
• Répétition de l’implémentation des méthodes CRUD pour ls objets métier
• Commande symfony permettant d’initialiser un module
symfony <TASK_NAME> <APP_NAME> <MODULE_NAME> <CLASS_NAME>
– <TASK_NAME>• propel-init-crud• propel-generate-crud• propel-init-admin.
Scaffolding
• un scaffolding est une structure basique (actions et templates) utilisée pour implémenter les méthodes CRUD sur une table
• Le code est minimal car il est censé servir de guide pour une développement future
• C’est une base qui doit être adaptée pour correspondre aux besoin logiques et de présentation du développeur.
• Les scaffoldings sont utilisés essentiellement pendant la phase de développement, pour avoir un accès web a une base de données, pour construire un prototype, ou comme base pour un module basé lui-même sur une table
Administration
• Une administration est une interface sophistiquée de manipulation de données, typiquement dédiée à la partie back office– Les Administrations se distinguent des scaffolding
en cela que leur code n’est pas modifiable. – Elles peuvent être paramétrées, étendue, ou
assemblées par héritage ou configuration. – Leur présentation est importante, et elles offrent
des possibilités de tri, pagination, et filtrage. – Une administration peut être créée et distribuée au
client comme une partie finie de l’application
Terminologie symfony
– Scaffolding (crud) • inheritance (init)
– Classes vides (squelettes)– N’est pas fait pour être modifié ( phpMyAdmin)
• code generation (generate)– Classes avec Code– En vue d’une adpatation du code généré
– Administration (admin)• Modifiable via la configuration
Initialiser un scaffolding
• symfony propel-init-crud myapp article Article – http://localhost/myapp_dev.php/article – Aucune action dans actions.class.php– Aucun template dans le répertoire templates/– Tout est hérité d’une classe auto-générée
• myproject/cache/myapp/prod/module/autoArticle/ – en cache
Générer un scaffolding
• symfony propel-generate-crud myapp article Article – http://localhost/myapp_dev.php/article – Contrôleur et templates générés à partir du
schema.yml dans myapp/modules/article/ – Code pour CRUD
Détails de la génération d’un scaffolding
• Dans actions/actions.class.php – index : redirection sur l’action list– list : affiche la liste de tous les enregistrements de la table– show : affiche toutes les colonnes d’un enregistrement– edit : affiche un formulaire de modification d’un enregistrement– update : action appelée par le formulaire d’édition– delete : supprimer un enregistrment – create : ajouter un nouvel enregistrement
• Dans le répertoire templates/ – editSuccess.php : formulaire d’édition d’un enregistrement – listSuccess.php : liste de tous les enregistrements– showSuccess.php : détails d’un enregistrement
actions.class.php généréclass articleActions extends sfActions {
public function executeIndex() {
return $this->forward('article', 'list'); } public function executeList() {
$this->articles = ArticlePeer::doSelect(new Criteria());} public function executeShow() {
$this->article = ArticlePeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->article); }
...
administration
• Typiquement adapté au back office– symfony init-app backend
• symfony propel-init-admin backend article Article
• http://localhost/backend.php/article • Fichier de conf cutomisable generator.yml
– Omposants logiques– Look & feel
• Possibilité de refédinir les action ste les templates
administration – code généré• Tout est en cache• dans actions/actions.class.php
– create : redirection vers l’action edit– delete : supprime un enregistrement– edit : affiche le formulaire d’édition d’un module, et assure le traitement de la
soumission de ce formulaire– index : redirige vers l’action list– list : affiche la liste de tous les enregistrements – save : redirige vers l’action edit
• Dans le répertoire templates/ – editSuccess.php : _edit_actions.php, _edit_footer.php, _edit_form.php,
_edit_header.php, _edit_messages.php– _filters.php– listSuccess.php : _list.php, _list_actions.php, _list_footer.php,
_list_header.php, _list_messages.php, _list_td_actions.php, _list_td_stacked.php, _list_td_tabular.php, _list_th_stacked.php, _list_th_tabular.php
generator.yml
• backend/modules/article/config/generator.yml par défaut• N.B. toute customisation se fait à la suite du thème et doit
par conséquent commencer par 4 espaces
http://www.symfony-project.org/uploads/assets/sfAdminGeneratorRefCard.pdf
generator: class: sfPropelAdminGenerator param: model_class: Article theme: default
generator.yml - action list - typiquegenerator: class: sfPropelAdminGenerator param: model_class: Article theme: default fields: author_id: { name: Article author } list: title: List of all articles display: [title, author_id, category_id] fields: published_on: { params: date_format='dd/MM/yy' } layout: stacked params: | %%is_published%%<strong>%%=title%%</strong><br /> <em>by %%author%% in %%category%% (%%published_on%%)</em> <p>%%content_summary%%</p> filters: [title, category_id, author_id, is_published] max_per_page: 2
generator.yml - action edit - typiquegenerator: class: sfPropelAdminGenerator param: model_class: Article theme: default fields: author_id: { name: Article author } edit: title: Editing article "%%title%%" display: "Post": [title, category_id, content] "Workflow": [author_id, is_published, created_on] fields: category_id: { params: disabled=true } is_published: { type: plain} created_on: { type: plain, params: date_format='dd/MM/yy' } author_id: { params: size=5 include_custom=>> Choose an author << } published_on: { credentials: } content: { params: rich=true tinymce_options=height:150 }
generator.yml - fields
• Par défaut la liste des champs est déduite du schema.yml– Il est possible de paramétrer quels champs
seront affichés, cachés, et même d’afficher des champs customiser n’ayant pas une correspondance direct avec l’objet
• Fields peut agir au niveau général et peut être redéfini au niveau de l’action edit ou list (c’est un principe général)
generator.yml – fields configuration
• name: nom de l’objet
• type: type de balise d’édition (de formulaire) à utiliser
• params: paramètres supplémentaires: classes CSS, taille de la balise d’édition, etc …
• help: texte d’aide afficher lors de l’édition
generator.yml - display• Permet de spécifier quels champs sont affichés dans une
action ainsi que l’ordre d’affichage (edit & list)• Permet également de regrouper les champs par rubrique
(edit)generator: class: sfPropelAdminGenerator param: model_class: Comment theme: default list: display: [id, article_id, content] edit: display: NONE: [article_id] Editable: [author, content, created_at]
generator.yml – display II
• Par défaut les clés primaires sont toujours cachées
generator.yml – customized fields
• Les champs du generator.yml ne doivent pas forcément correspondre à des champs de base de données– Un getter du modèle peut être utilisé dans
l’action list– Un getter et / ou un setter peut être utilisé
dans l’action list et edit
generator.yml – customized fields II
• lib/model/Article.phppublic function getNbComments()
{
return $this->countComments();
}
generator: class: sfPropelAdminGenerator param: model_class: Article theme: default list: display: [id, title, nb_comments, created_at]
generator.yml – customized fields III
• lib/model/Comment.class.phppublic function getArticleLink()
{
return link_to($this->getArticle()->getTitle(), 'article/edit?id='.$this->getArticleId());
}
generator: class: sfPropelAdminGenerator param: model_class: Comment theme: default list: display: [id, article_link, content]
generator.yml - partial
• MVC compliance!!• modules/comment/templates/_article_link.php<?php echo link_to($comment->getArticle()->getTitle(),
'article/edit?id='.$comment->getArticleId()) ?> • Accès à l’objet courant
– currentObject -> $current_object
list: display: [id, _article_link, created_at] fields: article_link: { name: Article }
generator.yml partial + logic = component
• Appel à la méthode articleLink de actions/components.class.php
• Peut être utilisée dans le contexte list, edit, filter– Le contexte est accessible via $type
list: display: [id, ~article_link, created_at] fields: article_link: { name: Article }
Paramétrage de l’affichagele titre
list: title: List of Articles ... edit: title: Body of article %%title%% display: [content]
%% … %% Permet d’accéder à un champs de l’objet
generator.yml - note d’aide
edit: fields: ... article_id: { help: The current comment relates to this article }
modules/comment/config/generator.yml
generator.yml – format de date
• N.B. le administrations sont i18n - ready
list: fields: created_at: { name: Published, params: date_format='dd/MM' }
generator.yml – affichage de l’action list
• Par défaut l’éction edit est lié (au sens hypertexte) à la clé primaire
• = devant le nom du champs cliquable
list: display: [article_link, =content]
generator.ymltabular (default)/ stacked
list: layout: stacked params: | %%=content%% <br /> (sent by %%author%% on %%created_at%% about %%article_link%%) display: [created_at, author, content]
generator.yml - filtreslist: filters: [article_id, author, created_at] layout: stacked params: | %%=content%% <br /> (sent by %%author%% on %%created_at%% about %%article_link%%) display: [created_at, author, content]
generator.yml – filtres II
• Pour les colonnes textes le filtre est une entrée texte possédant (*) en caractère joker
• Pour les clé étrangères le filtre est une liste déroulante contenant les enregistrements de la table liée (comme pour object_select_tag(), le texte des options est celui retourné par la méthode __toString() de la classe liée)
• Pour les colonnes dates le filtre est composé de deux calendrier (rich) permettant la sélection d’un intervalle de temps
• Pour les colonnes booléennes, le filtre est une liste déroulante possédant les valeurs: « true », « false », et « true or false » - la dernière valeur réinitialise le filtre
generator.yml – filtres partial• Imaginons un champs status pouvant prendre deux valeurs
(open ou closed), sans table étrangère• templates/_state.php <?php echo select_tag('filters[state]',
options_for_select(array( '' => '', 'open' => 'open', 'closed' => 'closed',
), isset($filters['state']) ? $filters['state'] : '‘)) ?>• config/generator.yml list: filters: [date, _state] • N.B. le contenu des champs est accessible via $filter
generator.yml – filtrage par valeur vide
• Afficher tous les commentaires sans auteur
list: fields: author: { filter_is_empty: true } filters: [article_id, author, created_at]
generator.yml – trier les listes
• En liste toutes les colonnes sont cliquables pour l’ordonnancement
• Lien direct vers une liste ordonnée selon une colonne<?php echo link_to('Comment list by date', 'comment/list?
sort=created_at&type=desc' ) ?>
• Les champs partial ne peuvent pas être un critère de tri
list: sort: created_at # Alternative syntax, to specify a sort order sort: [created_at, desc]
generator.yml - pagination
list: max_per_page: 5
generator.yml – utiliser un jointure pour accélerer les temps de réponse
• Par défaut doSelect est utilisé
• Affichage du nom de l’auteur d’un commentaire– requête supplémentaire à chaque
commentaire
list:
peer_method: doSelectJoinArticle
generator.yml – changer le type d’un champs en édition
• Une colonne définie comme integer, float, char, varchar(size) sera représentée en édition par object_input_tag().
• Une colonne définie comme longvarchar sera représentée en édition object_textarea_tag().
• Une clé étrangère sera reprsentée par object_select_tag().
• Une colonne définie comme boolean sera représentée par object_checkbox_tag().
• Une colonne définie comme timestamp ou date sera représentée object_input_date_tag().
generator.yml – changer le type d’un champs en édition II
<?php echo object_select_tag($comment, 'getArticleId', 'related_class=Article', 'include_custom=Choose an article') ?>
edit: fields: ## Drop the input, just display plain text id: { type: plain } ## The input is not editable author: { params: disabled=true } ## The input is a textarea (object_textarea_tag) content: type: textarea_tag params: rich=true css=user.css tinymce_options=width:330 ## The input is a select (object_select_tag) article_id: { params: include_custom=Choose an article }
generator.yml – gérer les champs partial
• templates/_newpassword.php
<?php echo input_password_tag('newpassword', '') ?>
edit: display: [id, nickname, _newpassword] fields: newpassword: name: Password help: Enter a password to change it
generator.yml – gérer les champs partial II
class userActions extends autouserActions { protected function updateUserFromRequest() { $password = $this->getRequestParameter('newpassword');
if ($password) { $this->user->setPassword($password); }
parent::updateUserFromRequest(); } }
generator.yml – gérer les champs partial III
• Imaginons que newpassword soit un champs de la table
• templates/_newpassword.php
<?php echo input_password_tag(‘user[newpassword]', '') ?>
• Rien à redéfinit dans le contôleur
• Pour accéder à la valeur dans le contrôleur$user = $this->getRequestParameter(‘user');
$password = $user['newpassword‘];
generator.yml – relation 1-n
• Génération automatique de liste déroulante– La valeur est toujours l’id– Le texte est le résultat de la méthode
__toString() de l’objet lié ou l’id si cette méthode n’existe pas
• relation n-1 : nombre de commentaires liés à un article– Gestion via un partial
generator.yml – relation n-n
edit: fields: article_author: { type: admin_double_list, params: through_class=ArticleAuthor }
generator.yml – actions de base
list: title: List of Articles object_actions: _edit: ~ _delete: ~ actions: _create: ~ edit: title: Body of article %%title%% actions: _list: ~ _save: ~ _save_and_add: ~ _delete: ~
generator.yml – ajouter une action
• Article/actions.actions.class.phppublic function executeAddComment() {
$comment = new Comment(); $comment->setArticleId($this->getRequestParameter('id')); $comment->save(); $this->redirect('comment/edit?id='.$comment->getId());
}
list: title: List of Articles object_actions: _edit: - _delete: - addcomment: { name: Add comment, action: addComment, icon: addcomment.png }
generator.yml – ajouter une action II
generator.yml – supprimer les actions
• Pour supprimer toutes les actions d’une section
list: title: List of Articles actions: {}
generator.yml - nommage
• Convention de nommage dans les administrations– champs de formulaire pour $article->title – name=‘’article[title]’’– id=‘’article_title’’
// generator.yml edit: display: [title]
// Resulting _edit_form.php template <?php echo object_input_tag($article, 'getTitle', array('control_name' =>
'article[title]')) ?> // Resulting HTML <input type="text" name="article[title]" id="article_title" value="My Title" />
generator.yml – conséquence sur les validateurs
## Replace square brackets by curly brackets in the fields list fields: article{title}: required: msg: You must provide a title ## For validator parameters, use the original field name between quotes sfCompareValidator: check: "user[newpassword]" compare_error: The passwords don’’t
generator.yml - credentials
## The id column is displayed only for users with the admin credential list: title: List of Articles layout: tabular display: [id, =title, content, nb_comments] fields: id: { credentials: [admin] } ## The addcomment interaction is restricted to the users with the admin credential list: title: List of Articles object_actions: _edit: - _delete: - addcomment: credentials: [admin] name: Add a comment action: addComment icon: backend/addcomment.png
generator.yml – feuille de style
generator:
class: sfPropelAdminGenerator
param:
model_class: Comment
theme: default
css: mystylesheet
generator.yml – personnalisé l’en-tête et le pied de page
• Il suffit de créer dans le répertoire templates – _list_header.php – _list_footer.php – _edit_header.php
– _edit_footer.php
• Ces templates seront automatiquement redéfinis– _edit_header.php
<?php if ($article->getNbComments() > 0): ?> <h2><?php echo $article->getNbComments() ?> comments.</h2> <?php endif; ?>
• Dans un partial edit : l’objet est toujours accessible via une variable portant le nom de la classe ($article)
• Dans un partial list : le pager est toujours accessible via la variable $pager
generator.yml – appel d’actions avec paramètres
This article has
<?php echo link_to($article->getNbComments().' comments',
'comment/list', array(
'query_string' => 'filter=filter&filters%5Barticle_id%5D='.$article->getId()
)) ?>
comments.
• La valeur de query_string est une version encodée de 'filter=filter&filters[article_id]='.$article->getId()
• Il est possible de spécifier un filtre ou un ordre
generator.yml - thèmes
• Tous les partials hériéts du framework peuvent être redéfinis dans le répertoire template
• Possibilité de redéfinir ces partials pour plusieurs modules: écrire un nouveau thème
• Thème par défaut : $sf_symfony_data_dir/generator/sfPropelAdmin/default/
• Thème personnalisé : data/generator/sfPropelAdmin/[theme_name]/template/ (partir du thème par défaut)
generator.yml – thèmes II• // [theme_name]/template/templates/ _edit_actions.php _edit_footer.php _edit_form.php _edit_header.php _edit_messages.php _filters.php _list.php _list_actions.php _list_footer.php _list_header.php _list_messages.php _list_td_actions.php _list_td_stacked.php _list_td_tabular.php _list_th_stacked.php _list_th_tabular.php
// [theme_name]/template/actions/actions.class.php // Process the request filters processFilters() // Adds a filter to the Criteria objectaddFiltersCriteria() processSort() addSortCriteria()
generator.yml – themes III
• Ces templates sont des templates de templates– Ces fichiers seront parsés pour générer les
templates finaux (phase de compilation)• Syntaxe alternative
<?php foreach ($this->getPrimaryKey() as $pk): ?>
[?php echo object_input_hidden_tag(
$<?php echo $this->getSingularName() ?>,
'get<?php echo $pk->getPhpName() ?>‘
) ?]
<?php endforeach; ?>
• code produit
<?php echo object_input_hidden_tag($article, 'getId') ?>
generator.yml – themes IV
• Mieux vaut partir des originaux• Un thème peut être packagé dans un plugins pour une
plus grande réutilisabilité et déploiement plus rapide• Il est possible de construire des générateurs
personnalisés$generator_manager = new sfGeneratorManager();
$data = $generator_manager->generate('sfPropelAdminGenerator', $parameters);
• API documentation de sfGeneratorManager • Exemple: sfAdminGenerator et sfCRUDGenerator