アダプターはクラスの外側でクラスの振るまいを拡張することを可能にします。 これはクラスごとに数百もの利用出来るメソッドがある複雑なシステムを、よりモジュール化してコードを見やすくします。
欠点としては、アダプターがクラスやソースコードを 調査 しても見つけられないということです。 アダプターを見つけられるようにするためにはきちんと資料に残す必要があります。
アダプターの詳細については zope.component README を参照してください。
アダプターは以下によってマッチングされます。
2種類のアダプターがあります。
アダプターは機能をクラスに対して提供します。そして、インターフェースがクラスのインスタンスから問い合わせられるときにこの機能が有効になります。
以下はカスタマイズした “image provider” を作成する方法の例です。 “image provider” は任意のコンテンツから画像の一覧を取得します。
これは “image provider” インターフェースです。:
from zope.interface import Interface
class IProductImageProvider(Interface):
def getImages(self):
""" プロダクトに付属する画像取得します。
@return: 反復可能な画像オブジェクト
"""
これはコンテンツのクラスです。:
class MyShoppableItemType(folder.ATFolder):
""" Buyable physical good with variants of title and price and multiple images """
implements(IVariantProduct)
meta_type = "VariantProduct"
schema = VariantProductSchema
これはコンテントクラスのアダプターです。
import zope.interface
from getpaid.variantsproduct.interfaces.multiimageproduct import IProductImageProvider
class FolderishProductImageProvider(object):
""" Mix-in class which provide product image management functions.
Assume the content itself is folderish archetype content type and
all contained image objects are product images.
"""
zope.interface.implements(IProductImageProvider)
def __init__(self, context):
# Each adapter takes the object itself as the contruction parameter
# and possibly provided other parameters for the interface adaption
self.context = context
def getImages(self):
""" Return sequence of images.
Perform folder listing and filter image content from it.
"""
images = self.context.listFolderContents(contentFilter={"portal_type" : "Image"})
return images
configure.zcml で MyShoppableItemType というコンテントタイプに対してアダプターを登録します。:
<adapter for=".shop.MyShoppableItemType"
provides=".interfaces.IProductImageProvider"
factory=".images.FolderishProductImageProvider" />
これでアダプターを使用して問い合わせが実行出来るようになります。以下はユニットテストの例です。:
def test_get_images(self):
self.loginAsPortalOwner()
self.portal.invokeFactory("MyShoppableItemType", "product")
product = self.portal.product
image_provider = IProductImageProvider(product)
images = image_provider.getImages()
# Not yet any uploaded images
self.assertEqual(len(images), 0)
以下のインターフェースはアダプターを登録するときに役に立ちます。
<adapter for="" /> の中に複数のインターフェースを記述することが可能です。 その場合は空白か改行で区切る必要があります。
以下は、2つのインターフェースに対してアダプターを登録する例です。
登録されたビュー(コンテクスト、リクエスト)をアダプターで置き換えます。
<adapter for="zope.interface.Interface zope.publisher.interfaces.browser.IBrowserRequest"
provides="gomobile.mobile.interfaces.IMobileTracker"
factory=".bango.BangoTracker" />
2種類の関数があります。
getAdapter/queryAdapter は以下の引数が必要です。
登録を行う例です。:
<!-- Register header animation picking logic - override this for your custom logic -->
<adapter
provides="plone.app.headeranimation.interfaces.IHeaderAnimationPicker"
for="plone.app.headeranimation.behaviors.IHeaderBehavior
Products.CMFCore.interfaces.IContentish
zope.publisher.interfaces.browser.IBrowserRequest
"
factory=".picker.RandomHeaderAnimationPicker" />
対応する問い合わせのコードです。:
from zope.component import getUtility, getAdapter, getMultiAdapter
# header implements IHeaderBehavior
# doc implements Products.CMFCore.interfaces.IContentish
# request implements zope.publisher.interfaces.browser.IBrowserRequest
from Products.CMFCore.interfaces import IContentish
from zope.publisher.interfaces.browser import IBrowserRequest
self.assertTrue(IHeaderBehavior.providedBy(header))
self.assertTrue(IContentish.providedBy(doc))
self.assertTrue(IBrowserRequest.providedBy(self.portal.REQUEST))
# Throws exception if not found
picker = getMultiAdapter((header, doc, self.portal.REQUEST), IHeaderAnimationPicker)
ノート
zope コンポーネントアーキテクチャーがまだ初期化されていないため、 import の間はモジュールの本文レベルのコードではアダプターは取得できません。
IHeaderBehavior アダプターが正しく登録されたかは以下のコードで確認できます。:
from zope.component import getGlobalSiteManager
sm = getGlobalSiteManager()
registrations = [a for a in sm.registeredAdapters() if a.provided == IHeaderBehavior ]
self.assertEqual(len(registrations), 1)
全てのマルチアダプター(コンテクスト、リクエスト)を取得します。
例:
from zope.component import getAdapters
adapters = getAdapters((context, request), provided=Interface)
警告
zope ビューのように局所的に登録されたアダプターは取得できません。