I found myself having the same need as Vincent so I looked a little bit at z3c.form. The end result is very much a mixed blessing. As Vincent discovered it is not very hard to get z3c.form 2.1 to manage a list of items. In my example I have this interface which is repeated:

class IInformationLink(Interface):
    """A link to more information related to a risk."""

    url = schema.URI(
            title = _(u"URL"),
            required = True)
    description = schema.TextLine(
            title = _(u"Description"),
            required = False)


this has to be an Interface: if you use a zope.schema.Schema things break badly. You can then use this in your main interface like this:

class IRisk(form.Schema, IRichDescription, IBasic):
    """A possible risk that can be present in an organisation.
    """
    links = schema.List(
            title = _(u"Information links"),
            description = _(u"A list of links to webpages which provide"
                            u" more information on this risk."),
            required = False,
            value_type = schema.Object(
                title = _(u"Link"),
                schema = IInformationLink))

This works, but the resulting markup from z3c.form is quite ugly: a big mess of divs, nested divs, label elements inside div.label elements, etc. The UI it presents is also very confusing: https://photos-1.getdropbox.com/i/o/JmLD1SNVPJbwy12pgo-FYOWLsG-9L9lKNdBCm6yIfok is an example. Notice how it is very unclear that the Add/Remove buttons at the button belong to the 'Links' field. It gets even worse if you try to insert some data: https://photos-1.getdropbox.com/i/o/ZrPquRJE5oEOZn1DhCdS6ZTDArNqKhAZ15UGtF-3sqA . Part of this is a flaw in zope.schema which does not except URLs without a http: prefix (which will confuse users). The 'The system could not process the given value' is a mysterious one and reveals an essential bit that is not documented: z3c.form requires a IObjectFactory factory for the IInformationLink interface. This is an multi-adapter (with 4 facets, almost none of which you will ever need) and requires the name of the adapter to be set to the interface (feels like ZCA abuse to me):

from zope.interface import Interface
from zope.interface import implements
from zope.component import adapts
from z3c.form.interfaces import IObjectFactory

class InformationLinkFactory(object):
    adapts(Interface, Interface, Interface, Interface)
    implements(IObjectFactory)

    def __init__(self, context, request, form, widget):
        pass

    def __call__(self, value):
        return dict(value)

which you can register in zcml like so:

    <adapter factory=".risk.InformationLinkFactory"
      name="euphorie.content.risk.IInformationLink" />

and then it still does not work since it requires that your object factory returns something that zope.schema.Object can handle. In other words: it is not possible to return dictionaries.

Next attempt: use a simple object that can implement IInformationLink:

class InformationLink(object):
    implements(IInformationLink)

    def __init__(self, value):
        self.url=value["url"]
        self.description=value["description"]


class InformationLinkFactory(object):
    adapts(Interface, Interface, Interface, Interface)
    implements(IObjectFactory)

    def __init__(self, context, request, form, widget):
        pass

    def __call__(self, value):
        return InformationLink(value)


and that finally works. The lessons I have learned from this are:

- z3c.form produces very awful HTML
- z3c.form produces very confusing user interfaces
- z3c.form documentation is indeed incomplete (no mention of
  ObjectFactory)
- z3c.form you can do cool stuff with it, although I am not convinced
  it is much better than hand-coding the form

And the reason I cc'ed the framework team: I strongly feel that until the generated markup and user interfaces from z3c.form are improved to meet Plone standards Plone itself should start using it.

Wichert.

_______________________________________________
Framework-Team mailing list
Framework-Team@lists.plone.org
http://lists.plone.org/mailman/listinfo/framework-team

Reply via email to