Basic Features

« Return to page index

Plone Developer Manual is a comprehensive guide to Plone programming.

1. Classes / Content Types

Use classes to generate content types and portal tools.

Overview

By default, when you create a class in your class diagram, it represents an
Archetypes content type. You can add operations in your model to generate
methods on the class, and attributes to generate fields in the schema. The
quick reference at the end of this tutorial will tell you which field types
you can use. You should also browse the "Archetypes quick reference
documentation":/documentation/manual/archetypes-developer-manual/fields to
see what properties are available for each field and widget type. You may set
these using tagged values (see below).

There are three basic ways in which you can alter the way your content types
are generated:

* You may set one or more stereotypes on your class, which alters the "type" of
class. A stereotype '<<portal_tool>>', for example means you are generating a
portal tool rather than just a simple content type.

* You can use tagged values in your model to configure many aspects of your
classes, their attributes and their methods. A list of recognised tagged
values acting on classes, fields and methods are found in the "quick
reference":archgenxmlquickref at the end of this tutorial.

When reading tagged values, ArchGenXML will generally treat them as strings,
with a few exceptions where only non-string values are permitted, such as the
'required' tagged value. If you do not wish your value to be quoted as a
string, prefix it with 'python:'. For example, if you set the tagged value
'default' to 'python:["high", "low"]' on a 'lines' attribute, you will get
'default=["high", "low"]' in a LinesField in your schema.

* ArchGenXML is clever about aggregation and composition. If your class
aggregates other classes, it will be automatically made into a folder with
those classes as the allowed content types. If you use composition (signified
by a filled diamond in the diagram) rather than aggregation, the contained
class will only be addable inside the container, otherwise it will be addable
globally in your portal by default.

Variants of Content Types

Simple Classes

A simple class is what we had in HelloWorld in the previous chapter.
A simple class is based on 'BaseContent' and BrowserDefault'. This is the
default if no other options override.

Folderish Classes

The easiest way to make a content type folderish is to introduce composition
or aggregation in your model - the parent class will become folderish and will
be permitted to hold objects of the child classes. You can also make a class
folderish just by giving it the '<<folder>>' stereotype. Both of these
approaches will result in an object derived from 'BaseFolder'.

You can also give a class the '<<ordered>>' stereotype (possibly in addition
to '<<folder>>') in order to make it derive from 'OrderedBaseFolder' and thus
have ordering support. Alternatively, you can set the 'base_class' tagged
value on the class to 'OrderedBaseFolder'. This is a general technique which
you can use to override the base folder should you need to. As an aside, the
'additional_parents' tagged value permits you to derive from multiple parents.

Another option is to derive from ATFolder (from ATContentTypes) by giving the
class the stereotype '<<atfolder>>'.

Other tagged values which may be useful when generating folders are:

filter_content_types -- Set this to '0' or '1' to turn on/off filtering of
content types. If content types are not filtered, the class will act as a
general folder for all globally addable content.

allowed_content_types -- To explicitly set the allowable content types, for
example to only allow images and documents, set this to: 'Image, Document'.
Note that if you use aggregation or composition to create folderish types as
described above, setting the allowed content types manually is not necessary.

Portal tools

A portal tool is a unique singleton which other objects may find via
'getToolByName' and utilise. There are many tools which ship with Plone,
such as portal_actions or portal_skins. To create a portal tool instead of
a regular content type, give your class the '<<portal_tool>>' stereotype.
Tools can hold attributes and provide methods just like a regular content
type. Typically, these hold configuration data and utility methods for the
rest of your product to use. Tools may also have configlets - configuration
pages in the Plone control panel. See the quick reference at the end of this
document for details on the tagged values you must set to generate configlets.

Abstract mixin classes

By marking your class as 'abstract' in your model (usually a separate
tick-box), you are signifying that it will not be added as a content type.
Such classes are useful as mixin parents and as abstract base classes for more
complex content types, and will not have the standard Archetypes registration
machinery, factory type information or derive from BaseClass.

