RFC II: pre-creation view solution [was Re: [Zope3-dev] RFC: preCreation view, postCreation view use cases]
Gary Poster
garyposter@earthlink.net
Tue, 2 Apr 2002 13:45:11 -0500
On Thursday 28 March 2002 10:17 am, Guido van Rossum wrote:
> I'm curious how you can provide a
> general framework for this feature -- maybe a look at the jobboard
> example (checked in as Packages/JobBoardEx on cvs.zope.org) would help
> you.
OK: I've built one.
I need to have a general blessing, particularly from ZC but also from the
community, before I merge this into the head. It changes a few fundamental
pieces of code. I would like to have some kind of approval very soon, so
that my merge (already before Steve A.'s And Stephan's recent mega-checkins)
isn't too nightmarish.
Interested parties may checkout Zope3 from the
"gary-pre_create_views-branch" branch, and checkout JobBoardEx from
"gary-pre_create_views_example-branch"
To try it out, once you have everything set up:
* You can see the default pre-creation view by typing in something like
http://127.0.0.1:8080/.ZPTPage.;create
within the container to which you want to add an item. This will work
with all standard addable items.
* See this work with the job board by adding a job board, then clicking
add job: you can see in the URL that we are using the "create" namespace.
Add a job and then click on "Approve submitted jobs" to see the new item
(note that approving doesn't work: it doesn't appear to be pertinent to my
changes and I don't want to spend time looking further into it until this
approach is approved)
Here's an overview of the approach: kinds of things changed, pros, and cons.
Kinds of things changed:
* I changed all of the factory/provideClass code in Zope.App.ZMI to accept
arguments.
* I added a namespace, "create," to PublicationTraversal. This namespace
returns an Addable corresponding to the addable id (such as is used in the
standard adder;view html)
* I added a property to the zcml zmi:factoryFromClass tag, marker_interface,
in which you name the marker interface you want to use to attach creation
views for this factory
* I did a fishy __implements__ trick to add marker interfaces on Addable
instances (see cons below)
Pros
* All previously written tests pass
* You can now have a view to create an object. As a view, you can then use
most any standard mechanism you desire to create the view (including Zope
2.5-ish session objects for wizards, presumably). You can also define both
default creation views and other creation views.
* You can therefore gather arguments to create a class without instantiating
it: this is important for a number of reasons. First, it allows you to
cleanly use standard Python classes with required __init__ arguments.
Second, it allows you to gather those arguments incrementally without calling
a potentially expensive instantiation until you are ready.
* The creation view also has complete per-product control of where the
product goes after creation (i.e. the post-creation use case is taken care of
per-view at least)
* Objects that do not need a special creation view still have a default
creation view (i.e., http://127.0.0.1:8080/.ZPTPage.;create as above)
* Fairly simple set-up: just build a marker interface, build a pre-creation
view, and set up the marker interface and view as in the following zcml
excerpt (*everything* is standard except the "marker_interface" declaration):
<zmi:factoryFromClass
name=".Job."
permission_id="Zope.Public"
title="Job"
marker_interface=".IJob.IJobCreator."
/>
<!-- *** Views *** -->
<!-- pre-creation job view -->
<browser:defaultView
for=".IJob.IJobCreator"
name="create"
factory=".JobView.CreateJobView"
/>
<security:protectClass
name=".JobView.CreateJobView"
permission_id="Zope.Public"
methods="index, action"
/>
Cons
* THE BIGGIE: I use the Addables as the traversed objects to get the
creation views. This has a lot of advantages, in that the creation view then
has all of the necessary Addable creation information available up the
acquisition chain. In order to have this work, I perform, arguably, a hack:
I attach marker interfaces to the Addable *instances* in __implements__, as
they are being added from the zcml. This conflicts with nothing at the
moment, and I tried to accomodate future changes (i.e., adding a true
__implements__ declaration to the Addable class). However, it is a hack,
since __implements__, even for these marker interfaces, is for classes...
* The approach requires you to create a marker interface *if* you need a
special creation view (if you want to use the default then no marker
interface is needed). Very easy, but yet another thing to have to do.
* the zcml property name "marker_interface" is not descriptive enough, both
because it is a pre-creation marker interface, and because in terms of the
implementation it could also be a tuple. Ideas?
* It would be nice if one could automatically create marker interfaces from
the associated (created) class __implements__ so that creation views for
superclasses could be automatically available. I don't see an easy clean way
of doing this, though.
* In the JobBoard example, since there are no placeful factories yet, Jobs
are available everywhere. I made it so that Job creation views could only be
shown in the JobBoard for a lark, but placeful factories will eventually be
needed, of course
Things I could do if this is approved
* tests specifically for the changes (factory tests involving arguments, in
particular)
* I could easily change Container's "adder;view" to use this
mechanism
* I could have added a preview creation view for the JobBoard example: that
kind of thing wouldn't be too hard
Epistle over. Thanks for reading. Please give feedback asap to keep me from
too much merging hell. :-)
Gary