[Checkins] SVN: Products.CMFDefault/trunk/Products/CMFDefault/ - moved FallbackAddView to formlib.form

Yvo Schubbe y.2009 at wcm-solutions.de
Wed Aug 26 15:51:01 EDT 2009


Log message for revision 103239:
  - moved FallbackAddView to formlib.form
  - added functional tests that show how to use ContentAddFormBase and FallbackAddView

Changed:
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/folder.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
  A   Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.txt
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/tests.py

-=-
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2009-08-26 19:39:25 UTC (rev 103238)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2009-08-26 19:51:00 UTC (rev 103239)
@@ -20,15 +20,6 @@
       permission="cmf.ListFolderContents"
       />
 
-  <adapter factory=".folder.FallbackAddView" />
-
-  <class class=".folder.FallbackAddView">
-    <require
-        permission="cmf.AddPortalContent"
-        interface="zope.formlib.interfaces.IPageForm"
-        />
-  </class>
-
   <adapter factory=".metadata.MinimalMetadataSchemaAdapter"/>
 
   <browser:page

Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/folder.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/folder.py	2009-08-26 19:39:25 UTC (rev 103238)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/folder.py	2009-08-26 19:51:00 UTC (rev 103239)
@@ -17,8 +17,6 @@
 
 from DocumentTemplate import sequence  # for sort()
 from Products.PythonScripts.standard import thousands_commas
-from zope.formlib.form import FormFields
-from zope.schema import ASCIILine
 from ZTUtils import Batch
 from ZTUtils import LazyFilter
 from ZTUtils import make_query
@@ -29,8 +27,6 @@
 from Products.CMFDefault.browser.utils import ViewBase
 from Products.CMFDefault.exceptions import CopyError
 from Products.CMFDefault.exceptions import zExceptions_Unauthorized
-from Products.CMFDefault.formlib.form import ContentAddFormBase
-from Products.CMFDefault.formlib.widgets import IDInputWidget
 from Products.CMFDefault.permissions import AddPortalContent
 from Products.CMFDefault.permissions import DeleteObjects
 from Products.CMFDefault.permissions import ListFolderContents
@@ -41,30 +37,6 @@
 from Products.CMFDefault.utils import translate
 
 
-class FallbackAddView(ContentAddFormBase):
-
-    """Add view for IDynamicType content.
-    """
-
-    form_fields = FormFields(ASCIILine(__name__='id', title=_(u'ID')))
-    form_fields['id'].custom_widget = IDInputWidget
-
-    def createAndAdd(self, data):
-        if not self.ti.product:
-            return super(FallbackAddView, self).createAndAdd(data)
-
-        # for portal types with oldstyle factories
-        container = self.context
-        name = container.invokeFactory(self.ti.getId(), data['id'])
-        obj = container._getOb(name)
-
-        obj_type = translate(obj.Type(), container)
-        self.status = _(u'${obj_type} added.', mapping={'obj_type': obj_type})
-        self._finished_add = True
-        self._added_obj = obj
-        return obj
-
-
 # XXX: This should be refactored using formlib. Please don't import from this
 #      module, things might be changed without further notice.
 

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml	2009-08-26 19:39:25 UTC (rev 103238)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml	2009-08-26 19:51:00 UTC (rev 103239)
@@ -11,4 +11,13 @@
       permission="zope.Public"
       />
 
+  <adapter factory=".form.FallbackAddView" />
+
+  <class class=".form.FallbackAddView">
+    <require
+        permission="cmf.AddPortalContent"
+        interface="zope.formlib.interfaces.IPageForm"
+        />
+  </class>
+
 </configure>

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2009-08-26 19:39:25 UTC (rev 103238)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2009-08-26 19:51:00 UTC (rev 103239)
@@ -30,12 +30,14 @@
 from zope.formlib import form
 from zope.formlib.interfaces import IPageForm
 from zope.interface import implementsOnly
+from zope.schema import ASCIILine
 from ZTUtils import make_query
 
 from Products.CMFCore.interfaces import IFolderish
 from Products.CMFCore.interfaces import ITypeInformation
 from Products.CMFDefault.browser.utils import ViewBase
 from Products.CMFDefault.exceptions import AccessControl_Unauthorized