Stub classes

By giving your class the '<<stub>>' stereotype, you can prevent it from being
generated at all. This is useful if you wish to show content types which are
logically part of your model, but which do not belong to your product. For
instance, you could create a stub for Plone's standard Image type if you wish
to include this as an aggregated object inside your content type - that is,
your content type will become folderish, with Image as an allowable contained
type.

Deriving/Subclassing Classes

Deriving or subclassing a class is used to extend existing classes, or change
their behavior. Using generalisation arrows in your model, you can inherit
the methods and schema from another content type or mixin class in your class.

Simple Derivation

All content types in Archetypes are derived from one of the base classes -
BaseContent, BaseFolder, OrderedBaseFolder and so on. If you wish to turn
this off, for example because the base class is being inherited from a
parent class, you can set the 'base_class' tagged value to '0'.

Multiple Derivation

You can of course use multiple inheritance via multiple generalisation
arrows in your model. However, if you need to use a base class that is not
on your model, you can set the 'additional_parents' tagged value on your
class to a comma-separated list of parent classes.

Deriving from other Products

If you want to derive from a class of an other product create a stub class
with a tagged value 'import_from': This will generate a import line
'from VALUE import CLASSNAME' in classes derived from this class.

Deriving form ATContentTypes

To derive from ATDocument just use a stereotype '<<atdocument>>'. Also
possible with '<<atfile>>', '<<atevent>>' and '<<atfolder>>'.

Packages - bring order to your code

Packages are both a UML concept and a Python concept. In Python, packages are
directories under your product containing a set of modules (.py files). In
UML, a package is a logical grouping of classes, drawn as a large "folder"
with classes inside it. To modularise complex products, you should use
packages to group classes together.

2. Attributes / Fields / Indexing

How to control the fields of your schema.

Archetypes are using 'schemas' (also called 'schemata') with 'fields' to define the form-fields on your content. The schema and its fields of your content types is generated from the 'attributes' of your classes in your model and their tagged values. Each field has a type and a widget.

The "Archetypes documentation":/documentation/manual/archetypes-developer-manual/ and the quick reference at the end of this document describes which fields are available and what parameters they take as configuration.

Usage of tagged values

If you set a tagged value on an attribute of your class, in general that tagged value will be passed through as a parameter to the generated Archetypes field. Hence, if you set a tagged value 'enforceVocabulary' to the value '1' on an attribute, you will get 'enforceVocabulary=1' for that field in the generated schema. Similarly, you can set a field's widget properties by prefixing the tagged value with 'widget:'. 'widget:label' sets the label of a widget, for instance.

Non-string tagged values

As before, when reading tagged values, ArchGenXML will generally treat them as strings, with a few exceptions where only non-string values are permitted, such as the 'required' tagged value. If you do not wish your value to be quoted as a string, prefix it with 'python:'. For example, if you set the tagged value 'default' to 'python:["high", "low"]' on a 'lines' attribute, you will get 'default=["high", "low"]' in a LinesField in your schema.

field recycling - copy from parents schema or another source schema and modify

This feature alows you to copy a field from another source schema and rename the field.

Rather than subclass an entire class then delete unwanted fields, you can explicitly copy just the fields you need. You can keep the copied field "as-is" or modify it by overriding properties with tag values as needed.

For example you may need a 'Description' field that is usually defined in your parent classes (BaseContent, BaseFolder) Schema. You would create a new attribute in your class named 'description' with a type of 'copy.' If you want it to appear in your base_edit form rather then the default of properties/metadata page you just need to change one property of the field by adding the tag 'schemata = "default"'.

You may also copy from any other schema or from within the same schema. You need to specify the source schema using the tag 'copy_from' and if you need to rename the field use the 'source_name' tag to indicate the source field Id, otherwise the Id of the field in you schema is used.

Index and metadata in catalogs and Collection

