Zope pour tous

Par , mai 2002.

Table des matières

Qu'est-ce que Zope peut faire pour vous?

Zope peut vous aider à créer des applications web dynamiques comme un portail ou un intranet à la vitesse de l'éclair. On dit qu'il s'agit d'un serveur d'applications, mais il est généralement utilisé comme engin de publication web.

Zope, c'est le Visual Basic du web*. Vous pouvez mettre ensemble une multitude de modules pour ajouter en quelques clics des objets complexes comme un système de nouvelles à la Slashdot (Squishdot). Aussi, Zope supporte des standards comme XML-RPC, DOM, et WebDAV, ce qui lui donne une très grande flexibilité et interopérabilité.

Zope inclue ses propres serveurs web et FTP, bien qu'il puisse coopérer efficacement avec Apache. Son système de stockage d'objets transactionnel et performant prend en charge la persistance des objets et permet d'éviter tous les tracas qu'apporte une application web traditionnelle avec base de données. Par contre, Zope peut tout de même coopérer avec d'autres types de stockage, comme des bases de données relationnelles (MySQL, Oracle, SQL Server, etc.).

Le système de stockage de Zope contient des objets, dont les plus importants sont les Page Templates constitués de DTML, un langage exécuté côté serveur et relativement simple. On y retrouve aussi des extensions, ou "produits", qui sont généralement un combinaison de DTML et de Python.

Il est important de noter que même si Zope est fait presqu'entièrement en Python, il n'est pas nécessaire de connaître Python pour utiliser Zope. Vous aurez vraiment besoin de Python lorsque le DTML n'est plus approprié pour ce que vous désirez faire, comme supporter des protocoles tels POP3 ou SNMP.

Enfin, Zope est réputé pour être très rapide. La totalité du code est en Python, mais par défaut, des fonctions ont été écrites en C, pour un plus grande vitesse d'exécution. Si ce n'est pas suffisant, vous pouvez augmenter votre capacité avec ZEO, qui permet de distribuer le stockage sur plusieurs machines, et d'exécuter plusieurs instances de Zope en même temps.

Zope est un produit open source couvert par la Zope Public License (reconnue par la Open Source Definition), et est supporté par une compagnie basée en Virginie, à une heure de route de Washington.

Étant donné que Zope est composé de plusieurs modules, il est difficile d'établir son âge. On peut dire que ça a commencé au milieu de 1996, peu avant la quatrième conférence internationale sur Python.

Installation

Les auteurs de Zope sont soucieux d'obtenir de bonnes performances, et ont essayé plusieurs façons d'utiliser Zope. Un document comparant les différentes façons est disponible. La plus simple est d'utiliser le serveur HTTP de Zope, mais la plus rapide est de compiler Apache avec mod_pcgi. L'équipe de Linux-Québec a plutôt opté pour l'installation d'Apache et sa configuration en tant que proxy (avec ProxyPass). C'est apache qui répond aux requêtes des clients, mais il ne fait que passer celles-ci au serveur HTTP de Zope, qui roule en parallèle sur la même machine. Ça permet de se servir des fonctions normales d'Apache (pages statiques, SSL, PHP, CGI).

Le Livre Zope comporte un chapitre qui couvre bien l'installation standard. Celle-ci est très simple, et consiste à télécharger l'archive, la décompresser à l'endroit voulu, et à exécuter le script d'installation: install. Par défaut, Zope se configure pour s'exécuter avec le même utilisateur UNIX que vous utilisez. Le site de Linux-Québec utilise non pas "root", ni "nobody", mais plutôt "zope". Il suffit donc de donner tous les fichiers à cet utilisateur ("chown -R zope:zope *"), et de changer pour l'utilisateur désigné avant d'exécuter le script d'installation ("su zope").

Exploration

Même si nous n'avons encore pas fait grand-chose, ça ne nous empêche pas d'utiliser le travail des autres!

Ajout d'objets pré-définis (Image, File, Squishdot) (on montre ça immédiatement pour épater)

Ajouter un fichier à la racine, le modifier, et le visualiser.

Uploader un fichier, le modifier et le visualiser.

Ajouter un objet Squishdot dans la racine et le visualiser.

Premier exercice

Lorsqu'on crée un site web, on veut normalement obtenir une uniformité d'une page à l'autre. Par exemple, on peut vouloir faire en sorte que le fond d'écran soit d'une certaine couleur, ou qu'un texte précis soit affiché au bas de toutes les pages.

