doc/book/en/development/datamodel/define-workflows.rst
brancholdstable
changeset 5422 0865e1e90674
parent 4985 02b52bf9f5f8
parent 5421 8167de96c523
child 5424 8ecbcbff9777
equal deleted inserted replaced
4985:02b52bf9f5f8 5422:0865e1e90674
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 .. _Workflow:
       
     4 
       
     5 Define a Workflow
       
     6 =================
       
     7 
       
     8 General
       
     9 -------
       
    10 
       
    11 A workflow describes how certain entities have to evolve between
       
    12 different states. Hence we have a set of states, and a "transition graph",
       
    13 i.e. a set of possible transitions from one state to another state.
       
    14 
       
    15 We will define a simple workflow for a blog, with only the following
       
    16 two states: `submitted` and `published`. So first, we create a simple
       
    17 *CubicWeb* instance in ten minutes (see :ref:`BlogFiveMinutes`).
       
    18 
       
    19 Set-up a workflow
       
    20 -----------------
       
    21 
       
    22 We want to create a workflow to control the quality of the BlogEntry
       
    23 submitted on the instance. When a BlogEntry is created by a user
       
    24 its state should be `submitted`. To be visible to all, it has to
       
    25 be in the state `published`. To move it from `submitted` to `published`,
       
    26 we need a transition that we can call `approve_blogentry`.
       
    27 
       
    28 A BlogEntry state should not be modifiable by every user.
       
    29 So we have to define a group of users, `moderators`, and
       
    30 this group will have appropriate permissions to publish a BlogEntry.
       
    31 
       
    32 There are two ways to create a workflow: from the user interface, or
       
    33 by defining it in ``migration/postcreate.py``. This script is executed
       
    34 each time a new ``cubicweb-ctl db-init`` is done.  We strongly
       
    35 recommend to create the workflow in ``migration/postcreate.py`` and we
       
    36 will now show you how. Read `Two bits of warning`_ to understand why.
       
    37 
       
    38 The state of an entity is managed by the `in_state` attribute which
       
    39 can be added to your entity schema by inheriting from
       
    40 `cubicweb.schema.WorkflowableEntityType`.
       
    41 
       
    42 
       
    43 About our example of BlogEntry, we must have:
       
    44 
       
    45 .. sourcecode:: python
       
    46 
       
    47   from cubicweb.schema import WorkflowableEntityType
       
    48 
       
    49   class BlogEntry(WorkflowableEntityType):
       
    50       ...
       
    51 
       
    52 
       
    53 Create states, transitions and group permissions
       
    54 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
    55 
       
    56 The ``postcreate.py`` script is executed in a special environment, adding
       
    57 several *CubicWeb* primitives that can be used.
       
    58 
       
    59 They are all defined in the ``class ServerMigrationHelper``.
       
    60 We will only discuss the methods we use to create a workflow in this example.
       
    61 
       
    62 A workflow is a collection of entities of type ``State`` and of type
       
    63 ``Transition`` which are standard *CubicWeb* entity types.
       
    64 
       
    65 To define a workflow for BlogDemo, please add the following lines
       
    66 to ``migration/postcreate.py``:
       
    67 
       
    68 .. sourcecode:: python
       
    69 
       
    70   _ = unicode
       
    71 
       
    72   moderators = add_entity('CWGroup', name=u"moderators")
       
    73 
       
    74 This adds the `moderators` user group.
       
    75 
       
    76 .. sourcecode:: python
       
    77 
       
    78   wf = add_workflow(u'blog publication workflow', 'BlogEntry')
       
    79 
       
    80 At first, instanciate a new workflow object with a gentle description
       
    81 and the concerned entity types (this one can be a tuple for multiple
       
    82 value).
       
    83 
       
    84 .. sourcecode:: python
       
    85 
       
    86   submitted = wf.add_state(_('submitted'), initial=True)
       
    87   published = wf.add_state(_('published'))
       
    88 
       
    89 This will create two entities of type ``State``, one with name
       
    90 'submitted', and the other with name 'published'.
       
    91 
       
    92 ``add_state`` expects as first argument the name of the state you want
       
    93 to create and an optional argument to say if it is supposed to be the
       
    94 initial state of the entity type.
       
    95 
       
    96 .. sourcecode:: python
       
    97 
       
    98   wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
       
    99 
       
   100 This will create an entity of type ``Transition`` with name
       
   101 `approve_blogentry` which will be linked to the ``State`` entities
       
   102 created before.
       
   103 
       
   104 ``add_transition`` expects
       
   105 
       
   106   * as the first argument: the name of the transition
       
   107   * then the list of states on which the transition can be triggered,
       
   108   * the target state of the transition,
       
   109   * and the permissions
       
   110     (e.g. a list of user groups who can apply the transition; the user
       
   111     has to belong to at least one of the listed group to perform the action).
       
   112 
       
   113 .. sourcecode:: python
       
   114 
       
   115   checkpoint()
       
   116 
       
   117 .. note::
       
   118   Do not forget to add the `_()` in front of all states and transitions names while creating
       
   119   a workflow so that they will be identified by the i18n catalog scripts.
       
   120 
       
   121 In addition to the user groups (one of which the user needs to belong
       
   122 to), we could have added a RQL condition.  In this case, the user can
       
   123 only perform the action if the two conditions are satisfied.
       
   124 
       
   125 If we use an RQL condition on a transition, we can use the following variables:
       
   126 
       
   127 * `X`, the entity on which we may pass the transition
       
   128 * `U`, the user executing that may pass the transition
       
   129 
       
   130 
       
   131 .. image:: ../../images/03-transitions-view.en.png
       
   132 
       
   133 You can notice that in the action box of a BlogEntry, the state is now
       
   134 listed as well as the possible transitions for the current state
       
   135 defined by the workflow.
       
   136 
       
   137 The transitions will only be displayed for users having the right permissions.
       
   138 In our example, the transition `approve_blogentry` will only be displayed
       
   139 for the users belonging to the group `moderators` or `managers`.
       
   140 
       
   141 
       
   142 Two bits of warning
       
   143 ~~~~~~~~~~~~~~~~~~~
       
   144 
       
   145 We could perfectly use the administration interface to do these
       
   146 operations. It is a convenient thing to do at times (when doing
       
   147 development, to quick-check things). But it is not recommended beyond
       
   148 that because it is a bit complicated to do it right and it will be
       
   149 only local to your instance (or, said a bit differently, such a
       
   150 workflow only exists in an instance database). Furthermore, you cannot
       
   151 write unit tests against deployed instances, and experience shows it
       
   152 is mandatory to have tests for any mildly complicated workflow
       
   153 setup.
       
   154 
       
   155 Indeed, if you create the states and transitions through the user
       
   156 interface, next time you initialize the database you will have to
       
   157 re-create all the workflow entities. The user interface should only be
       
   158 a reference for you to view the states and transitions, but is not the
       
   159 appropriate interface to define your application workflow.