Magazine Internet

Intro à Plone 3 : partie 1

Publié le 06 février 2009 par Mikebrant

Première partie d'un intro à Plone 3 .

Alors , dans ce tuto on va voir comment  créer une appli Plone 3.

Je ne sais pas combien il y aura de parties, mais je vais essayer de publier et terminer cette intro le plus vite possible ( en une semaine ce serait pas mal).
Et donc du coup l'intro à Zope 3 est mise en berne .

Le site que l'on va faire ? jesuisunconnard.com (bah oui  à défaut d'etre connu, faut bien qu'il serve à quelquechose) .

Jesuisunconnard sera décomposé en 2 packages :
jesuisunconnard.politique
jesuisunconnard.metier ( j'ai pas trouvé mieux comme nom)
Alors oui, on ne va pas voir comment créer un thème vite-fait bien fait, mais je ferais surement un petit article après ce tuto d'intro.

Je ne vais pas non plus traiter les tests, très importants, mais ca prendrait bien trop de place dans cette intro à Plone 3, mais qui sait, surement dans un prochain (mais très lointain) article ?

Et avant de commencer :  je n'arrive pas à faire d'accents circonflexes sur opéra 10.

C'est parti.

Installation de Plone via Buildout

 $ paster create -t plone3_buildout monSite


Répondez aux questions (mettez et laissez à on le debug_mode et verbose_security pour le moment ).

Et on lance le buildout :

$ cd monSite & python2.4 bootstrap.py & ./bin/buildout


C'est terminé.

 Le thème

Comme dit plus haut, on ne va pas faire de thème personnalisé : j'en ai trouvé un très joli, et comme je suis une quiche en design ca tombe bien !
C'est keepitsimple. Et il est disponible chez pypi.
On rajoute donc dans buildout.cfg, dans la section [eggs] ceci :

[buildout]
parts =
  plone
  zope2
[...]
eggs =
  elementtree
  plonetheme.keepitsimple


puis dans zcml de [instance] ceci :

[instance]
recipe = plone.recipe.zope2instance
zope2-location = ${zope2:location}
[...]
zcml =
  plonetheme.keepitsimple


Qui va créer un fichier dans parts/instance/etc/site-package-includes afin que Zope trouve notre joli thème.

Création de notre politique

Les 2 premières parties étaient assez triviales mais bon.

On  va donc créer notre package plone 3 :

$ cd src & paster -create -t plone jesuisunconnard.politique


Namespace du paquet : jesuisunconnard
Le nom du paquet : politique
Zope2Product : True

 Et comme vous vous en doutez, il faut rajouter ceci dans notre buildout.cfg :

[buildout]
parts =
  plone
  zope2
[...]
eggs =
  elementtree
  plonetheme.keepitsimple
  jesuisunconnard.politique
develop =
  src/jesuisunconnard.politique
[...]
[instance]
recipe = plone.recipe.zope2instance
zope2-location = ${zope2:location}
[...]
zcml =
  plonetheme.keepitsimple
  jesuisunconnard.politique


Ce package va nous permettre de configurer globalement notre site Plone, c'est à dire que, grace à lui, on va pouvoir :
- rajouter un onglet
- lister uniquement nos types dans "ajout d'élément"
- modifier le nom du site
- ajouter par dépendances, d'autres packages
 [...]

Maintenant que notre politique est créée, on va éditer le fichier src/jesuisunconnard.politique/jesuisunconnard/politique/configure.zcml :

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:five="http://namespaces.zope.org/five"
  xmlns:genericsetup="http://namespaces.zope.org/genericsetup"

  i18n_domain="jesuisunconnard.politique">
 <five:registerPackage package="." />
   
  <genericsetup:registerProfile
  name="default"
  directory="profiles/default"
   />
</configure>


La balise five sert à enregistrer notre paquet en tant que Produit Zope2 .

la balise genericsetup, quant à elle, permet d'enregistrer un profil pour notre politique.
Mais c'est quoi un profil ? on va prendre une photo ?
Non ;  un profil va contenir certaines configurations pour notre site ( le nom, la description, les worflows, les roles, etc...)

Le profil s'appellera donc default.
Et directory est l'emplacement de ce profil.


Comme vous vous en doutez il faut donc créer les dossiers profiles et default :

$ cd jesuisunconnard.politique/jesuisunconnard/politique/ & mkdir -p profiles/default


Donc, comme dit juste avant, notre profil va contenir certaines configurations, qui se feront uniquement via fichiers XML.

 Configuration de notre profil

On va commencer par modifier le nom du site ainsi que sa description .
On crée donc le fichier src/jesuisunconnard.politique/jesuisunconnard/politique/profiles/default/properties.xml :

<?xml version="1.0" ?>
<site>
  <property name="title">Je suis un connard</property>
  <property name="description">Parce qu'il faut savoir rire de tout</property>
</site>


Et c'est tout.
la proriété title représente le titre du site et description la description [ je précise au cas où il y ait des ames égarées ].

Maintenant, on veut rajouter 3 onglets : "A propos", "Raconte ton histoire"  et "Aleatoire".
Ces 3 onglets vont, non pas rediriger vers un dossier (sinon on aurait pas besoin de les rajouter à la "main"), mais rediriger sur des pages que l'on créera dans une prochaine partie : 
on va donc préparer le terrain.

On va devoir créer le fichier src/jesuisunconnard.politique/jesuisunconnard/politique/profiles/default/actions.xml  et y mettre :

<?xml version="1.0" ?>
<object name="portal_actions" meta_type="Plone Actions Tool" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  
   <object name="portal_tabs" meta_type="CMF Action Category">
  
   <object name="aPropos" meta_type="CMF Action" i18n:domain="plone">
      <property name="title" i18n:translate="ongletApropos">A propos</property>
      <property name="description" i18n:translate=""></property>
      <property name="url_expr"></property>
      <property name="icon_expr"></property>
      <property name="available_expr"></property>
      <property name="permissions">
      <element value="View"/>
      </property>
      <property name="visible">True</property>
      </object>
  
   <object name="ajout" meta_type="CMF Action" i18n:domain="plone">
      <property name="title" i18n:translate="ongletRaconte">Raconte ton histoire</property>
      <property name="description" i18n:translate=""></property>
      <property name="url_expr"></property>
      <property name="icon_expr"></property>
      <property name="available_expr"></property>
      <property name="permissions">
      <element value="View"/>
      </property>
      <property name="visible">True</property>
      </object>
     
      <object name="aleatoire" meta_type="CMF Action" i18n:domain="plone">
      <property name="title" i18n:translate="ongletAleatoire">Aleatoire</property>
      <property name="description" i18n:translate=""></property>
      <property name="url_expr"></property>
      <property name="icon_expr"></property>
      <property name="available_expr"></property>
      <property name="permissions">
      <element value="View"/>
      </property>
      <property name="visible">True</property>
      </object>
  
   </object>
</object>


La 2° ligne permet de sélectionner notre objet, en l'occurence portal_actions ( d'où le nom du fichier).
Et oui, nos onglets vont être enregistrés dans portal_actions et plus particulièrement dans son objet portal_tabs ( tabs = onglets , je précise on ne sait jamais) : d'où la 4° ligne.

