Adapters Zope 3
Par gawel le 13/03/2007 22:18
Catégories : Zope3
Les adapters
Les adapters Zope 3 rajoutent des fonctionnalités à un objet. Exemple, nous avons deux classes:
class Gruik(object):
attribut21 = u'je suis issue de la classe Gruik'
class Gruik2(object):
def titre(self):
return u'je suis issue de la classe Gruik2'
On aimerais pouvoir appeler un attribut 'titre' sur ces deux objets de façon transparente. Pour cela, il nous faut une interface:
import zope.interface
class IGruikTitre(zope.interface.Interface):
titre = zope.interface.Attribute(u'un titre')
Puis, 2 adapters qui implémentent notre interface et adaptent nos classes:
import zope.component
class GruikTitre(object):
zope.interface.implements(IGruikTitre)
zope.component.adapts(Gruik)
def __init__(self,context):
self.context = context
def _titre(self):
return self.context.attribut21
titre = property(_titre,None)
class GruikTitre2(object):
zope.interface.implements(IGruikTitre)
zope.component.adapts(Gruik2)
def __init__(self,context):
self.context = context
def _titre(self):
return self.context.titre()
titre = property(_titre,None)
On enregistre ses deux adapters (normalement via des zcml):
zope.component.provideAdapter(GruikTitre) zope.component.provideAdapter(GruikTitre2)
On est ensuite capable d'appeler l'attribut titre sur nos deux classes en passant par leur adapter:
>>> gruik = Gruik() >>> IGruikTitre(gruik).titre u'je suis issue de la classe Gruik' >>> gruik2 = Gruik2() >>> IGruikTitre(gruik2).titre u'je suis issue de la classe Gruik2'
On appelle donc l'interface sans ce soucier de quel adapter est appelé.
Les multi-adapters
Il est possible de définir des adapters pour plusieurs objets:
class Animal(object):
description = u'un animal'
class Nourriture(object):
description = u'de la nourriture'
class IRepas(zope.interface.Interface):
pass
class Repas(object):
zope.interface.implements(IRepas)
zope.component.adapts(Animal,Nourriture)
def __init__(self,animal,nourriture):
self.animal = animal
self.nourriture = nourriture
def ilmangequoi(self):
return u'au repas, %s mange %s' % (self.animal.description,
self.nourriture.description)
zope.component.provideAdapter(Repas)
Ce qui nous permet en suite d'adapter l'animal à sa nourriture via le repas:
>>> animal = Animal() >>> nourriture = Nourriture() >>> repas = zope.component.queryMultiAdapter((animal,nourriture)) >>> repas.ilmangequoi() u'au repas, un animal mange de la nourriture'
Les adapters nommés
Il est possible de nommer des adapters. En surclassant notre précédent Repas, nous pouvons en créer de nouveau qui porterons un nom:
class PetitDej(Repas):
def ilmangequoi(self):
return u"au petit des, %s mange %s abondamment pour prendre des forces !" % (self.animal.description,
self.nourriture.description)
class Diner(Repas):
def ilmangequoi(self):
return u"au diner, %s fais la diète pour ne pas être ballonné la nuit" % self.animal.description
zope.component.provideAdapter(PetitDej,name='ptitdej')
zope.component.provideAdapter(Diner,name='diner')
Puis les utiliser explicitement:
>>> animal = Animal() >>> nourriture = Nourriture() >>> repas = zope.component.queryMultiAdapter((animal,nourriture),name='ptitdej') >>> repas.ilmangequoi() u'au petit des, un animal mange de la nourriture abondamment pour prendre des forces !' >>> repas = zope.component.queryMultiAdapter((animal,nourriture),name='diner') >>> repas.ilmangequoi() u'au diner, un animal fais la di\xe8te pour ne pas \xeatre ballonn\xe9 la nuit'
Conclusion
Toute l'architecture de Zope 3 est basé sur les interfaces et les adapters (je vous conseil la lecture des README de zope.interface et zope.component). La vue d'un objet est, par exemple, un multi-adapter nommé qui adapte un context et une request et dont le nom est, la plupart du temps, le .html que l'on appelle.
Il est possible, grâce à ce système de redéfinir tout ou partie du comportement de votre application. La façon dont sont générés l'id de vos objets (voir INameChooser) ou la façon dont il sont traversé (voir ITraver)par exemple.







