blog

Archetypes: Schema extending an object only inside a specific folder

| categories: zca, archetypes, zope, adapters, plone, schemaextender

It's possible to register schema-extenders (and modifiers) for only certain subsections (folders) of your Plone site. It's relatively simple, and all you need is to do is add a local site-manager to the folder and then register the adapters against it.

/img/plone.png

This blogpost assumes that you are already familiar with Plone's Archetypes schema extensions and provides more advanced usage examples. If you've got no idea what I'm talking about but want to learn more, checkout the pypi page here first.

Introduction

By using simple adapters (known as schema-extenders), it's possible to extend or modify the schemas of your Archetypes objects without actually getting your hands dirty. One advantage of using adapters to modify an Archetype's schema is that it allows multiple Plone add-on products to modify the schema in an extendible and non-invasive way, without using any subclassing. You don't need to touch the original code at all.

The Zope Component Architecture (ZCA) provides the functionality that makes all this happen. Adapters are registered (via ZCML or python) and are then kept track of by a ZCA component known as a site manager.

A normal Plone site provides a global site manager located at the root of the site. This site manager keeps track of all the registered adapters in the site. When you schema-extend an object, it's the site manager that is queried for the possible adapters (schema-extenders and schema-modifiers) that apply to this object.

You don't however have to have only one site-manager. You can easily create a local site-manager in a folder elsewhere in your site, and this allows you to have a folder specific registry of ZCA adapters and utilities. Concerning schema-extension, this means that you have schema-extenders that apply only in certain subsections (folders) of your site.

The nitty gritty

So, how do we do this? First we need to create the schemaextender that we will be applying only on a local folder. The following code describes this extender object. To keep it simple, it adds one extra field to the existing object's schema, namely the ExtensionStringField.

import zope.interface
from Products.Archetypes import atapi
from archetypes.schemaextender.field import ExtensionField
from archetypes.schemaextender.interfaces import ISchemaExtenderclass

ExtensionStringField(ExtensionField, atapi.StringField):

    class LocalExtender(object):
        zope.interface.implements(ISchemaExtender)
        _fields = [
            ExtensionStringField('MyLocalString',
                widget=atapi.StringWidget()),
            ]

        def __init__(self, context):
            self.context = context

        def getFields(self):
            return self._fields

Lets assume that we have now have a folder in which we want objects of a certain type to be extended by our extender above. To be able to do this, we first need to create a local site-manager inside this folder.

from five.localsitemanager import make_objectmanager_site

if not ISite.providedBy(folder):
    make_objectmanager_site(folder)

So, as mentioned, the code above will create a local site-manager inside your folder. How and when you call the above code is up to you. You can for example put it in an External Method and call it once, or you could create a subtype and have a reproducible way of creating local site-managers through the Plone UI.

Next, we have to register our schema-extender for a specific object this specific site-manager. Which kind of object it is, is determined by it's interface(s). So, assuming we wanted to extend all the Documents in this folder, we would register our extender for the IATDocument interface.

from Products.ATContentTypes.interface import IATDocument
sm = folder.getSiteManager()
sm.registerAdapter(
    LocalExtender,
    (IATDocument,),
    ISchemaExtender,
    name=u'LocallyExtendedObject'
)
  • The first variable passed to registerAdapter, is our LocalExtender class, also known as the adapter factory. The factory is used to compute the adapter.
  • The second variable is a tuple containing a sequence of interfaces that the object must implement to make it a candidate for adaptation.
  • The third variable is the interface that the factory (schema-extender) must implement in order to make it a valid adpater in this context.
  • Lastly, the name is useful since it can be used to override adapters that applied to subtypes of an object.

For more info on local site-managers and registering ZCA components for them, see five.localsitemanager.localsitemaqnager.txt.