Skip to content

Instantly share code, notes, and snippets.

@regebro
Last active December 15, 2015 21:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save regebro/5326178 to your computer and use it in GitHub Desktop.
Save regebro/5326178 to your computer and use it in GitHub Desktop.
Overview over ways to create views in Zope, and some opinions on their future.

Sanetizing Plone Views

(Pun intended)

There are too many ways of createing views in Plone. This needs fixing. It's a job that is too much for any one person, so we need a plan. This is an attempt to look at the situation and asses things so that we can make a plan, which can then be made into a PLIP and worked on.

I split the ways of creating view into groups after how the views are looked up by the publishing machinery. This is important since it means that many of the types of views can only be removed by removing the whole group.

My apologies if I have missed any ways of doing this.

I. Object lookup

Zope is an object publisher, and it will use traversal to find an object. What makes Zope unique is that it will not look up a view on that object to render it, instead it will simply call the object. This means that the simplest form of view we can have is to just find a callable object of some sort, and call it, and display whatever it returns, under the assumption that whatever it returns is HTML.

  • Ubiquity: Everywhere.
  • Method of removal: Can be removed by removing all object lookup of views in Baserequest.
  • Recommendation: Can not be removed for the forseeable future, as this is the basis for all methods under both section I. and section II.

I.a. Object methods

Any object stored in ZODB can be traversed to, and if that object has a method that has a doc-string, it can be traversed to and used as a view.

  • Ubiquity: No sane person uses this in new code, however, it's quite common in Zope core, and perhaps also in CMF and Plone core. For example all the manage_whatever methods used by the ZMI are done like this.
  • Method of removal: Can be removed by adding special casing to not call direct object methods.
  • Recommendation: Keep until the ZMI is removed.

I.b. Callable attributes, ie templates

Templates are not object methods, but just object attributes. Since Python's lookup of attributes and methods doesn't differ, neither does Zope.

There are two types of templates supported, DTML and ZPT.

  • Ubiquity: Unusual in modern code, however most of Zope's internals uses this.
  • Method of removal: Can be removed by adding special casing to not call Templates.
  • Recommendation: Removing this would require a complete rewrite of Zope. Removing it is clearly not feasible at this moment. However, DTML templates can be rewritten, although that's a big job.

I.c. Making the object callable

This is to some extent just special cases of the above I.a. and I.b., but still worth mentioning as an illustration of the complexity.

I.c.1. __call__

The __call__ is a special case of as it makes the object as a whole callable, and hence any object with this method will be a view all by itself.

  • Ubiquity: 46 cases in Zope. 2 in CMFPlone.
  • Method of removal: Can be removed by removing all object lookup of views, or by adding special casing to not call traversed objects.
  • Recommendation: Move to using default BrowserViews for these objects.

I.c.2. index_html

If the object has a method or template called index_html this will be used as the view.

  • Ubiquity: 7 cases in Plone core 10 in CMFPlone. Some have both __call__ and index_html. Probably the behavior is subtly different.
  • Method of removal: Can be removed by removing all object lookup of views, or by removing the special handling of index_html in BaseRequest.
  • Recommendation: Move to using default BrowserViews for these objects.

II. Acquisition

Thanks to the wonders of acquisition, object attributes can be acquired from other objects that are higher in the content hierarchy. This adds a bunch of extra ways of making views. Some of these are so commonly used that the can not be removed any time soon.

  • Ubiquity: Everywhere.
  • Method of removal: Can be removed by checking if the found view is acquired and then not calling it.
  • Recommendation: Can not be removed for the forseeable future, as this is the basis for all methods under section II.

II.a. Persistent "methods"

A Python script can reside somewhere in the object hierarchy, and it will automatically become an attribute on the folderish object it resides in, as well as all other objects that resides anywhere inside that folderish objects child hierarchy.

  • Ubiquity: This is one of the main features of the Zope through-the-web technology, but it is no longer common to use this directly to build sites and applications.
  • Method of removal: Can be removed by specifically adding a check if it is an acquired template.
  • Recommendation: Keep at least until II.c. has been removed.

II.b. Persistent templates

A DTML or ZPT templates can reside somewhere in the object hierarchy, and it will automatically become an attribute on the folderish object it resides in, as well as all other objects that resides anywhere inside that folderish objects child hierarchy.

  • Ubiquity: This is one of the main features of the Zope through-the-web technology, but it is no longer common to use this directly to build sites and applications.
  • Method of removal: Can be removed by specifically adding a check if it is an acquired template.
  • Recommendation: Keep at least until II.c. has been removed.

II.c. Portal skins