ArchgenXML can create configuration files to create an index and/or metadata entries in the catalog such as portal_catalog.

Available are the following tagged values:

'catalog:index' -- add the field to the index. Boolean, 1 or 0. Default is 0. If set, you may need to provide 'index:*' tagged values too.

'catalog:metadata' -- add the field to the metadata record on the query result? Boolean, 1 or 0. If you do not provide 'index:attributes', the name of the accessor of the field is the default. If 'catalog:metadata_accessor' is given it will be used instead.

'catalog:metadata_accessor' -- the accessor used for the metadata (string).

'catalog:name' -- sometimes you need to add an index to a other catalog than 'portal_catalog' and its XML-File 'catalog.xml'. Provide a tuple of comma separated strings, id of the catalog and the filename of its configuration file. default is "portal_catalog, Plone Catalog Tool'.

'index:type' -- the type of index used as (string), for example 'FieldIndex', 'KeywordIndex', 'DateIndex' or any available index in your portal. For known types a default is guessed, such as FieldIndex for StringFields or DateIndex for DateFields. If no guess is possible, we assume a FieldIndex.

'index:attributes' -- the attributes to use for index (string or comma separated list of strings). This are the methods called at indexing time. Normally it is enough to provide one index method, but for some specific use cases you might need to provide alternatives. If you do not provide this tagged value, the name of the accessor of the field is the default.

'index:name' -- the name of the index used (string). Use this name in your queries. If you do not provide a name, the name of the accessor of the field is the default.

'index:extras' -- some indexes are using so called 'extras' on installation as configuration. If the index need extras you'll need to declare them here. provide a comma separated list.

'index:properties' -- some indexes are using 'properties' on installation as configuration. If the index need properties you'll need to declare them here. Provide a comma separated list.

'collection:criteria' -- add the index to the Collection (aka Smart Folder) Indexes available for defining Criteria. Provide a comma seprated list of criteria that will be available by default. Available criterias are: ATBooleanCriterion, ATDateCriteria, ATDateRangeCriterion, ATListCriterion, ATPortalTypeCriterion, ATReferenceCriterion, ATSelectionCriterion, ATSimpleIntCriterion, ATSimpleStringCriterion, ATSortCriterion, ATCurrentAuthorCriterion, ATPathCriterion, ATRelativePathCriterion. You must provide an 'index:type' as well.

'collection:criteria_label' -- the display name of the 'collection:criteria', called 'friendly name' (string). Its added to the 'generated.pot' as a literal. If not given the 'widget:label' is taken if provided.

'collection:criteria_description' -- a help text (string), used for 'collection:criteria'. Its added to the 'generated.pot' as a literal. if not provided the 'widget:description' is used.

'collection:metadata' -- register the 'catalog:metadata' as an available column in a Collection. Can be used as an alternative for 'catalog:metadata'. 'catalog:metadata_accessor' is used if given.

'collection:metadata_label' -- the display name of the 'collection:metadata', called 'friendly name' (string), used for index:criteria. Its added to the 'generated.pot' as a literal. If not given the 'widget:label' is taken if provided.

'collection:metadata_description' -- a help text (string), used for 'collection:criteria'. Its added to the 'generated.pot' as a literal. If not provided the 'collection:criteria_help' or - if not provided - 'widget:description' is used.

*DEPRECATED* For backward compatibility reasons we support a sub part of the old style in ArchGenxML Version 1.6 and earlier using the tagged value 'index'. This is deprecated and will be removed in one of the next version of ArchGenXML. A tagged value 'index' with value like 'index:type' above creates an index with the accessor. To include the index in catalog metadata (and have the attribute ready to use in the brain objects), append ':brains' (same as older ':schema'), (e.g. 'FieldIndex:brains'). ArchGenXML does longer provides the ability to define multiple indexes using the old declaration style.

3. Widgets

Setting up the Widgets for each field.

