<< Common template issues  Example of wrapping workflow >> 

Custom workflows

One of the most powerful features of Exponential 3 is that you can create custom workflows. Workflow is a mechanism that makes it possible to customize or add new features to operations in Exponential. For example: add some additional actions to publish routing or some additional steps to view objects.

Workflows should be connected to defined Exponential operations with triggers (there are only two defined operations in the content module currently: "Read" and "Publish"). For each defined operation, the Exponential kernel tries to execute two triggers. One is activated before the actual operation body is executed and another is activated after that. A trigger is just a row stored in the database table eztrigger.

Table definition:

CREATE TABLE eztrigger (
  id int(11) NOT NULL auto_increment,
  name varchar(255),
  module_name varchar(200) NOT NULL default '',
  function_name varchar(200) NOT NULL default '',
  workflow_id int(11) default NULL,
  PRIMARY KEY  (id),
  UNIQUE KEY eztrigger_def_id (module_name,function_name,name)
) TYPE=MyISAM;

Field "name" is the name of the trigger, for example, "pre_publish" or "pre_read". The fields module_name and function_name are the names of module and function that the system will start executing the workflow for.

Understanding Operations

An operation is a sequence of functions and triggers which should be executed to make a full action like read or publish. For example, simple "read" operation (below) is just a sequence of "pre_read" trigger and "fetch-object" method.

$OperationList['read'] = array( 'name' => 'read',
                                'default_call_method' => array( 'include_file' => 'kernel/content/ezcontentoperationcollection.php',
                                                                'class' => 'eZContentOperationCollection' ),
                                'parameters' => array( array( 'name' => 'node_id',
                                                              'required' => true ),
                                                       array( 'name' => 'user_id',
                                                              'required' => true ),
                                                       array( 'name' => 'language_code',
                                                              'default' => '',
                                                              'required' => false ) ),
                                'keys' => array( 'node_id',
                                                 'user_id' ),

                                'body' => array( array( 'type' => 'trigger',
                                                        'name' => 'pre_read',
                                                        'keys' => array( 'node_id',
                                                                         'user_id'
                                                                         ) ),



                                                 array( 'type' => 'method',
                                                        'name' => 'fetch-object',
                                                        'frequency' => 'once',
                                                        'method' => 'readObject',
                                                        ) ) );

  • name - the name of the operation.
  • default_call_method - an array which shows in which file and class methods used in the operation are defined
  • parameters - parameters that are passed to each method and trigger in the operation when they are executed
  • keys - part of parameters that are used to identify stored interrupted operation (operation memento)
  • body - array of arrays that describe methods and triggers of the operation

Types of body elements:

Trigger:

  • type - trigger, shows that current body element is trigger
  • name - name of the trigger used to fetch trigger from database. To fetch the trigger, the system will use next conditions - (module name, operation name, trigger name)
  • key - part of the parameters used to identify running workflow process

Method:

  • type - method
  • name - fetch-object, name of method used in internals of operation
  • frequency - once, it means that method will be run only once
  • method - method of class described with "default_call_method" "class" parameter of operation. That function is the code which will be executed

Creating workflows

Workflows consist of a sequence of workflow events which will be executed one by one. Therefore, the first step is to create workflow event types. Alternatively, you can use events that already exist.

Creating new workflow event

Suppose that you want to create a workflow event which will show a "hello user" message to users after the workflow has run. We use hellouser as the name of the event. To create this new workflow event, you need to complete the following steps:

  1. modify site.ini settings to add the new workflow event type. You should add "event_hellouser" to the AvailableEventTypes parameter
  2. create directory kernel/classes/workflowtypes/event/hellouser/
  3. create file in that directory called hellousertype.php

File hellousertype.php
define( "EZ_WORKFLOW_TYPE_HELLO_USER_ID", "hellouser" );

class helloUserType extends eZWorkflowEventType
{
    /*!
     Constructor
    */
    function helloUserType()
    {
        $this->eZWorkflowEventType( EZ_WORKFLOW_TYPE_HELLO_USER_ID, "Hello User" );
    }

