Modifier dynamiquement les nouveaux types de contenu de Plone 2.1
Par davconvent le 18/04/2005 12:22
Catégories : Plone
Cet article est basé sur la technique du 'Monkey Patch', décrite dans l'excellent article de Casey Duncan
Merci à Danny Bloemendaal pour ses éclaircissements.
- Cas d'utilisation
- Je dois ajouter ou modifier un champ (un 'field') au schema de certains types de contenu fournis avec ATContentTypes. Ce nouveau champ doit s'afficher dans la page d'édition des metadonnées. De plus, je veux que certains champs de metadonnées disparaîssent de cette même page.
- Contraintes
- Je ne veux pas toucher au code de ATContentTypes, car ça risque de rendre sa mise à jour fastidieuse. Je pourrais développer un nouveau type de contenu qui sousclasse celui que je veux modifier, c'est tout à fait encourragé, mais je devrais alors m'assurer de la migration de l'ancien type vers le nouveau, comme le fait ATContentTypes lui-même pour remplacer les anciens types de contenu livrés avec le CMF. Ce genre de migration peut être fastidieuse à mettre en place et à maintenir, je préfère m'en passer.
- Solution
- Je vais écrire un 'monkey patch', un (tout petit) produit qui va, au démarrage de Zope, modifier dynamiquement le schema des types de contenu que je veux modifier.
- Remarques
-
- Les changements sont appliqués au produit patché pour l'instance Zope: tous les sites Plone qui se partagent une même instance Zope sont affectés.
- J'ai souvent lu ou entendu qu'il vaut mieux ne pas utiliser de 'monkey patch' pour changer une fonctionnalité ou pour corriger un bug. Je partage cet avis, le patch n'est utile que pour appliquer de légères modifications à un produit afin de l'adapter à des besoins précis. Gare aux effets de bord.
- Certains produits permettent d'être rafraîchis pour prendre en compte les modifications apportées à leur code. N'oubliez pas de rafraîchir le patch si vous devez rafraîchir un produit que vous avez patché. De préférence, redémarrez Zope si des modifications ont été apportées soit au produit patché soit au patch.
Le patch
Voici la structure que doit avoir le produit sur le système de fichiers:$INSTANCE_HOME/Products/MyPatches/
$INSTANCE_HOME/Products/MyPatches/__init__.py
$INSTANCE_HOME/Products/MyPatches/ATCTPatch.py
ATCTPatch.py:
from Products.Archetypes.public import StringField
from Products.Archetypes.ClassGen import generateMethods
FIELDS_TO_HIDE = ('language', 'subject', 'contributors', 'creators', 'rights')
INVISIBILITY = {'view':'invisible', 'edit':'invisible'}
def hideFields(schema, fieldnames=FIELDS_TO_HIDE):
for field in fieldnames:
schema[field].widget.visible=INVISIBILITY
myOwnMetadataField = StringField('toto',
schemata='metadata',
isMetadata=True,
)
from Products.ATContentTypes.content.event import ATEvent, ATEventSchema
from Products.ATContentTypes.content.document import ATDocument, ATDocumentSchema
from Products.ATContentTypes.content.file import ATFile, ATFileSchema
from Products.ATContentTypes.content.image import ATImage, ATImageSchema
from Products.ATContentTypes.content.link import ATLink, ATLinkSchema
from Products.ATContentTypes.content.newsitem import ATNewsItem, ATNewsItemSchema
schemata = (ATEventSchema,
ATDocumentSchema,
ATFileSchema,
ATImageSchema,
ATLinkSchema,
ATNewsItemSchema,
)
for schema in schemata:
schema.addField(myOwnMetadataField)
hideFields(schema)
contents = (ATEvent,
ATDocument,
ATFile,
ATImage,
ATLink,
ATNewsItem,
)
for content in contents:
generateMethods(content, content.schema.fields())
Explication : Après avoir importé les classes et fonctions d'Archetypes dont j'ai besoin, je défini la liste des champs que je veux voir disparaître de la page d'édition des métadonnées, le dictionnaire python qui servira à les rendre invisibles, et une petite fonction que j'appellerai à cet effet (lignes 1 à 8). Je défini le champ métadonnée qui sera rajouté aux types de contenu (lignes 11 à 14). J'importe les types de contenu à modifier, et leur schema respectif (lignes 16 à 21). J'ajoute mon champ aux schemas importés et modifie le widget des champs qui doivent disparaître (lignes 18 à 32). Je regénère les méthodes relatives aux champs (accessors, mutators, edit_accessors) pour chaque type dont le shema a été modifié (lignes 33 à 42).
__init__.py:
# Comment line to disable patch
Import ATCTPatch
Explication : J'aurais pu écrire le patch directement dans le fichier __init__.py, mais je trouve plus commode de l'importer, ça me permet d'annuler son effet en redémarrant Zope après avoir commenté la ligne. De plus si à l'avenir je veux rajouter de nouveaux patchs à mon Zope, je pourrai les intégrer facilement sans devoir éditer un seul module fourre-tout.








Pour compléter ce beau tutoriel, je recommande de faire tourner les tests unitaires fournis avec ATContentTypes, pour vérifier que l'on a pas fait de casse avec le patch.