ArchGenXML will pick a default widget for your fields and fill in default labels and descriptions. For example, a 'string' field gets a 'StringWidget' by default, but a 'selection' field type gets 'SelectionWidget' on a StringField! You can override this in two ways. So ArchGenXML mixes up fields and widgets slightly for convinience reasons. Anyway, you can override all predefined definitions using widget options.

Widget options are specified with the prefix 'widget:'. As with normal field tagged values, unrecognised options will be passed straight through to the widget definition.

The most common widget options are:

widget:type -- sets the widget type used. Its the name of the widget class. You can use all widgets shipped within the Archetypes-Framework by just providing this tagged value. To use 3rd-Party widgets you additionally need to import the class using the *imports* tagged value on class level.

widget:label -- sets the widget's label

widget:description -- sets the widget's description

widget:label_msgid -- overrides the default label message id (i18n)

widget:description_msgid -- overrides the default description message id (i18n)

widget:i18n_domain -- sets the i18n domain (defaults to the product name)

You may also use widget-specific options, such as 'widget:size' where they apply. Look up possible widget-specific options at the documentation of the widget you want to use.


Changing the default widgets

To change the widget used for one field-type for a whole model, a product, a package or just for all fields in one class you can set on the product, package or class level the tagged value 'default:widget:FIELDNAMEABBREVIATION' to 'WIDGETNAME'. For example use the tagged value 'default:widget:Reference' set it to 'ReferenceBrowserWidget' to use the ReferenceBrowserWidget instead of the ReferenceWidget. You might also want to also use the 'imports' tagged value and set it to 'from ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget' on your class to ensure that you get the widget definition imported into your class.

Creating new widgets

To define a new widget add a class to your model with the '<<widget>>' stereotype.

4. Methods and Actions

Defining Methods and Actions

To create a method in your class, add a method to the UML diagram, with the desired parameters. The types of the parameters and the type of the return value are ignored, since Python does not support this.

Methods can different access specifiers (also called visibilities) These are:

public (shown by a + before the method name) -- The method is part of the class' public interface. It will be declared public (accessible from unsafe/through-the-web code) by default. If you add a tagged value 'permission' (see below), it will be declared as protected by this permission.

