Message-ID: <965452482.3552.1485853617372.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_3551_535245329.1485853617363" ------=_Part_3551_535245329.1485853617363 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html How-to trigger a workflow using the Public API

How-to trigger a workflow using the Public API

The ContentService implemented in eZ Publish 5.x has no knowledg= e of the Legacy workflow engine. This means that all features in the 4.x se= ries that used workflows need a workaround. One of the most common use-case= s is pre-publishing approval, for instance of user generated content.

Le= gacy kernel callbacks

Fortunately, there is a quite simple way to trigg= er workflows from eZ Publish 5 code: by using a Legacy Kernel Callback. The= overall process is described in the  Legacy code and features<= /a> documentation chapter.

Create with the Public API, publish with the Lega= cy Kernel

Thanks to this, it is possible to create a draft using native eZ Publish= 5 code, and get this draft pre-approved using the legacy workflow & co= llaboration systems, including email notifications.

Legacy workflow configuration

Let's take an approval workflow as an example. It needs to be configured= the old way, using the backoffice. Create a workflow, add an Approve event to = it, and connect it to the content/publish/before trigger.

Create a draft using the public API

This is done the usual way, as extensively covered in the Public API Cookbook. The main dif= ferent is that we will NOT call ContentService::publishVersion()= .

Create content using the Public API
=20
$contentType =3D $contentTypeService->loadContentTypeByIdentifie=
r( $contentTypeIdentifier );

$contentCreateStruct =3D $contentService->newContentCreateStruct( $conte=
ntType, 'eng-GB' );
$contentCreateStruct->setField( 'title', $title );
$contentCreateStruct->setField( 'intro', $intro );
$contentCreateStruct->setField( 'body', $body );

$locationCreateStruct =3D $locationService->newLocationCreateStruct( $pa=
rentLocationId );


// create a draft using the content and location create struct and publish =
it
$draft =3D $contentService->createContent( $contentCreateStruct, array( =
$locationCreateStruct ) );

=20

Publish a Public API draft using the Legacy Kernel

 

You need to use the object to run a Legacy Kernel Callback (e.g. code fr= agment). This legacy code will execute the publish operation with the given= content id and version number. It will then check the operation result, an= d return true or false, depending if the operation went all the way through= , or if it was interrupted (approval workflow event, for instance). This ha= ndling could and should of course be enhanced, with error han= dling to begin with, but it doesn't change the core principle.

This example will work in any controller that extends eZ\Publ= ish\EzPublishCoreBundle\Controller:

=20
/**
 * @param $contentId
 * @param $versionId
 * @return bool true if the operation was completed, false if it was interr=
upted
 */
protected function runLegacyPublish( $contentId, $versionId, $runAsUserId =
=3D null )
{
    $legacyKernel =3D $this->getLegacyKernel();
    return $legacyKernel->runCallback(
        function () use ( $contentId, $versionId, $runAsUserId )
        {

            $db =3D \eZDB::instance();
            $transactionCounter =3D $db->transactionCounter();
            if ( $runAsUserId )
            {
                \eZUser::setCurrentlyLoggedInUser( \eZUser::fetch( $runAsUs=
erId ), $runAsUserId );
            }
            $operationResult =3D \eZOperationHandler::execute(
                'content', 'publish', array( 'object_id' =3D> $contentId=
, 'version' =3D> $versionId )
            );
            if ( ( array_key_exists( 'status', $operationResult ) &&=
; $operationResult['status'] !=3D \eZModuleOperationInfo::STATUS_CONTINUE )=
 )
            {
                // Required by https://jira.ez.no/browse/EZP-20558
                for ( $i =3D 0, $counter =3D ( $db->transactionCounter()=
 - $transactionCounter ); $i < $counter; ++$i )
                {
                    $db->commit();
                }
                return false;
            }
            return true;
        }
    );
}
=20

eZ Script context

If you are running the callback in a command line script, you need to ad= d these calls before executing any legacy code:

=20
$script =3D \eZScript::instance( array( 'use-modules' =3D> true =
) );
$script->initialize();
=20

 

Any Legacy code can be executed this way. While it is a backwar= d compatibility feature, it is considered good practice to work around= missing features. It is however not recommended to rely heavily on Legacy = features for performances reasons.

Pay attention to the user

Public API code is always executed as a user, by default anonymous. Sinc= e workflows are often user dependent (Approval is), it is important that th= is code is executed as an editor, or as a user who will trigger the workflo= w.

Logging in a user on the Public API repository
=20
$repository->setCurrentUser( $repository->getUserService()-&g=
t;loadUser( $userId ) );
=20

Of course, this isn't required when using Public API code in controllers= , since those will use the currently-logged in user.

Legacy code also requires a user

By default, code in LegacyKernel::runCallback() calls is ex= ecuted as anonymous. You'll have to log the executing user manually on = legacy as well.

Logging in a user with the Legacy Kernel
=20
\eZUser::setCurrentlyLoggedInUser( \eZUser::fetch( $runAsUserId ), =
$runAsUserId );
=20

 

Data compatibility and workflow collaboration

Content created using the Public API does appear as expected in the dash= board, and the draft can be checked from here. Collaboration options from t= he backoffice are available, and the object's lifecycle can be managed the = way it used to with eZ Publish 4.x.

Test script

The code below is a working Command script example that demonstrates the= workaround. Just drop it in a bundle and update the namespace: https://gist.github.com/bdunogier/e05ed564770fa6a51e51

------=_Part_3551_535245329.1485853617363--