Apprentissage DTML : mini site en 100 lignes [Brève]
Pour 100 lignes, t'as un site web, un vrai !
Ce site est simple, même simpliste (un habillage CSS serait le bienvenu), mais propose les fonctions de bases d'un site web :- Affichage du titre de la page
- Affichage de l'URL et de la date de mise à jour (potentiellement tout autre donnée de ce type : copyright et autres mentions légales)
- Navigation ascendante (breadcrumb), descendante (menu local), locale (articles dans la page)
- Plan du site
- Recherche sur le site
- Gestion de la sécurité : la navigation, le plan, et la recherche tiennent compte d'éventuelles restrictions d'accès
Structure
Les pages sont structurées très classiquement (en-tête / corps en 2 colonnes / pied). La configuration "standard" est la suivante : chaque rubrique forme une page, composée par les articles entreposés à ce niveau.On peut créer autant de rubriques que l'on veut ; les rubriques "Plan" et "Recherche" proposent des interfaces évidemment spécifiques.
Le site isole la zone de paramétrage et le site proprement dit :
- la racine globale stocke les codes définissant la logique (scripts, méthodes) ainsi qu'un ZCatalog ;
- la racine contient aussi le sous-répertoire "site" qui contient les rubriques ;
- en desous de "site", les rubriques "plan" et "recherche" abritent des versions surchargés de la méthode d'affichage du contenu.
Les systèmes de navigation utilisés permettent de restreindre l'accès aux des rubriques sans que cela ne perturbe les liens (les documents non-accessibles ne sont jamais "cliquables").
Objets manipulés
Ce site utilise 6 types d'objets Zope :- 10 "DTML Method", pour structurer la présentation
- 1 "Python Scripts", pour réaliser certains traitements logiques (navigation)
- 1 "ZCatalog", pour indexer et rechercher les contenus
- des "DTML Document", pour présenter les articles (autant que d'articles)
- des "Folder", au moins 4, pour structurer le site.
DTML
Le DTML est un langage à balises : <tag>quelque chose</tag>Le site fait usage des balises DTML suivantes :
- "dtml-var" : pour "rendre" des objets, pour "évaluer" le résultat d'expressions Python
- "dtml-if" ("dtml-elif" "dtml-else") : pour effectuer du traitement conditionnel (présentation)
- "dtml-in" : pour traiter des listes
- "dtml-with" : pour surcharger l'espace de noms courant
- "dtml-tree" : pour afficher le plan du site
- "dtml-try ("dtml-except" "dtml-finally") : pour protéger d'une exception éventuelle
Fonctions et expressions
Plusieurs fonctions et expressions Python sont utilisées.Certaines font directement référence à l'objet placé au sommet de l'espace de nom :
- title_or_id : retourne le titre ou l'identifiant
- absolute_url : retourne l'URL absolue depuis la racine
- bobo_base_modification_time : date de mise à jour (ancien et conservé)
- objectValues : liste des objets contenus (s'applique aux objets conteneurs)
- aq_parent : place le conteneur de l'objet au sommet de l'espace de noms
- getId : retourne l'identifiant
- getObject : retourne l'objet lui-même
- sequence-item : l'objet courant dans une boucle "dtml-in"
Sécurité
La gestion de la sécurité permet ici de créer des rubriques en accès réservé sans que celles-ci soient, via le plan, la navigation, ou la recherche ... proposées à l'utilisateur dépourvu des droits nécessaires.On utilise une protection implicite au sein du parcours des listes, à l'aide du modificateur "skip_unauthorized"
Le code (validé>
DTML Method : index_html
<dtml-var header_html> <dtml-var body_html> <dtml-var footer_html>Il fallait y penser : décrire logiquement le contenu d'une page web, aggréger les différents éléments, supporter l'enchassement d'éléments. Après, il n'y a plus qu'à définir une correspondance entre les éléments, stockés dans une base de donnée orientée objet, et les URLs ... Voilà l'un des aspects les plus immédiats de Zope pour un concepteur web.
DTML Method : header_html
<html> <head><title><dtml-var "title_or_id()"></title></head> <body>Vous avez compris l'aggrégation ? la page HTML va se construire peu à peu via la suite des ordres DTML et l'enchassement des éléments ...
DTML Method : footer_html
<p><table width="100% cellpadding="2">
<tr align="center"><td width="50%"><dtml-var "absolute_url()"></td>
<td><dtml-var "bobobase_modification_time().strftime('%d/%m/%Y')"></td>
</tr></table>
</body>
</html>
Evidement, on termine ici la page HTML.
L'URL de la page courante et sa date de mise à jour (ici l'objet considéré est le Folder courant)
sont automatiquement fournies.
Mais quelle facétie a poussé les concepteurs à conserver cette fonction ancestrale et au nom
barbare ("bobo" est l'ancêtre de Zope ...) ?
DTML Method : body_html
<table width="100%" cellpadding="5"> <tr><td width="25%" valign="top"><small><dtml-var page_menu_html></small></td> <td><small>Vous êtes ici : <dtml-var breadcrumb_py></small> <p><dtml-var page_content></td></tr> </table>Et voilà pour l'enchassement ! Le menu, la navigation, les contenus : tout est intégré dans la page !
Ici, on récupère très simplement la navigation ascendante (les breadcrumbs) à l'aide d'un script Python.
DTML Method : page_menu_html
Rubriques : <dtml-in "objectValues(['Folder'])" skip_unauthorized> <li><a href="<dtml-var absolute_url>"><dtml-var "title_or_id()"></a></li> </dtml-in><p> Articles : <dtml-in "objectValues(['DTML Document'])"> <li><a href="#<dtml-var "getId()">"><dtml-var "title_or_id()"></a></li> </dtml-in>Deux listes sont parcourues, elle sont obtenues en listant le contenu de la rubrique sur tel ou tel type d'objet, répertoires pour l'une (sous-rubriques), documents pour l'autre (articles).
Nous avons besoin de contrôler les permissions d'accès avant de proposer la liste des sous-rubriques ; c'est immédiat avec le filtre "skip_unauthorized" particulièrement explicite.
Python Script : breadcrumb_py
links=[]
for parent in context.REQUEST.PARENTS:
links.insert(0, """<a href="%s">%s</a>""" % (parent.absolute_url(), parent.getId()))
if parent.getId() == "site":
break
return " / ".join(links)
Un peu de calcul et un peu de mise en forme ; on accède à la variable contextuelle PARENTS pour
récupérer toute la hiérarchie supérieure.
DTML Method : page_content_html
<h1><dtml-var "title_or_id()"></h1> <dtml-in "objectValues(['DTML Document'])" sort="id"> <a name="<dtml-var "getId()">"></a> <h2><dtml-var "title_or_id()"></h2> <dtml-var sequence-item> </dtml-in>Construction de la page : les documents disponibles sont chargés par ordre alphabétique ; on positionne l'ancre nécessaire à la gestion de la navigation intrapage.
DTML Method : page_content_html pour le Folder 'plan'
<h1><dtml-var "title_or_id()"></h1>
<a href="&dtml-URL0;?expand_all=1"> Tout développer </a><br>
<a href="&dtml-URL0;?collapse_all=1"> Tout réduire </a>
<p>
<dtml-tree site skip_unauthorized>
<a href="<dtml-var "absolute_url()">"><dtml-var "title_or_id()"></a>
</dtml-tree>
Une fonctionnalités les plus époustouflantes ! le plan dynamique se monte avec un seul
élément DTML ; comme on n'est pas radin, mais plutôt soigneux, ici encore on va vérifier
que le visiteur est bien autorisé avant de lui proposer la navigation : le miracle s'accomplit avec
l'invocation du filtre "skip_unauthorized".
DTML Method : page_content_html pour le Folder 'recherche'
<h1><dtml-var "title_or_id()"></h1> <dtml-var search_param_html> <p> <dtml-var search_result_html>Un formulaire pour la saisie des paramètres de recherche, et une fonction d'affichage des résultats.
DTML Method : search_param_html
<form action="" method="get"> <input type="text" name="search_string" size="40" value="<dtml-var search_string missing="">" ></input> <input type="submit" value="Rechercher"></input></td> </form>Un formulaire des plus élémentaires, mon cher Watson ! Ici aussi, Zope permet des contrôles de typage, de validité des champs, etc.
DTML Method : search_result_html
<dtml-if search_string>
<dtml-in "catalog.searchResults({'PrincipiaSearchSource':search_string})"
sort="bobobase_modification_time">
<dtml-try>
<dtml-if "getObject()">
<dtml-with getObject>
<dtml-if "_.SecurityGetUser().has_permission('View', this())">
<a href="<dtml-with aq_parent><dtml-var "absolute_url()"></dtml-with>#<dtml-var "getId()">">
<dtml-var "title_or_id()"></a>
<dtml-else><dtml-var "title_or_id()"></dtml-if>
<br></dtml-with>
</dtml-if>
<dtml-except>
</dtml-try>
</dtml-in>
<dtml-else>
<ul><li>rechercher</li>
<li>chercher AND trouver</li>
<li>trouv* OR trouver</li></ul>
</dtml-if>
On invoque la ZCatalog via les index de type "Plein Texte" ; les paramètres du formulaire
sont implicitement transmis et donc immédiatement récupérables dans le code.
On procède aussi à un test de sécurité, cette fois-ci en testant explicitement une permission de l'utilisateur courant sur l'objet référencé par l'index retourné. Si les droits sont insuffisants, on ne fournira pas la navigation.
Commentaires
Re: Apprentissage DTML : mini site en 100 lignes
Posted by:
zopera
at
10/09/01
Encore une contribution __REMARQUABLE__ !!!
Hé bien voilà ce que j'appelle un tutorial ! Fabuleux, c'est simple, concis, et à la portée des débutants (dont je fais partie). Merci beaucoup !
Dans body_html, il me semble qu'il y a une erreur :
%s/page_content/page_content_html

Log in
PloneArticle
Restreindre les meta_types d'un ObjectManager