The portal_skins tool is modifying the Acquisition context for a CMF site so that all templates that reside in any of the portal_skins skin folders will become an acquired template of any content object in the CMF site. This allows several new, related methods of creating views:

  1. Add a DTML template, ZPT template or Python script in a folder inside portal_skins.
  2. Add a DTML template, ZPT template or Python script in a folder on the local disk, that will be mapped through a "Filesystem Directory View" into portal_skins, allowing it to become an attribute on the content objects.
  • Ubiquity: Over 2000 templates and scripts in Plone.
  • Method of removal: Can be removed by moving all skin scripts and templates to a ZPT based solution.
  • Recommendation: This evil has to go. It's a massive job. First all existing templates and script must be converted, then portal_skins can be deprecated, then all of CMF slowly made obsolete by Plone.

III. BrowserViews (Zope Toolkit)

Zope 3 was to fix the mess, but since we merged all the fun bits into Zope 2, it just made it messier. However, we now have a clean definition of what a view is, which is good. There is an interface hierarchy of different kinds of views, of which BrowserView is the relevant here, and it's an object that takes a context and a request and returns a response, similar to other frameworks.

It is the future, but even though there is only one type of view, you can add views by an insane amount of different ways.

  • Ubiquity: Everywhere.
  • Method of removal: Can be only be removed by going back to Zope 2.7.
  • Recommendation: Keep.

III.a. Raw component architecture

You can simply make a view, and register it by direct calls to the component architecture.

  • Ubiquity: Unusual.
  • Method of removal: Can be only be removed by removing the component architecture. All other ways of adding BrowserViews rely on this.
  • Recommendation: Keep.

III.b. ZCML

The original way to add BrowserViews was with ZCML. That's all and nice except there are too many ways of doing it even with ZCML.

As a side-note: The way of looking up default browser pages is overly complex and should probably be looked at as well.

III.b.1 browser:view

The fundamental command to make a view is called browser:view. It's very verbose, and hence almost never used. It does several things, amongst them it protects the view with a permission, and it creates a view class dynamically if there isn't one, and it can insert the view in a menu.

It supports both attributes on classes or templates, with or without classes, and it can set which attributes of a class is accessible from the template, etc, etc.

It can also take a page subcommand, see III.b.2.

  • Ubiquity: Unusual.
  • Method of removal: Can be removed by removing the browser:view command from Five.
  • Recommendation: Try to remove it. It's too complex. If we are still using the menu support (I know CMF was at some point), then stop it. Some things are using browser:view to make unusual views, such as traversers etc, which could pose a problem.

III.b.2 browser:page

A simpler way is browser:page, which is the standard way of creating BrowserViews. This is also extremely complex, as it supports all the features of browser:view.

  • Ubiquity: The most common way.
  • Method of removal: Can be removed by removing the browser:page and browser:pages commands from Five.
  • Recommendation: Keep for now, but it's complexity and the general hate of all things XML means that we should look for a way to get rid of all ZCML in the long run.

III.c View customizations

This is the BrowserViews replacement of portal_skins. It allows you to change BrowserViews templates through-the-web. It's an essential part of the through-the-web story for Plone, and as long as we support that, we need to keep this.

Word on the -street- mailing list is that it doesn't work as expected and isn't very useful.

  • Ubiquity: A way of customizing a site, not very common.
  • Method of removal: Can be removed by removing the portal_view_customizations tool.
  • Recommendation: Remove.

III.d five.grok

To get rid of ZCML, Martijn Faasen created the Grok web framework. Getting rid of ZCML seemed a good idea. So Lennart Regebro and Godefroid Chapelle created five.grok to bring Grok to Zope.

  • Ubiquity: Heavily used by a few people, some of the Plone core developers.
  • Method of removal: As it's a separately downloadable module it can't really be removed, only discouraged. We can remove it from Plone core.
  • Recommendation: Keep for now.

Summary:

Method Ubiquity Recommendation
Object lookup: method Unusual Must stay for now
Object lookup: template (DTML) Common in core Remove
Object lookup: template (ZPT) Common in core Feasibility study
Object lookup: __call__ Common in core Remove
Object lookup: index_html Unusual Remove
Acquired Python scripts Unusual Must stay for now
Acquired DTML Templates Unusual Must stay for now
Acquired ZPT Templates Unusual Must stay for now
Portal skins (Scripts, DTML, ZPT) Everywhere Remove from core
BrowserViews: Direct API calls Unusual Must stay
BrowserViews: browser:view Unusual Remove
BrowserViews: browser:page/pages Everywhere Keep
BrowserViews: View customizations Core feature Remove
BrowserViews: five.grok Common Keep for now
@gotcha
Copy link

gotcha commented Apr 15, 2013

I have not been able to understand which of those ways to define a view should be recommended and kept "forever"...

@regebro
Copy link
Author

regebro commented Jul 2, 2013

None of them are good. five.grok is quite nice, but forces you into the grok-style, not everyone likes it. Also the martian-stuff is magic.

I think we should first get rid of portal_skins, and also remove index_html (and much of the traversal magic), and then talk about how to get rid of ZCML altogether. Grok may be the way to go. Perhaps something else. We could replace all the grok magic with class decorators, for example. But that's still years before we have to have that discussion. :-)

@aclark4life
Copy link

Wow this is awesome… thanks for posting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment