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 https://svn.plone.org/svn/archetypes/archetypes.schemaextender/ , 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 True >>> 'extra_field' in schema True
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!
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
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):
Reinout