+from Products.CMFDefault.formlib.widgets import IDInputWidget
 from Products.CMFDefault.interfaces import ICMFDefaultSkin
 from Products.CMFDefault.utils import Message as _
 from Products.CMFDefault.utils import translate
@@ -168,6 +170,30 @@
                              make_query(portal_status_message=message))
 
 
+class FallbackAddView(ContentAddFormBase):
+
+    """Add view for IDynamicType content.
+    """
+
+    form_fields = form.FormFields(ASCIILine(__name__='id', title=_(u'ID')))
+    form_fields['id'].custom_widget = IDInputWidget
+
+    def createAndAdd(self, data):
+        if not self.ti.product:
+            return super(FallbackAddView, self).createAndAdd(data)
+
+        # for portal types with oldstyle factories
+        container = self.context
+        name = container.invokeFactory(self.ti.getId(), data['id'])
+        obj = container._getOb(name)
+
+        obj_type = translate(obj.Type(), container)
+        self.status = _(u'${obj_type} added.', mapping={'obj_type': obj_type})
+        self._finished_add = True
+        self._added_obj = obj
+        return obj
+
+
 class ContentEditFormBase(_EditFormMixin, PageForm):
 
     actions = form.Actions(

Added: Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.txt	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.txt	2009-08-26 19:51:00 UTC (rev 103239)
@@ -0,0 +1,113 @@
+Add Forms
+---------
+
+Set up user.
+
+    >>> uf = app.site.acl_users
+    >>> uf._doAddUser('mgr', 'mgrpw', ['Manager'], [])
+
+Create the browser object we'll be using.
+
+    >>> from Products.Five.testbrowser import Browser
+    >>> browser = Browser()
+    >>> browser.handleErrors = False
+    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+
+Register the content class and factory.
+
+    >>> from Products.CMFDefault.formlib.tests import CONTENT_ZCML
+    >>> from Products.Five import zcml
+    >>> zcml.load_string(CONTENT_ZCML)
+
+Create the type info object.
+
+    >>> from Products.CMFDefault.formlib.tests import MYFOO_XML
+    >>> from Products.CMFDefault.formlib.tests import TYPES_XML
+    >>> from Products.GenericSetup.context import SetupEnviron
+    >>> from Products.GenericSetup.interfaces import IBody
+    >>> from zope.component import getMultiAdapter
+
+    >>> ttool = app.site.portal_types
+    >>> context = SetupEnviron()
+    >>> context._should_purge = False
+    >>> importer = getMultiAdapter((ttool, context), IBody)
+    >>> importer.body = TYPES_XML
+    >>> importer = getMultiAdapter((ttool.MyFoo, context), IBody)
+    >>> importer.body = MYFOO_XML
+
+If no add view is registered for 'test.foo' the fallback add view is used. It
+just has an ID field.
+
+    >>> browser.open('http://localhost/site/++add++MyFoo')
+    >>> '[[cmf_default][Add [[cmf_default][MyFoo]]]]' in browser.contents
+    True
+    >>> browser.getControl(name='form.bar')
+    Traceback (most recent call last):
+    ...
+    LookupError: name 'form.bar'
+    >>> browser.getControl(name='form.id').value = 'MY_ID'
+    >>> browser.getControl('[[zope][Add]]').click()
+    >>> '[[cmf_default][[[cmf_default][MyFoo]] added.]]' in browser.contents
+    True
+    >>> 'MY_ID' in app.site.contentIds()
+    True
+
+This is the most simple add form you can create for 'test.foo'. Add views
+always belong to specific content factories. The name of the factory and the
+name of the add view have to be the same.
+
+    >>> from zope.component import getSiteManager
+    >>> from zope.formlib import form
+    >>> from Products.CMFDefault.formlib.form import ContentAddFormBase
+    >>> from Products.CMFDefault.formlib.tests import IFoo
+
+    >>> class FooAddView(ContentAddFormBase):
+    ...     form_fields = form.FormFields(IFoo)
+    >>> getSiteManager().registerAdapter(FooAddView, name='test.foo')
+
+The customized add form has the same title but no ID field. On the other hand
+it has the fields defined in IFoo.
+
+    >>> browser.open('http://localhost/site/++add++MyFoo')
+    >>> '[[cmf_default][Add [[cmf_default][MyFoo]]]]' in browser.contents
+    True
+    >>> browser.getControl(name='form.id')
+    Traceback (most recent call last):
+    ...
+    LookupError: name 'form.id'
+    >>> browser.getControl(name='form.bar').value = 'BAR'
+    >>> browser.getControl(name='form.baz').value = 'BAZ'
+    >>> browser.getControl('[[zope][Add]]').click()
+    >>> '[[cmf_default][[[cmf_default][MyFoo]] added.]]' in browser.contents
+    True
+    >>> 'Foo' in app.site.contentIds()
+    True
+
+Now we add again the ID field.
+
+    >>> from Products.CMFDefault.formlib.widgets import IDInputWidget
+    >>> from Products.CMFDefault.utils import Message as _
+    >>> from zope.schema import ASCIILine
+
+    >>> class FooAddView(ContentAddFormBase):
+    ...     form_fields = (
+    ...         form.FormFields(ASCIILine(__name__='id', title=_(u'ID'))) +
+    ...         form.FormFields(IFoo)
+    ...         )
+    ...     form_fields['id'].custom_widget = IDInputWidget
+    >>> getSiteManager().registerAdapter(FooAddView, name='test.foo')
+
+The customized add form has the ID field and the fields defined in IFoo.
+
+    >>> browser.open('http://localhost/site/++add++MyFoo')
+    >>> '[[cmf_default][Add [[cmf_default][MyFoo]]]]' in browser.contents
+    True
+    >>> browser.getControl(name='form.id').value = 'MY_ID2'
+    >>> browser.getControl(name='form.bar').value = 'BAR'
+    >>> browser.getControl(name='form.baz').value = 'BAZ'
+    >>> browser.getControl('[[zope][Add]]').click()
+    >>> '[[cmf_default][[[cmf_default][MyFoo]] added.]]' in browser.contents
+    True
+    >>> 'MY_ID2' in app.site.contentIds()
+    True
+


Property changes on: Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/tests.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/tests.py	2009-08-26 19:39:25 UTC (rev 103238)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/tests.py	2009-08-26 19:51:00 UTC (rev 103239)
@@ -17,11 +17,78 @@
 
 import unittest
 import Testing
+from Testing import ZopeTestCase
 from zope.testing import doctest
 
+from Products.CMFCore.PortalContent import PortalContent
+from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
+from Products.CMFDefault.testing import FunctionalLayer
+from zope.component.factory import Factory
+from zope.interface import implements
+from zope.interface import Interface
+from zope.schema import TextLine
 
+CONTENT_ZCML = """\
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five">
+
+  <five:registerClass
+      class="Products.CMFDefault.formlib.tests.Foo"
+      meta_type="Foo Type"
+      permission="cmf.AddPortalContent"
+      />
+
+  <utility
+      component="Products.CMFDefault.formlib.tests.FooFactory"
+      name="test.foo"
+      />
+
+</configure>
+"""
+
+TYPES_XML = """\
+<?xml version="1.0"?>
+<object name="portal_types">
+ <object name="MyFoo" meta_type="Factory-based Type Information"/>
+</object>
+"""
+
+MYFOO_XML = """\
+<?xml version="1.0"?>
+<object name="MyFoo">
+ <property name="content_meta_type">Foo Type</property>
+ <property name="factory">test.foo</property>
+ <property name="add_view_expr">string:${folder_url}/++add++MyFoo</property>
+ <action title="View" action_id="view" category="object" url_expr=""/>
+</object>
+"""
+
+
+class IFoo(Interface):
+
+    bar = TextLine(title=u'Bar')
+    baz = TextLine(title=u'Baz')
+
+
+class Foo(PortalContent, DefaultDublinCoreImpl):
+
+    implements(IFoo)
+
+    def __init__(self, id, bar='', baz=''):
+        DefaultDublinCoreImpl.__init__(self)
+        self.id = id
+        self.bar = bar
+        self.baz = baz
+
+FooFactory = Factory(Foo)
+
+
 def test_suite():
     suite = unittest.TestSuite()
+    s = ZopeTestCase.FunctionalDocFileSuite('form.txt')
+    s.layer = FunctionalLayer
+    suite.addTest(s)
     suite.addTest(doctest.DocFileSuite('schema.txt',
                                     optionflags=doctest.NORMALIZE_WHITESPACE))
     suite.addTest(doctest.DocFileSuite('widgets.txt',



More information about the Checkins mailing list