Et après c'est assez trivial poursuit :
à l'intérieur de portal_tabs, on définit 3 objets ( aPropos, ajout, aleatoire) étant de type CMF Action : et hop ce sont devenus des onglets.

title : le titre de l'onglet
description: la description de l'onglet
url_expr: l'url où pointe l'onglet : vide pour le moment
icon_expr: l'icone de l'onglet : on n'en veut pas
available_expr: condition éventuelle pour qu'apparaisse l'onglet
permissions: la permission pour l'onglet, ici, tout le monde peut le voir
visible: si l'onglet est caché (False) ou pas (True)

C'est bientot la fin

Il nous reste une dernière chose à faire, avant de terminer cette première partie.

Comme dit plus haut, je veux uniquement lister dans "ajout d'un élément" les objets que l'on créera dans une prochaine partie , c'est  à dire que "Document", "Evenement" et compagnie doivent disparaitre.
Et Comment on fait ça ?

On crée le fichier src/jesuisunconnard.politique/jesuisunconnard/politique/profiles/default/import_steps.xml, contenant ceci :

<?xml version="1.0" ?>
<import-steps>
   <import-step id="jesuisunconnard-etapes" version="06022009-01"
   handler="jesuisunconnard.politique.setuphandlers.importVarious" title="autreEtapes">
   </import-step>
</import-steps>


Mais c'est quoi ce fichier import_steps.xml ? tu veux qu'on fasse du step ?
Queneni !
Enfait quand on va installer notre paquet, genericsetup va importer notre profil default afin de configurer notre site .
Et cette configuration se fait étape par étape : normal.
Mais si l'on veut rajouter une étape comme c'est le cas ( lister seulement nos objets dans "ajout d'un élément"), on doit créer ce fichier.

on crée une nouvelle étape via la balise <import-step>, en oubliant pas de lui mettre un id.
Le handler sera ce que notre nouvelle étape va appeler ; ici, c'est la fonction importVarious() qui le sera.