protected (#) -- The method is not part of the class' public interface, but is meant for use by sub-classes. It will be declared private to prevent unsafe code from accessing it.

private (-) -- The method is internal to the class. It will be declared private to prevent unsafe code from accessing it.

package (~) -- The method is intended to be accessed by other code in the same module as the class. It will not gain any Zope security assertions, relying instead on the class/module defaults.

There are a few tagged values you can use to alter how the code is generated:

code -- Sets the python code body of the method. Only use this for short one-liners. If you fill in code manually in the generated files, method bodies will be preserved when you re-generate the product from the UML model.

documentation -- Content of the python doc-string of the method. You can also use the documentation feature of most UML modellers to set documentation strings.

permission -- Applies to methods with 'public' visiblity only. If you set the permission tagged value to 'My custom permission' results in security.declareProtected("""My custom permission""",'methodname') - that is, access to your method is protected by the permission with the name 'My custom permission'.

If you want to use the CMF core permissions, add an 'imports' tagged value to the method's class containing 'from Products.CMFCore import permissions', and then set the permission tagged value of your method to 'python:permissions.View', 'python:permissions.ModifyPortalContent' or any other core permission. You can also use the common paradigm of defining permissions in config.py as constants with names like EDIT_PERMISSION. A config.py is automatically generated and its contents imported, so you can just set the permission tagged value to, for example, 'python:EDIT_PERMISSION'.

Archetypes uses actions for generating custom tabs to access some view of an Archetype object. ArchGenXML can generate actions for you: Just define a method without any parameters and set its stereotype to &lt;&lt;action&gt;&gt;.

Once again tagged values can be set on the sterotyped methods in order to set some properties of the action:

action -- The TAL expression representing the action to be executed when the user invokes the action. Defaults to the methodname.

category -- The category of an action, view or form. Defaults to 'object'.

id -- The id of an action, view or form. Defaults to the methodname.

label -- The label of an action, view or form. Defaults to the methodname.

permission -- 'permission=My permission' results in 'permissions': ('''My Permission''',). See the description of the general 'permission' tagged value above for more.

condition -- A TALES expression giving a condition to control when the action is to be made available.

You can override the default Archetypes actions by using special names for the id. These are:

view -- for overriding the default view action.

edit -- for overriding the default edit action.

contents -- for overriding the default contents action.

5. Relationships between classes and objects

How to use references, associations, aggregations and compositions

With aggregations, compositions and associations you define where your new type will show up, what it might contain and to which content it can point to.

There is virtually no limit on how many aggregations, compositions and associations you can attach to a class.

Aggregations: Global Containment "Aggrigation Img":img:aggregation.png

Aggregation means: This content can exist global and in this container. The container class that gets the empty rhomb (diamond) attached is derived from BaseFolder and it's allowed_content_types is set to the class that is attached to it.If more than class is attached to one class by aggregations the allowed_content_types is extended accordingly. The attached class keeps the default ``global_allow=1``.

Compositions: Strict Containment "Composition Img":img:composition.png

Compositions are used to model parts that exist or live and die with their associated owner. So the code generated is similair to the one generated by aggregations, but with one major difference: The attached classes are only allowed to be generated in the folderish type of the class they're attached to (this is done by setting ``global_allow=0`` in the factory type information of the class).

Directed Associations: References "Directed Association Img":img:directedassociation.png

References are used to store the relation of an object to other objects.

Each content type that derives from ``IReferenceable`` is capable of being referenced. Objects from such a content type have an UID (Unique Identification) that's unique throughout the whole Plone site. Therefore References don't break if you move referenced objects around in the site.

To use ``ReferenceFields`` there are two possible ways. The by models-design clean way is to use directed associations. Another possibility is to define References as class-attributes.

Directed Associations

An directed association between two classes generates a ``ReferenceField`` in the class where the association starts.

The ``relationship`` itself is named after the association's name.

The multiplicity defines if the allows a 1:1 or 1:n relation. Attention: This only results in validation on the field. References at all don't know anything about multiplicity, so this is only a check on userinterface-level.

All other field settings are taken from the association's end, including information how to generate the widget. By default a ReferenceWidget is used. You can use tagged values on the association's end to define label, description, a different widget-type, schemata, etc. like you do it on a field (on a class attribute).

The big drawback of using associations to create ReferenceFields is that they always get attached to the end of the schema and there is no way to change that in the UML diagram. So if you need order in your fields read the next section.


References as class attributes

You can define an attribute with the type reference. Then you can apply any needed tagged values to it.

keys of interest are::

allowed_types : needs a list of allowed types

multiValued : set to 0 to only be able to select one object to reference to

relationship : name of the relationship in the reference_catalog

The benefit of using an attribute to define the reference is that you can define the place in the schema where the ReferenceField will show up.

Reference classes (advanced)

Sometimes it's needed to store information not in the origin or
destination class, but in the reference itself. UML has a notation to
model this: "association classes":http://argouml.tigris.org/documentation/defaulthtml/manual/ch17s11.html#s2.ref.association_multiway

ArchGenXML support them automatically. When a model includes an
association class, two things occur:

a) A new content type is created, named like the association name

b) The generated ReferenceField has a new attribute defined like this: ``referenceClass = ContentReferenceCreator('My_Association_Name')``

This causes that the class of the reference instances is now not "Archetypes.ReferenceEngine.Reference", but "Archetypes.ReferenceEngine.ContentReference", a subclass of it that has a new method: getContentObject(), that return the content inside the
reference.