    function execute( &$process, &$event )
    {
        return EZ_WORKFLOW_TYPE_STATUS_ACCEPTED;
    }
}

eZWorkflowEventType::registerType( EZ_WORKFLOW_TYPE_HELLO_USER_ID, "hellousertype" );

This is a very simple workflow event type. To create a workflow event type we need to create a class inherited from eZWorkflowEventType and then register it into the system using the method eZWorkflowEventType::registerType(). This class should have at least one method in addition to the class constructor. The method execute is called when the workflow event is executed. The behaviour of running the workflow depends on the return value of this function.

Possible values
ValueDescription
EZ_WORKFLOW_TYPE_STATUS_ACCEPTED Workflow accepts that event, and run next event in workflow
EZ_WORKFLOW_TYPE_STATUS_REJECTED
EZ_WORKFLOW_TYPE_STATUS_WORKFLOW_CANCELLED
They have the same meaning currently. The workflow will be canceled.
EZ_WORKFLOW_TYPE_STATUS_DEFERRED_TO_CRON
EZ_WORKFLOW_TYPE_STATUS_DEFERRED_TO_CRON_REPEAT
This status means that execution of the workflow is deferred to the cron daemon. The difference between the first one and the second one is that the workflow will be executed from the next event in the first case and from the same event in the second case after finishing current running process.
EZ_WORKFLOW_TYPE_STATUS_FETCH_TEMPLATE
EZ_WORKFLOW_TYPE_STATUS_FETCH_TEMPLATE_REPEAT
The workflow engine should interrupt executing workflow and show page to the user. In case of this status, the workflow event should set up some internal variables. (Will be explaned below). Differences between them is the same as in the previous case.
EZ_WORKFLOW_TYPE_STATUS_REDIRECT
EZ_WORKFLOW_TYPE_STATUS_REDIRECT_REPEAT
Workflow engine should interrupt executing the workflow and redirect the user to a specified page. In case of this status the workflow event should set up some internal variables. (Will be explaned below). Differences between them is the same as in the previous cases.
EZ_WORKFLOW_TYPE_STATUS_NONE Undefined status. The same as EZ_WORKFLOW_TYPE_STATUS_REJECTED temporally.

To show a page to the user, you need to use the status EZ_WORKFLOW_TYPE_STATUS_FETCH_TEMPLATE and set up some internal variables.

    function execute( &$process, &$event )
    {

        $user =& eZUser::currentUser();
        $userName =& $user->attribute( 'login' );
        $localhostAddr = eZSys::hostname();
        $requestUri = eZSys::serverVariable( 'REQUEST_URI' );


        $process->Template = array( 'templateName' => 'design:workflow/eventtype/result/' . 'event_hellouser' . '.tpl',
                                     'templateVars' => array( 'return_uri' => $requestUri,
                                                              'user_name' => $userName ) );
        return EZ_WORKFLOW_TYPE_STATUS_FETCH_TEMPLATE;
    }

In addition, you need to create the result template.

<form action={$return_uri|ezurl} method="post" >

<div class="maincontentheader">
<h1>{"Hello"|i18n('workflow/eventtype/result/event_hellouser')} {$user_name}</h1>
</div>
<div class="buttonblock">
<input type="submit" name="Next" value="next" />
</div>

</form>

The workflow event is ready now and it is time to create the workflow. Click on 'Workflows' in the left menu and choose a defined group or just create a new one.

Class edit

then click "New workflow" button.

Class edit

Specify the workflow name first, and then you can add the "Event/Hello User" event to the workflow by selecting it from the dropdown list and clicking the "New Event" button.

Class edit

Simply click the store button after you have added the event.

Now the workflow is ready and you need to create a trigger. Go to the "Triggers" list (in the "Set up" menu box) and select the newly created workflow from the dropdown list on the content - read - before line.

Triggers

Click the "Store" button. The workflow is connected to the operation now.

Finally the workflow is ready and has been connected to the operation.


Exponential