For years we have had the need to embed a utility in Plone products that allows us to execute private methods in restricted Python mode. You need such a utility when using a ZMI Python script in a Page Template or in an Expression. The last one is a CMFCore class that is used in workflow transition condition or in Archetypes field condition for example. To be able to do this utility you need to create a ‘portal tool’ for your site with some public methods. Here I will show you how to build a very basic utility that I can use in the next blog entry.
What is a tool
In pure Zope 2/CMF, a tool is a unique item with a forced id that inherits from the SimpleItem class. An instance of a tool is always created on the root of your Plone site to be acquirable from everywhere in the site.
The CMFCore product provides a function that allows us to call a tool in an unique way: ‘getToolByName’.
In python modules, external methods, or python scripts, you can use following code:
from Products.CMFCore.utils import getToolByName
mytool = getToolByName(obj or context, 'tool id', default value is not found - None if not specified)
You can use it in Page Template too, using the 'module' call:
python:modules['Products.CMFCore.utils'].getToolByName(here, 'tool id')
What should a tool module contain
Now back to our implementation.
First you need to have a product to write in. To create a new product please read this howto , or download someone else's to play with.
In your product create a file called 'tool.py,' if there will be only one tool in your product, or 'myfunctiontool.py' if there will be more than one. As a best practice, I recommend to always choose the second way.
A simple tool code could be:
from OFS.SimpleItem import SimpleItemfrom Products.CMFCore.utils import UniqueObject
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
class ProductNameTool(SimpleItem, UniqueObject):
""" Description of what your tool handle
id = 'portal_productname'
meta_type = 'Product Name Tool'
manage_options = SimpleItem.manage_options
security = ClassSecurityInfo()
Description of imported items:
- SimpleItem is a class coming from Zope that ensures us that we have persistence and base views available in ZMI.
- UniqueObject is a utility class coming from CMF that ensures us that nobody can rename an instance of it. It's important for us because our tool must never be renamed by error.
- ClassSecurityInfo is the class to use in every Zope persistent class in order to define the security of each method.
- InitializeClass is the helper function that registers our class in the Zope context.
Description of class attributes:
- The id must be unique on your site root and should start with 'portal_' or end with '_tool'. If your tool unherit from ZCatolog the id must be suffixed by '_catalog'.
- All classes must have a meta type. You can just extend your class name with spaces.
- manage_options contains the tabs displayed in the ZMI.
- security defines the security in your class. All classes must contain such a declaration.
Initialize our tool at Zope startup
Now that Zope knows that you have a tool, what about Plone? Plone requires an extra step in order to register our tool (full details in: "Write your first Zope 2 product".
We have to edit the __init__.py file of our product and add following lines:
from Products.CMFCore.utils import ToolInit
from myfunctiontool import ProductNameTool
tools = (ProductNameTool,)
def initialize( context ):
ToolInit( 'My Product Tools'
).initialize( context )
ToolInit is a class that handles tool registration for us. We can register all tools defined in our product in only one pass.
ProductNameTool is our tool class. Here we need to import all tool classes we want to register.
At last, we call the ToolInit constructor and run its 'initialize' method to build our tool factories:
- the first parameter is the name viewed in the Add dropdown menu in the ZMI
- tools is a tuple of classes
- product_name should contain the name of your product
- icon is the name of the icon displayed in the ZMI (16x16) that must be on the root of your product
We can restart Zope then add the tool in the ZMI. After that, we can add methods to this tool. Most often these methods are public or protected by 'View' or 'Manage portal' permissions.
Future of Zope 2 tools
In Zope 3 tools are becoming utilities. In Plone 3 we are in limbo, with all old Zope 2 tools registered both as tools and as utilities. In the near future, however, only the utilities will be used. Use Tool for Plone 2.5 development only.
You can read more about utilities in Zope 3 and Plone 3 documentation.