[Zope3-Users] z3c.formext into Plone

Laurent Mignon laurent.mignon at softwareag.com
Fri Jan 30 12:54:58 EST 2009


Today, I've spent a lot of time trying to use z3c.formext into plone.
  	
Here is a summary of the different adaptations to be done to make this 
possible.

z3c.formext
-----------

* in the component.py file,  the statement used into the getConfig 
function of the Component class in not compatibe with Python2.4. (simple 
fix)
   {{{
      return jsonEncode(self._getConfig()) if json else self._getConfig()
   }}}

   must be replaced by

   {{{
       if json:
           return jsonEncode(self._getConfig())
       return self._getConfig()
   }}}

* I also have modified calls to the translate method to provide the 
request as context since, in zope2, locale is set up on the request.
into jsoncompat.py
{{{
def translateObject(o, context):
     if isinstance(o, list):
         for index, value in enumerate(o):
             o[index] = translateObject(value, context)
     elif isinstance(o, tuple):
         o = [translateObject(value, context) for value in o]
     elif isinstance(o, dict):
         for key, value in o.items():
             o[key] = translateObject(value, context)
     elif isinstance(o, unicode):
         o = translate(o, context=context)
     return o

def jsonEncode(o, context):
     o = translateObject(o, context)
     return encode(o)
}}}

* the handler used for the jsmodule zcml directive doesn't correctly 
register the resource for zope2. To make the resource available, I've 
modified the directive to use the same implementation that the one used 
by Five.  I can provide the new implementation into a new module (maybe 
plone.z3cformext or collective.z3cformext or ???)

* the versionedResource zcml directive doen't work for me. I've just 
registered the z3c.formext.loader.js as a simple browser:resource (it's 
probably the same kind of problem that for the jsmodule directive.


z3c.formjs
----------

z3c.formjs is used to provide ajax functionalities used for button 
handling.
These functionalities are provided by an AjaxRequestTraverserPlugin that 
allow to access methods registered as an ajax request handler (ex button 
handler).
These handler are provided as BrowserPage that allow these to be 
publishable.
The AjaxRequestTraverserPlugin has to be rewritten since our z3c.form 
instance are wrapped into a Five BrowserView by plone.z3cform.
The AjaxView must also be rewritten to mix in acquisition so that 
security can be acquired for views.
My changes look like:
{{{

     class AJAXView(Acquisition.Explicit, BrowserPage):
         """A wrapper class around AJAX handler to allow it to be 
publishable.

             Mixes in explicit acquisition so that security can be 
acquired for
         views"""

         def __init__(self, handler, request, view):
             self.context = self.handler = handler
             self.request = request
             self.__parent__ = self.view = view
             #see Zope2.app.startup line 284 needed to build a physicalPath.
             #it's probably not the good way
             self.__name__ = self.handler.func.__name__

         def __call__(self):
             return self.handler(self.view)


     class AJAXRequestTraverserPlugin(object):
         """Allow access to methods registered as an ajax request handler.

         Call acquisition
         """

         zope.interface.implements(ITraverserPlugin)

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

         def publishTraverse(self, request, name):
             #context is a plone.z3cform.layout.FormWrapper
             #a call to switch_on' is required before we can
             #update and use the form_instance
             z2.switch_on(self.context, 
request_layer=self.context.request_layer)
             self.context.form_instance.update()
             handler = 
self.context.form_instance.ajaxRequestHandlers.get(name)
             if handler is None:
                 raise NotFound(self.context, name, request)
             #acquisition
             return AJAXView(handler, self.request,
                     self.context).__of__(self.context)

}}}

The new implementation can be provided into a new module 
(plone.z3cformjs or collective.z3cformjs or ???)
The taverser plugin would be registered as a subscriber for the 
plone.z3cform.interfaces.IFormWrapper or a new interface defined in the 
new module

{{{
   <subscriber
       for="plone.z3cform.interfaces.IFormWrapper
	   zope.publisher.interfaces.browser.IBrowserRequest"
       provides="z3c.traverser.interfaces.ITraverserPlugin"
       factory=".ajax.AJAXRequestTraverserPlugin"
       />

}}}


z3c.traverser
-------------

The factory used to provide the ajax traverser plugin is provided by 
z3c.traverser.browser.PluggableBrowserTraverser.
The traversing process in zope2 is implemented into 
ZPublisher.BaseRequest. The PluggableBrowserTraverser is looked up by 
the traverseName method (line 308).
After the lookup, an explicit call to the Acquisition is performed
{{{
   def traverseName(self, ob, name):
         if name and name[:1] in '@+':
             # Process URI segment parameters.
             ns, nm = nsParse(name)
             if ns:
                 try:
                     ob2 = namespaceLookup(ns, nm, ob, self)
                 except TraversalError:
                     raise KeyError(ob, name)
                 return ob2.__of__(ob)
}}}
Since the PluggableBrowserTraverser provided by  z3c.traverser is not 
Acquisition.Explicit, we need to provide a new one mixin the 
z3c.traverser.browser.PluggableBrowserTraverser and Acquisition.Explicit.
The new traverser can be registered as an adapter for the 
plone.z3cform.interfaces.IFormWrapper or the new interface provided by 
(plone.z3cformjs or collective.z3cformjs or ???)

The new implementation can be provided into a new module 
(plone.z3ctraverser or collective.z3ctraverser or ???) or we can use the 
plone.z3cformjs module

into the plone.z3cformjs configure.zcml, the factory used for ajax would 
be registered with
{{{
  <adapter
       trusted="True"
       for="plone.z3cform.interfaces.IFormWrapper
            zope.publisher.interfaces.browser.IBrowserRequest"
       provides="zope.publisher.interfaces.browser.IBrowserPublisher"
       factory="plone.z3ctraverser.browser.PluggableBrowserTraverser"
       permission="zope.Public"
       name="ajax"
       />
}}}


conclusion
----------

It's possible to use z3c.formext with Plone/zope2. Maybe, some of my 
explanations are wrong and I've missed something... Your comments are 
welcome.
I'm really impressed by the concepts and the functionalities provided by 
the different modules involved into the integration of z3c.formext. 
Thank you to their authors and contributors! The Plone community has 
much to learn from what is done outside of itself... Plone

sorry for my English....


ps: I think that the z3cFormPanel extjs component uses the svn version 
of extjs (probably the next 3.0). If you use extjs 2.2 you have to 
modify some parts of the z3cFormPanel definition.



More information about the Zope3-users mailing list