Dans Zope, les documents incluent normalement deux autres documents: standard_html_header et standard_html_footer, qui sont déjà présents lors d'une installation fraîche. Ces deux documents peuvent contenir n'importe quoi, mais servent généralement à organiser la page à afficher. On met habituellement les tags <HTML>, <HEAD>, <TITLE> et <BODY> dans standard_html_header et on ferme ces tags dans standard_html_footer.

Notez que ce mécanisme va à l'encontre de la pratique qui consiste à avoir uniquement des documents complets. Un document complet en est un si tous les tags qui y sont ouverts y sont égalements fermés. Cette pratique rend évidents les problèmes d'ouverture et de fermeture de tags.

Commençons par créer un document DTML simple. Dans la liste déroulante, sélectionnez "DTML Document", mettez "index_html" comme Id, et "Mon premier exercice avec Zope" comme titre. Modifiez le contenu de ce document pour qu'il ressemble à ceci:

<dtml-var standard_html_header>

<h1><dtml-var title_or_id></h1>

<p>Bienvenue!</p>

<dtml-var standard_html_footer>

Sauvegardez, et cliquez sur l'onglet "View". Vous voyez maintenant votre document, avec l'en-tête et le pied de page par défaut.

Nous allons maintenant, en peu de temps, changer complètement la façon dont notre document est affiché. Nous allons mettre une barre verticale à gauche pour contenir un menu, et notre document sera affiché à droite.

Modifiez les documents standard_html_header et standard_html_footer de cette façon:

<html>
<head>
  <title><dtml-var title_or_id></title>
</head>
<body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table border="0" cellpadding="2" cellspacing="0" height="100%">
  <tr>
    <td valign="top" width="150" bgcolor="#DDDDDD">
      <center>Menu</center>
    </td>
    <td valign="top">

    </td>
  </tr>
</table>
</body>
</html>

Maintenant, si vous visualisez votre document index_html comme tout à l'heure, vous verrez une grande différence. Ce n'est qu'un début!

Nous avons donné aux deux documents standard le rôle de mettre en place les éléments de la page. Plutôt que de mettre tout le code HTML du menu dans le standard_html_header, nous allons créer un document qui contiendra uniquement le menu, et inclure le menu dans standard_html_header. Voici donc le document 'menu':

<ul>
  <li>Accueil
  <li>Mécanique
  <li>Biologie
  <li>Nous rejoindre
</ul>

Il nous faut maintenant modifier l'en-tête pour inclure ce menu:

<html>
<head>
  <title><dtml-var title_or_id></title>
</head>
<body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table border="0" cellpadding="2" cellspacing="0" height="100%">
  <tr>
    <td valign="top" width="150" bgcolor="#DDDDDD">
      <center><dtml-var menu></center>
    </td>
    <td valign="top">

Et voilà! Chacun de nos documents a maintenant une tâche précise, ce qui permet d'isoler rapidement les problèmes lorsqu'ils surviennent. De plus, nos documents sont devenus réutilisables. Le menu peut être inclu dans le standard_html_header, mais on peut l'inclure n'importe où et il s'affichera toujours correctement.

Un menu dynamique

Lorsqu'on utilise Zope dans la réalité, on se retrouve rapidement avec plusieurs documents, qu'on doit regrouper dans des répertoires. Pour cet exercice, nous tenterons de faire en sorte que chaque répertoire apparaisse automatiquement dans le menu créé dans l'exercice précédent.

Dans la racine, créez deux objets "Folder", et le nommez-les "mecanique" et "biologie". Dans chacun des répertoires, créez un document nommé index_html. Par exemple, vous pourriez y mettre ceci:

<dtml-var standard_html_header>

<h1><dtml-var title_or_id></h1>

<p>La mécanique est la science du mouvement et de l'équilibre des corps.</p>

<dtml-var standard_html_footer>

<dtml-var standard_html_header>

<h1><dtml-var title_or_id></h1>

<p>La biologie est la science qui a pour objet la description
des êtres vivants et l'étude des phénomènes qui les caractérisent.</p>

<dtml-var standard_html_footer>

Une fois répertoires et leurs documents créés, il suffit de modifier le menu de cette façon:

<ul>
  <li>Accueil
  <dtml-in expr="PARENTS[-1].objectValues(['Folder'])">
     <li><a href="<dtml-var expr="absolute_url()">"><dtml-var title_or_id></a>
  </dtml-in>
  <li>Nous rejoindre
</ul>

L'expression PARENTS[-1].objectValues(['Folder']) retourne la liste des objets de type Folder contenus dans la racine. La variable PARENTS est une liste des objets parents de l'objet courant, c'est-à-dire menu. On obtient la racine avec le parent numéro -1, ce qui signifie le dernier de la liste. On obtient l'URL de chaque Folder à l'aide de la méthode absolute_url().

