Taming the Wild Types Tool
Taming the Wild Types Tool
Overview
A fairly young addition to the PTK / CMF architecture, the
portal_types
tool plays several important roles.
Understanding these roles is a key piece of zen for CMF
developers and site builders.
Roles of the Types Tool and TypeInformationObjects
Object Construction
Initially, the types tool was conceived as a simplified replacement for the "Wizards" folder of the "classic" PTK. Wizards were typically multi-page forms, which collected metadata and content from the user in order to construct a content object, or a folder. Separating the logic for constructing an object (into a Wizard, distinct from the object's class) from the logic used to edit it (typically, in the class itself), made for poor maintainability. In addition, the Wizards had to be distributed as through-the-web objects, which made updates to PTK/CMF-based sites quite painful.
The original versions of the type information objects stored in the types tool contained little more than the properties needed to construct an instance through a simple, polymorphic interface.
Having created a registry of "addable content types" for a CMF Site, other roles began quickly to accrete.
Skinning Content UI
Having successfully "skinned" the portal-wide UI
components via the creation of the portal_skins
tool, we
wanted very much to allow site builders and application
developers to customize the UI components for specific
content objects, as well. The type information objects
turned out to be logical containers for the mappings
between logical "actions" and the skin methods which enact
them.
Holding Site-Specific Policies
Embedding policy decisions about content objects in their classes makes such content objects hard to reuse; sites whose policies (discussability, for instance, or allowed contents) are forced to subclass to override such policies, and may not be successful, at that. Type information objects make excellent "policy configuration points" for such choices.
Customizing Content Behavior in Instance Space
Because more than one type information object can "point" to the same underlying class, while imparting different construction semantics, UI, and policy settings, type information objects allow the site builder to leverage CMF content objects for multiple purposes.
Interfaces
portal_types
Interface
Objects implementing this interface serve as the central registry for content type information in a CMF site.
API:
# getType__roles__ = None # Public def getTypeInfo( self, contentType ): """ Return an instance which implements the ContentTypeInformation interface, corresponding to the specified 'contentType'. """ # listTypeInfo__roles__ = None # Public def listTypeInfo( self, container=None ): """ Return a sequence of instances which implement the ContentTypeInformation interface, one for each content type regisetered in the portal. If the container is specified, the list will be filtered according to the user's permissions. """ def constructContent( self, contentType, container, id ): """ Build an instance of the appropriate content class in 'container', using 'id'. """
ContentTypeInformation Interface
Objects implementing this interface function as factories and configuration points for the classes they wrap.
API:
def Metatype( self ): """ Return the Zope 'meta_type' for this content object. """ def Type( self ): """ Return the "human readable" type name (note that it may not map exactly to the 'meta_type', e.g., for l10n/i18n or where a single content class is being used twice, under different names. """ def Description( self ): """ Textual description of the class of objects (intended for display in a "constructor list"). """ def isConstructionAllowed( self, container ): """ Does the user have the permission to construct an instance of this type in 'container'? """ def allowType( self, contentType ): """ Can objects of 'contentType' be added to containers whose type object we are? """ def constructInstance( self, container, id ): """ Build a "bare" instance of the appropriate type in 'container', using 'id' as its id. Return the URL of its "immediate" view (typically the metadata form). """ def allowDiscussion( self ): """ Can this type of object support discussion? """ def getActionById( self, id ): """ Return the URL of the action whose ID is id. """ def getIcon(self): """ Returns the portal-relative icon for this type. """
Implementations
TypesTool
In addition to implementing the portal_types
interface,
instances of this type are ObjectManagers: they hold type
information objects, as well as "helper" objects (e.g.
Python Scripts). They provide a UI for adding new type
information objects, and support for populating these
objects with default values registered by Zope products
(see "Implementing the factory_type_information
Protocol", below).
TypeInformation (base class)
This class implements a shared portion of the ContentTypeInformation interface (those portions not dealing with object construction):
- Action list bindings and UI
- Policy configuration
- Metadata about the type itself.
TypeInformation objects have several shared properties:
title
Human-readable "type name".description
Fuller description, used in selection UIs.content_meta_type
What is the underlying Zope meta_type for objects of this type?icon
What icon should we show for objects of this type?immediate_view
-- After construction, what method should we show first?filter_content_types
/allowed_content_types
-- If folderish, do objects of this type limit their contents to specific types?allow_discussion
-- Do objects of this type allow discussion?
FactoryTypeInformation (FTI)
This class implements the object construction portion of the ContentTypeInformation interface by invoking Zope's product-dispatcher/factory-dispatcher mechanism directly. These type objects are simplest to configure, and provide the easiest path to integrating content objects supplied "directly" by Zope products.
FTI objects have two unique properties:
-
product
- the name of the Zope product which holds the class and factory methods for the objects of this type.
-
factory
- the name of the factory method (not
the Zope "factory object" created for ZClasses!) which
creates instances of the class. Notes:
- This should be a "direct" method, not a form.
- The user must have permission to invoke the method in the current location, according to the Zope security policy.
- The method will be called, effectively as though
invoked so:
manage_addProduct[ product ].factory( id )
Note that additional positional and keyword arguments might be passed, if the invoking method supplies them.
ScriptableTypeInformation (STI)
This class implements the object construction portion of the ContentTypeInformation interface by invoking a user-supplied method (typically a PythonScript). Somewhat more difficult to set up than FTI objects, these type objects provide for more flexible object creation, e.g.:
- Populate default metadata for the type.
- Supply default content for the type.
- Configure multiple objects, e.g., a folder with one or more content objects.
STI objects have two unique properties:
-
permission
- the permission which protects their constructor method / script.
-
constructor_path
- a traversable path to the method or
script to be called to construct an instance. This
method must accept at least two arguments
(
container
andid
), and must return an instance, already added tocontainer
, and wrapped in it.
See also How-to: Using Scriptable Type Information type objects
Usage Scenarios
This section describes several kinds of customizations which the types tool facilitates.
Adding / Removing Content Types
Unlike Zope products, whose factories show up "automagically" in the "Add..." list after product installation, CMF sites require explicit configuration to enable new product types. Likewise, a particular CMF site may suppress the creation of certain content types, merely by removing its type information object.
Creating "News-Only" Folders
Suppose you need to restrict the items created under your
site's /news
folder to be only NewsItems? Create a new
type object, using CMFDefault/Folder
as your starting
point, and then check the 'Filter content types?" checkbox
and select only "NewsItem" in the Allowed content types
list.
Internationalizing Action URLs
Change the Name
property of each action on a type
object's Actions
tab to internationalize the label which
shows up in the 'actions_box'; change the Action
property to select an internationalized skin method.
Binding Customized UI
Create custom skin methods for your objects, and bind them using the Actions tab (skin methods which reuse the names of the objects' existing actions don't need any re-binding).
TBD
Developer Docs
factory_type_information
protocol- Using ZClasses as content
Futures
- Type objects + contained methods --> "local" ZClasses?