archetypes.schemaextender, hurray!ΒΆ

Tags: plone

collective.realestatebroker is a very, very locale-dependent beast. Real estate object attributes that are relevant in the Netherlands can be unexplainable once you cross the border. So for our product we needed a way to extend basic content types for the Dutch market. I mean, spamming the core product with Dutch-specific fields is bad taste. Enter archetypes.schemaextender. That makes it delightfully easy to extend existing contenttypes (based on the recent ISchema goodie from archetypes).

Svn version can be gotten from , which I'd recommend over the egg for now as that had a bug that I tripped over (svn version didn't have the bug). To illustrate how it works, here's part of a unittest.

Step 1. archetypes.schemaextender's ``overrides.zcml`` isn't applied, so the default ISchema handling is still in place. To fix this (if you use buildout) include an entry ``archetypes.schemaextender-overrides`` in your zcml section. For this unittest we'll do the work by hand:

    >>> from archetypes.schemaextender.extender import instanceSchemaFactory
    >>> component.provideAdapter(instanceSchemaFactory)

Step 2. Create field classes for the fields you want to adapt. Say, a StringField. Make sure you inherit from ExtensionField, first:

    >>> from archetypes.schemaextender.field import ExtensionField
    >>> class ExtendedStringField(ExtensionField, atapi.StringField):
    ...     pass

Step 3. Create a schema extender. An extender is a named adapter behind the scenes, so you have to say which interface you adapt. In our case, IResidential and/or ICommercial:

    >>> class MyExtender(object):
    ...     component.adapts(IResidential)
    ...     interface.implements(IOrderableSchemaExtender)
    ...     _fields = [ExtendedStringField(
    ...         'extra_field',
    ...         storage=atapi.AnnotationStorage(),
    ...         widget = atapi.StringWidget(label = u'Extra field')
    ...         ),
    ...                ]
    ...     def __init__(self, context):
    ...         self.context = context
    ...     def getFields(self):
    ...         return self._fields
    ...     def getOrder(self, original):
    ...         # Possibility to move fields.
    ...         return original

Step 4. Wire up your extender with some zcml by defining an adapter with your extender as the "factory" and give it some name (so that it is a named adapter). We'll again enable it manually here (it is a unit test):

    >>> component.provideAdapter(MyExtender,
    ...                          name=u"dutch.test")
    >>> res = Residential('res')
    >>> schema = res.Schema()
    >>> 'price' in schema
    >>> 'extra_field' in schema

I don't even want to think about the amount of fun we can have with this! Lots of more or less painful customizations to pre-3.0 sites can be re-done in a much more elegant way. Hurray for zope3 that makes it all possible. And thanks to Florian and Martin for doing most of the coding on archetypes.schemaextender!

(Old imported comments)
"Live from Cofoco (Copenhagen Food Consulting)" by on 2007-11-02 23:32:10
I still have to understand why this is better than monkey patching.
"Test comment" by on 2007-11-02 20:19:13
I've managed to log into my own site with openid :-) Problem was that I used a https: openid and plone barfs on that. (Now fixed in svn, btw).

Reinout logo

About me

My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):