Si on affichait la liste des répertoires d'un répertoire précis, c'est encore plus simple. Au lieu de PARENTS[-1], on met simplement le nom du répertoire dont on veut le contenu.

Acquisition

Sans le savoir, vous avez utilisé ce qu'on appelle l'acquisition de contenu. Si vous spécifiez quelque chose qui n'est pas présent dans le même contexte, Zope traversera tous les objets parents à la recherche de l'objet désigné.

Lorsque vous avez utilisé la variable standard_html_header dans un document placé dans le répertoire biologie, Zope n'a pas pu trouver le document dans ce même répertoire. Par contre, il l'a trouvé dans le dossier parent et l'a affiché comme si c'était un document local à biologie.

Supposons qu'on veuille afficher un menu différent lorsqu'on visualise un document du répertoire biologie. Il suffit simplement de placer un document du même nom ("menu") dans le répertoire visé:

<ul>
  <li>Girafes
  <li>Lions
  <li>Canards
</ul>

En visualisant le document biologie/index_html, on s'appercoit effectivement que le menu a changé d'allure. En retournant à la racine ou en allant dans mecanique, le menu est resté inchangé. Zope cherche les objets en traversant les contextes jusqu'à la racine. Dès qu'il trouve un objet du nom demandé, cet objet est utilisé.

Créer des nouveaux types d'objets

Jusqu'à maintenant, on a utilisé des objets pré-définis: Folder, DTML Document et objet Squishdot. Un des problèmes auxquels on fait face rapidement lorsqu'on est habitué à travailler avec des bases de données est le stockage structuré de données. Par exemple, on peut vouloir maintenir une liste d'individus dans une page web, mais on ne veut pas avoir à gérer l'affichage de quelques dizaines de fiches, une à la fois.

Deux façons, deux philosophies: fichiers python, ou clic-matic)

Exercice numéro deux

Création d'une page de liens: ZClass avec titre, url, description, et cote d'évaluation (très simple à faire en HTML, mais démontre comment c'est facile de faire ce qu'on fait normalement avec une base de données: formulaires pour ajouter des éléments, recherche structurée)

Allez dans "Control Panel", puis "Products". Ajoutez un nouvel item:

Id
Title

À côté du nouveau produit figure une boîte ouverte, qui signifie que le produit est géré par le web. Cliquez sur le nouveau produit pour en explorer le contenu. Le seul item visible est un "Product Help", qui permet de documenter le produit.

Ajoutez maintenant une ZClass à votre produit:

Id
Title
Meta Type

Assurez-vous que "Create constructor objects" et "Include standard Zope persistent object base classes" sont sélectionnés. Comme notre classe n'a besoin d'aucune fonctionnalité particulière, on n'ajoutera aucune héritance. Finalement, cliquez "Add".

De retour à notre produit, on voit la ZClass qui vient d'être créée, de même que des objets qui permettent d'instancier notre classe, c'est à dire de créer des objets de type "Link".

La première chose à ajouter à notre classe sont ses propriétés. Cliquez sur la classe "Link", puis "PropertySheets", puis "Add Common Instance Property Sheet". Donnez-lui simplement l'identifiant "entry_info", cliquez "Add", et entrez dans la feuille de propriétés que vous venez de créer. Vous allez ajouter toutes les propriétés suivantes:

Champ Type Description
title string Titre de l'hyperlien
url string URL de l'hyperlien

Une fois les deux propriété ajoutées, retournez à votre produit.

Maintenant, nous allons permettre à nos futurs objets de s'afficher. Pour cela, il faut ajouter une méthode DTML à notre classe. Ajoutez les deux méthodes suivantes à la classe Link:

<a href="<dtml-var url>"><dtml-var title></a>

<dtml-var standard_html_header>
<dtml-var content_html>
<dtml-var standard_html_footer>

Vous vous demandez peut-être pourquoi on crée deux méthodes plutôt qu'une seule. La raison est simple: index_html est la méthode qui est appelée par défaut lorsqu'un visualise un objet. Cela signifie que si vous visualisez l'objet lui-même, vous en verrez le contenu, agrémenté des en-têtes et pied de page standard. Par contre, si vous désirez afficher une liste de liens dans une page, vous ne voulez pas l'en-tête, et vous appelez seulement content_html.

Maintenant, si on tente d'ajouter un objet Link dans un Folder (à l'aide du menu déroulant), on se rend compte que le formulaire d'ajout manque les champs titre et url. Nous allons donc modifier le formulaire d'ajout de Link comme ceci:

