Ma cave sur eZ Publish : Les Templates (Partie 2)
- Publié le 16 Février 2009
- 9 commentaire(s)
- Catégorie : Technologies Web
Une fois les classes de contenus crées, il s'agit d'organiser et de développer les templates. Ma stratégie d'affichage fonctionne autour du principe suivant : "Comment être le plus fainéant possible, en générant un maximum de pages avec le moins de code possible".
Le principe utilisé est celui de l'entonnoir : C'est à dire que chaque niveau d'affichage contient l'affichage des sous niveaux, et ainsi dessuite.
Par exemple la page par région contient :
- La liste de tous les domaines de la région
- La liste de toutes les localisations Google maps de la région
- La liste des appellations de la région
- La liste de toutes les cuvées par appellations, etc.
Les pages intermédiaires des appellations, des domaines et des cuvées fonctionnent sur le même principe, et recyclent ainsi des blocs d'affichages identiques.
Les fichiers de templates et les overrides
Création des fichiers selon certaines conventions
Chaque template est personnalisé par overrides et respecte quelques conventions. Ce n'est pas obligatoire, mais cela facilite la compréhension du code et l'entretien du site :
- [class_identifier]_full.tpl : La vue complète du noeud
- [class_identifier]_line.tpl : La vue en ligne du noeud (pour une liste par exemple)
- [class_identifier]_XXX.tpl : Une vue particulière du noeud (résumé, résultat de recherche, etc.)
Cela donne dans mon cas, par exemple pour les templates des cuvées, créés dans le répertoire extension/[mon_extension]/design/[mon_design]/override/templates/cave/ :
- cave_cuvee_full.tpl : page d'une cuvée
- cave_cuvee_line.tpl : ligne représentant une cuvée, dans tous les tableaux de toutes les pages du site
- cave_cuvee_box.tpl : bloc d'affichage détaillée d'une cuvée (photo, description), dans tous les pages du site
Définition de overrides de templates
Le fichier extension/[mon_extension]/settings/siteaccess/[mon_siteaccess]/override.ini.append.php permet de déclarer toutes les correspondances entre les classes, les types de vues et les templates. Par exemple pour les 3 templates des cuvées :
[cave_cuvee_full] Source=node/view/full.tpl MatchFile=cave/cave_cuvee_full.tpl Subdir=templates Match[class_identifier]=cave_cuvee [cave_cuvee_line] Source=node/view/cave_cuvee_line.tpl MatchFile=cave/cave_cuvee_line.tpl Subdir=templates Match[class_identifier]=cave_cuvee [cave_cuvee_box] Source=node/view/cave_cuvee_box.tpl MatchFile=cave/cave_cuvee_box.tpl Subdir=templates Match[class_identifier]=cave_cuvee
Exploitation des vues dans le code des templates
Ainsi la fabrication des tableaux listant les cuvées fonctionne toujours sur le même principe :
<table class="cuvee_table"> <tbody> {foreach $cuvees as $index => $cuvee} {node_view_gui content_node=$cuvee view=cave_cuvee_line} {/foreach} </tbody> </table>
Le tableau $cuvees est le résultat d'un fetch, dont la composition varie en fonction des pages et des paramètres.
Pour aller jusqu'au bout de la description, voici un aperçu du template cave_cuvee_lien.tpl :
{def $stock = concat('stock_', $node.data_map.stock.content) $rating = $node.data_map.rating.content.data_map.rating.content $couleur = $node.data_map.couleur.content.data_map.css_identifier.content} {def $prix = $node.data_map.prix.content|wash} {if $prix|eq(0)} {set $prix = 'N.C.'} {else} {set $prix = concat($prix, ' €')} {/if} {def $appelation = fetch( content, object, hash( object_id, $node.data_map.appelations.content.relation_list.0.contentobject_id ) )} <tr class="{$stock}"> <td class="td5"><div title="{$node.data_map.couleur.content.name} // " class="{$couleur} couleur"> </div></td> <td class="td400"><a title="{$appelation.main_node.parent.name|wash} // {$appelation.name|wash}" href={$node.parent.url_alias|ezurl}>{$node.parent.name|wash}</a> - <a class="cuvee_invert" href={$node.url_alias|ezurl}>{$node.name|wash}</a></td> <td class="td80 {$stock}"><a href={$node.url_alias|ezurl} title="{$node.data_map.stock.content|wash} bouteille(s) en cave // ">{$node.data_map.stock.content|wash}</a></td> <td class="td80"><div class="rating rating_{$rating}" title="Vin {$node.data_map.rating.content.name} // {if $rating|eq(0)}Pas encore bu ...{else}Cet avis est personnel et n'engage que moi !{/if}"></div></td> <td class="td80"><a title="Prix indicatif // Le prix varie selon le mode d'achat" href={$node.url_alias|ezurl}>{$prix}</a></td> </tr> {undef $stock $rating $couleur $prix $appelation}
On peut observer les quelques astuces pour gérer les notations (icônes des 5 bouteilles) en CSS, en modifiant dynamiquement le nom la classe CSS correspondante à chaque fond d'images.
Cas particulier : la liste des cuvées par appellation
La logique d'association des données rend l'opération un peu complexe. Il s'agit en quelques sorte d'effectuer la requête suivante :
- Listes moi toutes les cuvées de la région (noeud parent de l'appellation) associées (par un attribut de type Object relations) à l'appellation courante (le noeud courant)
Il est nécessaire dans ce cas de créer un Extended Attribute Filter permettant lors d'un fetch de filtrer les objets (ici les cuvées) par un objet associé (ici l'appellation courante). Ce mécanisme n'est pas très bien documenté, et il nécessite une bonne connaissance du modèle de données eZ Publish. Voici une extraction simplifiée du code :
Déclaration de l'Extended Attribute Filtre
Il faut créer le fichier extension/[mon_extension]/settings/extendedattributefilter.ini.append.php
<?php /* #?ini charset="utf-8"? [relatedObject] ExtensionName=myblog ClassName=relatedObjectClass MethodName=relatedObjectMethod FileName=classes/relatedobject.php */ ?>
Implémentation du code
Il faut donc créer le fichier extension/[mon_extension]/classes/relatedobject.php. Cet exemple est simplifié pour rendre plus compréhensible la logique du code. Il est conseillé, à long terme, de factoriser ce genre de code pour gérer tous les types de situations (plusieurs object_id, autres types de relations, sélection de l'attribut...).
<?php class relatedObjectClass { function __construct() { } function relatedObjectMethod($params) { $sqlJoins = array(); $sqlTables = array(); if(isset($params['relations'])){ foreach ($params['relations'] as $key => $relation) { if ( isset($relation['related_object_id']) ) { $table = 'tab_'.$key; $sqlTables[] = 'ezcontentobject_link AS '.$table; $sqlJoins[] = 'ezcontentobject_tree.contentobject_id = '.$table.'.from_contentobject_id AND ezcontentobject_tree.contentobject_version = '.$table.'.from_contentobject_version'; $sqlJoins[] = $table.'.to_contentobject_id='.(int)$relation['related_object_id']; } } } $sqlJoins = join(' AND ', $sqlJoins); $sqlTables = join(', ', $sqlTables); if (trim($sqlTables) != '') { $sqlTables = ', '.$sqlTables;} if (trim($sqlJoins) != '') {$sqlJoins .= ' AND ';} return array('tables' => $sqlTables, 'joins' => $sqlJoins); } } ?>
Appel dans le template
{def $vin_cuvees = fetch( 'content', 'tree', hash( 'parent_node_id', $node.parent.node_id, 'class_filter_type', 'include', 'class_filter_array', array('cave_cuvee'), 'sort_by', array( array( 'path_string', true() ) ), 'extended_attribute_filter', hash(id, 'relatedObject', 'params', hash( 'relations', array( hash('related_object_id', $node.object.id ) ) ) ) ) )}
Que boire avec ce billet ?
Domaine de la Rectorie - Coume Pascole - Rouge 2003
| Région : | Languedoc |
| Appellation : | Collioure |
| Domaine : | Domaine de la Rectorie |
| Couleur : | |
| Stock : | 0 |
| Notation : | |
| Prix : | 19 € |
| Commentaire(s) : | 0 Commentaire(s) |
Finalement tous les vins de ce domaine ont un air de ressemblance : concentration, présence exubérante du fruit rouge, finesse et longueur, élégance... Autre règle absolue, à garder quelques années avant de déguster, c'est à dire entre 5 et 10 ans. Il n'est pas étonnant que ces cuvées soient de plus en plus difficile à trouver et que les prix grimpent de façon inéluctable.
fénéant techniquement = ergonomie mal adaptée à l'internaute fénéant
la technique de l'entonnoir ne me plaît pas ergonomiquement, on peut cliquer partout et quand tout n'est pas saisie, on se retrouve souvent sur des pages qui se ressemblent ! l'affichage est assez complexe.
de plus, je pense qu'il manque un truc important : le fil d'ariane.
du coup si l'internaute n'est pas un pro des appellations/ domaines/cuvée, je trouve qu'on s'y perd un peu...
ça reflète bien un blog pensé techniquement avant de réfléchir à l'ergonomie
le bon point à retenir : c'est le référencement naturel, 415 pages aspirées pour /ma-cave.
Les internautes peuvent rechercher un domaine et/ou une cuvée, ils arrivent sur la bonne page
Perso je reverrais les titles pour être encore plus explicite
bref :
- être juste au niveau de l'organisation des contenus
- faire du joli code
ça fait travailler le cerveau...
mais cette rubrique n'est peut être pas optimisée pour le temps de cerveau disponible des internautes !
Mise en page des cuvées et des domaines
Effectivement, concernant les cuvées et les domaines je dois jongler avec 2 contraintes :
- La nécessité d'avoir une page par cuvée (on va pas mélanger les blancs et les rouges !)
- La réalité sur certaines cuvées, ou je n'ai pas di'nformations, et donc l'affichage des infos du domaine en dessous des infos de la cuvée est nécessaire... donc les pages se ressemblent
Peut être faudrait il que je designe les pages de cuvées autrement...
En tout cas, ca fonctionne pas trop mal pour le référencement ![]()
et maintenant les templates !!
bon là, j'avoue, je suis un peu larguée ... désolée les gars !
le seul truc que j'approuve c'est le choix de la Rectorie à boire avec ce billet ... hips !
L'extendedAttributeFilter
Alors je vais finir par être fan de ce blog.
Tricky l'extended Attribute. Il se trouve que sur un de mes projets je vais sûrement utiliser quelquechose dans ce goût.
Souvent je me demande ce qui est le plus performant entre coller un fetch complexe dans une template ou développer un opérateur spécifique... des opinions la dessus?
Fetch complexe ou ExtendedAttributeFilter
La question se pose déjà lorsqu'il est possible de s'en sortir avec un Fetch ou une combinaison de Fetch complexes. Quand on s'est habitué aux ExtendedAttributeFilter, ca permet tout de même de simplifier largement le code, et de factoriser les situations récurrentes. Le code en devient plus performant et plus facile à entretenir qu'une pléthore de Fetch imbriqués... Mais bon, les situations ne se ressemblent pas, on ne peut rien généraliser.
Template
Bonjour,
Sur ton site comment fais tu la surcharge de CSS.
C est a dire , quand tu vires du template blanc au template noir.
Merci et Felicitation pour le site , il est superbe!
Changement de CSS blanc et noir
Marakud, je ne surcharge pas les CSS, je change la source dynamiquement avec JavaScript / Mootools.
Mootools propose un objet pour cela : http://mootools.net/docs/Plugins/Assets
Cet objet permet de précharger des images, des fichiers javascripts, des fichiers CSS... Je l'utilise par exemple pour précharger les images du bandeau.
Pour la suite, le plus simple c'est encore d'explorer le code JavaScript du site avec FireBug.
Template
Re bonjour,
j'ai donc visiter le site que tu m'a donné...
Et j'ai essayé d'appliquer mootools, mais je narrive pas avec ezpublish.
J'ai bien verifier a savoir , si les includes sont bien fait.
Mais je pense que ezpublish ne prends pas en compte, le javascript que je lui met en include.
pourrais tu maider a mieux comprendre le fonctionnement de mootools sur ezpublish stp.
merci
literal
Qd tu inclus du code javascript dans une template, pense à utiliser {literal}
http://ez.no/doc/ez_publish/techn...late_functions/miscellaneous/literal