Bon bah il ne nous reste plus qu'à la créer .
fichier src/jesuisunconnard.politique/jesuisunconnard/politique/setuphandlers.py :

#-*- coding:Utf-8 -*-
from Products.CMFCore.utils import getToolByName
def desactiveTout(portal):
   portal_types = getToolByName(portal, 'portal_types')
  
   getattr(portal_types, 'Document').global_allow = False
   getattr(portal_types, 'Event').global_allow = False
   getattr(portal_types, 'Favorite').global_allow = False
   getattr(portal_types, 'File').global_allow = False
   getattr(portal_types, 'Folder').global_allow = False
   getattr(portal_types, 'Image').global_allow = False
   getattr(portal_types, 'Link').global_allow = False
   getattr(portal_types, 'Topic').global_allow = False
   getattr(portal_types, 'News Item').global_allow = False
def importVarious(context):
   portal = context.getSite()
   desactiveTout(portal)


importVarious ne fait qu'appeler desactiveTout().

On récupère l'objet portal_types (qui est un singleton) via getToolByName().
Puis, on récupère chaque objet représentant un type indésirable via getattr(portal_types, monType) ,  que l'on désactive via l' attribut global_allow.

Et voilà.

Et merde, c'est pas la fin

Ceci est le dernier paragraphe , mais le vrai.

Dans le paragraphe précédent, j'ai écris :
Enfait quand on va installer notre paquet, genericsetup va importer notre profil default afin de configurer notre site .
Vous avez du vous dire : "mais comment il sait qu'il doit importer default et pas un autre ou rien du tout ?

Et bien ca se passe du côté de chez swan du dossier src/jesuisunconnard.politique/jesuisunconnard/politique/Extensions, qu'il faut créer ( il faut en faire un package donc n'omellettez pas le fichier __init__.py ) .

Dedans, créez le fichier Install.py (avec le I majuscule) :

import transaction
from Products.CMFCore.utils import getToolByName
#PRODUCT_DEPENDENCIES = ('jesuisunconnard.metier',)
PRODUCT_DEPENDENCIES = ()
  
EXTENSION_PROFILES = ('jesuisunconnard.politique:default',)
def install(self, reinstall=False):
  
  
   portal_quickinstaller = getToolByName(self, 'portal_quickinstaller')
   portal_setup = getToolByName(self, 'portal_setup')
   for product in PRODUCT_DEPENDENCIES:
   if reinstall and portal_quickinstaller.isProductInstalled(product):
   portal_quickinstaller.reinstallProducts([product])
   transaction.savepoint()
   elif not portal_quickinstaller.isProductInstalled(product):
   portal_quickinstaller.installProduct(product)
   transaction.savepoint()
  
   for extension_id in EXTENSION_PROFILES:
   portal_setup.runAllImportStepsFromProfile('profile-%s' % extension_id, purge_old=False)
   product_name = extension_id.split(':')[0]
   portal_quickinstaller.notifyInstalled(product_name)
   transaction.savepoint()


Ce code n'est pas de moi, je l'ai trouvé dans pas mal de codes et sur des sites, donc je n'ai pas vraiment de sources à donner.
Je ne vais pas l'expliquer, puisqu'on s'en fou du fonctionnement.
Tout ce qui nous intéresse c'est de savoir, que install() va permettre d'installer d'autres paquets :
il nous suffira d'ajouter le nom du paquet dans PRODUCT_DEPENDENCIES (on rajoutera par la suite jesuisunconnard.metier)
Et il nous permet aussi d'importer nos profils via EXTENSION_PROFILES  (monPaquet:nomProfil) .
C'est comme ca que genericsetup sait qu'il doit importer notre profil default.

Et c'est vraiment la fin de cette première partie ( n'oubliez pas de faire un buildout), si vous voulez le code c'est ici.

J'en profite au passage, pour dire que je pourrais peut-être éventuellement chercher un partenariat  le jeudi & vendredi.
Je suis actuellement à Montréal, en 3° année à l'école SUPINFO.
Je ne vais pas écrire mon CV ici (ce n'est ni le moment ni l'endroit), mais si vous êtes intéressé contactez-moi ([email protected] )
[ qui ne tente rien n'a rien ]

(et dire que je dois finir cette intro en une semaine...)


Retour à La Une de Logo Paperblog

LES COMMENTAIRES (1)

Par Amo
posté le 31 décembre à 19:48
Signaler un abus

J'apprécie l'effort pour faire un article sur la réalisation d'une appli Plone "from scratch" d'un coté, donc bravo. D'un autre côté, dieu a inventé la ZMI et la CMF ...

A propos de l’auteur


Mikebrant 9 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte

Dossier Paperblog