The same effect can be reached without association classes, by defining
a content type and then adding the "association_class" tagged value to
the association (although I haven't been able to make this work).

To create the reference via code, use a special form of the addReference method::

origin = <the origin content>
destination = <the destination content>
assocName = <the association name>

origin.addReference(destination,
assocName,
referenceClass=ContentReferenceCreator(assocName),
attr1=value1,
attr2=value2...)

(where attr1, attr2... are the attributes of the association)

To read the data, we can't use the origin.getRefs(assocName) method, as usual, because it returns only the destination objects. One way to read it is by using the reference_catalog tool::

from Products.CMFCore.utils import getToolByName
tool = getToolByName(origin, 'reference_catalog')
refs = tool.getReferences(origin, assocName)
if not refs:
return []
else:
return [(ref.getContentObject(), ref.getTargetObject()) for ref in refs]

6. Workflows

Usage of state diagrams to create custom workflows.

ArchGenXML can use state diagrams to generate workflows for a portal type. Workflows are used to set the various states an object can be in, and the transitions between them.

Importantly, workflows control permissions of objects. By convention, and for convenience and consistency, most content types will use the permissions found in the CMFCorePermissions class in the CMFCore product to control access to their methods. The methods generated by and inherited from the CMF and Archetypes frameworks adhere to this principle. Although many different content types use the same basic permissions to control access, workflows are the means by which you can control permissions for an object in detail. For instance, you may wish to specify that in the testing state, Manager and Reviewer has Modify portal content permissions, and Owner, Manager and Reviewer has View permissions. For the completed state, you could have a different set of permissions. See the DCWorkflow documentation for more details about how to use workflows.

Problems with UML-Software

The workflow implementation of ArchGenXML has to date only been tested with ArgoUML and Poseidon (tested Version is 3.1 and 3.2 CE).

ObjectDomain is known not to work at this time, because it does not appear to correctly export the XMI for state diagrams. If you have different experiences, please add a comment to this document or contact us.

Creating a workflow

In your UML modeller, add a state diagram for the class you wish to create a custom workflow for. If you don't want to assign the workflow to a class use an class with stereotype stub. In Poseidon, this is done by right-clicking on the object in the tree on the left hand side, and selecting to add a new state diagram. The name of the state diagram becomes the name of the workflow.

States

On the state diagram, add a state item (a rounded-corner box) for each state. You must have an initial state of your workflow for it to work correctly. Use a "initial state" symbol (filled cirlce) for the state your object defaults to after creation. Optional you can use a normal state item and set a tagged value initial_state with value 1 to it.

At present, ArchGenXML does not support the "final state" UML symbols to represent final states, so you should stick to the standard state symbols.

The names of your states in UML become the names of the states in your workflow. The user-visible label can be set with the label tagged value; it defaults to the state name.

Workflow in UML

Transitions

For each possible transition between states, add a transition arrow to your UML model. The name of the transition becomes the name of the workflow action. You can set the label tagged value on the transition to set a custom label to display to the user.

If a transition with the same name/target is used more than one time, you can use the stereotype <<primary>> to define its settings once and use it by name on all similar transitions.

Transition guards

You can add a guard to a transition to restrict to whom and when it is made available. Set the expression field of a transition to a |-separated list of the following pairs:

guard_roles
Set guard_roles:Owner; Manager to restrict the transition to users posessing the Owner or Manager role in the current context.
guard_permissions
Set guard_permissions:My custom permission;View to ensure that only those users with My custom permission or View permissions in the current context are allowed to access the transition.
guard_expr
Set 'guard_expr:expression", where expression is a TALES expression, to have the expression be evaluated in order to determine whether the transition should be made available.

Thus, to restrict access to roles Reviewer and Manager, and only those users with permission My custom permission and View in the current context, you can set the expression of the transition to guard_roles:Reviewer;Manager|guard_permissions:My custom permission, View.

If you are using Poseidon, transition guards are located in the property of the transition arrow with the name [A] Guard. You can add an expression like the one outlined above to this field.

Permissions

ArchGenXML uses tagged values on states in a somewhat unconventional, though convenient, way to control permissions. With the exception of the special-case initial_state and label tagged values, you give the name of the permission as the tagged value key, and a comma-separated list of roles the permission should be enabled for as the value.

There are three shorthand permission names available:

access
referes to the Access contents information permission,
view
refers to the View permission,
modify
refers to the Modify portal content permission,
list
refers to the List folder contents permission.
delete
refers to the Delete objects permission.

Hence, if you want your state to permit anonymous users and members to view your content, only permit managers to modify, and permit both the owner and managers to add new objects controlled by the Add MySubTypes permission, you can add tagged values to the workflow state:

    view           ==> Anonymous, Member
    modify         ==> Manager
    Add MySubTypes ==> Owner, Manager

If you want to aquire the permissions and add new ones you can use the value 'aquire':

    view           ==> acquire, Anonymous, Member

(One special case: if you leave the value empty, no one gets that permission (which is logical), but it also explicitly unsets acquisition of the permission).

Workflow actions

The portal_workflow tool allows a script to be executed before and/or after a transition is completed. This is no longer supported. Instead subscribers to the Workflow events are used. Event-subsribers are more flexible.

Actions are set using the effect field of a transition. The value given here gives the name of the subscriber to execute (and thus must be valid python method name). ArchGenXML will create or modify a subscriber for each workflow-action in a file wfsubsribers.py in your product. You must fill in the method bodies for the actions in this file. Method bodies will be preserved upon re-generation of your product from the UML model. In Plone 2.5 compatible mode DCWorkflow needs a patch with a backport. This patch is generated, if 2.5 is selected as plone_target_version (tagged value on model).

By default, actions specified in this way are post-transition actions, meaning that they are executed after the transition has taken place. If you wish to specify a pre-transition action, executed before the transition takes place, separate action names by semicolons: preActionName;postActionName. If you want only a pre-transition action, use preActionName; to specify that there is an empty post-transition action.

Attach workflow to more than one class

In UML there is no semantic to use a workflow for more than one class. We introduced the tagged value use_workflow for classes. Value is the workflow name.

Worklist support

You can attach objects in a certain state to a worklist. A worklist is something like the "documents to review" list you get when you're a reviewer in a Plone site. This is done by adding a tag worklist to the state with the name of the worklist as value (like review_list).

You can add more than one state to a worklist, just by specifying the same name for the worklist tagged value. Likewise, you can have more than one worklist (just not on the same state). The tagged value worklist:guard_permissions allows you to specify the permission you need to have to view the worklist. The default value is Review portal content.

7. Tests

Generation of tests from UML.

Overview

We hope there is no need for us to emphasize how important testing is for even the most simple products you may be developing. This makes it especially useful to include the creation of both your testing framework and individual tests within your UML model.

Within a new package with a stereotype of '<<tests>>' you can create your base test case class with a stereotype of '<<plone_testcase>>' and a test setup class with a stereotype of '<<setup_testcase>>'. You can then add additional test classes as needed with a stereotype of either '<<testcase>' or '<<doc_testcase>>'.

"sample UML":img:uml-testcase.png

Base Test Case

Creating a class in your tests package with a stereotype of '<<plone_testcase>>' generates the needed base test case for all other test cases.

Test Setup

Creating a class in your tests package with a stereotype of '<<setup_testcase>>' generates a testcase for the setup, with pre-defined common checks.

Test Cases

Test Case

Creating a class in your tests package with a stereotype of '<<testcase>>' generates a standard test case class.

Doc Tests

Creating a class in your tests package with a stereotype of '<<doc_testcase>>' generates a doc test file in the 'doc' folder of your product with a name of 'class + .txt'. You can use the tag of 'doctest_name' on your class (excluding any extension as '.txt' is appended automatically) to indicate a different name for your generated doc test.

Functional Tests

Generate browser functional tests using the '<<plonefunctional_testcase>' stereotype.

Interface Tests

Generate interface tests using the '<<interface_testcase>>' stereotype.

It is unverified whether these generated test cases will verify Z3 style interfaces but stay tuned!