<HTML>
<HEAD><TITLE>Add Link</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>Add Link</H2>
<form action="Link_add"><table>
<tr><th>Id</th>
    <td><input type=text name=id></td> 
</tr>
<tr><th>Title</th>
    <td><input type=text name=title></td>
</tr>
<tr><th>URL</th>
    <td><input type=text name=url></td>
</tr>
<tr><td></td><td><input type=submit value=" Add "></td></tr>
</table></form>
</body></html>

Ce formulaire sera soumis à la méthode Link_add, comme on peut le voir sans l'attribut action de l'élément form. C'est cette méthode qui se charge de créer le nouvel objet et de l'initialiser avec les valeurs spécifiées dans le formulaire. Il nous faut modifier cet objet pour que les deux nouveaux champs soient sauvegardés:

<HTML>
<HEAD><TITLE>Add Link</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">

<dtml-comment> We add the new object by calling the class in
                a with tag.  Not only does this get the thing
                added, it adds the new thing's attributes to
                the DTML name space, so we can call methods
                to initialize the object.
</dtml-comment>

<dtml-with "Link.createInObjectManager(REQUEST['id'], REQUEST)">

  <dtml-comment>

     You can add code that modifies the new instance here.

     For example, if you have a property sheet that you want to update
     from form values, you can call it here:

       <dtml-call "propertysheets.Basic.manage_editProperties(
                  REQUEST)">

  </dtml-comment>

  <dtml-call "propertysheets.entry_info.manage_editProperties(REQUEST)">

</dtml-with>

<dtml-comment> Now we need to return something.  We do this via
                a redirect so that the URL is correct.

                Unfortunately, the way we do this depends on
                whether we live in a product or in a class.
                If we live in a product, we need to use DestinationURL
                to decide where to go. If we live in a class,
                DestinationURL won't be available, so we use URL2.
</dtml-comment>
<dtml-if DestinationURL>

 <dtml-call "RESPONSE.redirect(
       DestinationURL+'/manage_workspace')">

<dtml-else>

    <dtml-call "RESPONSE.redirect(
           URL2+'/manage_workspace')">
</dtml-if>
</body></html>

Maintenant, si on tente à nouveau d'ajouter un Link dans un Folder à l'aide du menu déroulant, on obtient un formulaire qui contient les champs "Id", "Title" et "URL". Une fois les champs remplis, le formulaire est soumis à la méthode Link_add, et l'objet est alors créé. On peut le voir dans la liste des objets du folder. Il n'a pas d'icône car nous ne lui en avons pas donné. Pour associer un icône à la classe, il suffit d'aller dans la classe Link, sous l'onglet "Basic", et de spécifier "Icon Path" ou d'uploader un fichier image.

Si on clique sur l'objet Link que nous venons d'ajouter, on ne voit pas les onglets "Edit" et "View" auxquels on est habitués. Nous allons ajouter l'onglet "View" à la méthode index_html que nous avons définie précédemment. Dans la classe Link, sous l'onglet "Views", ajoutez une vue ayant pour nom "View" et associée à index_html. De retour à notre objet, on voit immédiatement le nouvel onglet, qui nous affiche le contenu du lien.

Maintenant qu'on peut visualiser notre lien, on voudrait pouvoir le modifier dans un onglet "Edit". On utilisera un formulaire pré-défini, fourni par l'objet "Property Sheet" qu'on a ajouté à notre classe. Toujours sous l'onglet "Views" de la classe, ajoutez une vue ayant pour nom "Edit", et associée à propertysheets/entry_info/manage. Voilà, un onglet "Edit" a été ajouté et est déjà fonctionnel!

Finalement, il ne nous reste qu'à créer plusieurs objets Link dans un Folder (nommé "liens", dans cet exemple), et de les afficher avec une méthode comme celle-ci:

<dtml-var standard_html_header>
<h2><dtml-var document_title></h2>

<dtml-in expr="liens.objectValues(['Link'])">
  <li><dtml-var content_html>
</dtml-in>

<dtml-var standard_html_footer>

Le tag dtml-in permet d'itérérer sur tous les objets de type 'Link' présents dans l'objet liens, qui est notre Folder. À l'intérieur du dtml-in, le contexte n'est plus celui du document, mais celui de l'objet Link, et on peut alors appeler content_html directement.

Pour en savoir plus

http://www.zope.org/Documentation, outil de recherche donne presque toujours de bons résultats

Zope, la compagnie, offre de la formation, en plus d'offrir du support technique comme plusieurs autres compagnies. Mais puisqu'il s'agit d'un projet open source, les listes de diffusion sont très utilisées.