This page contains a set of SimpleWorkflow snippets that you may have to deal with someday.
Initializing The SimpleWorkflowBehavior behavior
Don't be scared ! most of the time you will not have to use all the configuration settings like on the following example.
@app/models/Post.php
class Post extends \yii\db\ActiveRecord
{
public function behaviors()
{
return [
[
'class' => '\raoul2000\workflow\base\SimpleWorkflowBehavior',
// model attribute to store status
'statusAttribute' => 'col_status',
// workflow source component name
'source' => 'my_workflow_source',
'defaultWorkflowId' => 'MyWorkflow',
'statusConverter' => null,
'statusAccessor' => null,
// Event Sequence Component Name
'eventSequence' => 'eventSequence',
'propagateErrorsToModel' => false,
'stopOnFirstInvalidEvent' => true,
]
];
}
}
Initializing The WorkflowSource Component
Again, no worries ! Usually the default Workflow Source component will be just fine to use and you'll probably never have to create such a component.
@app/config/web.php
$config = [
'components' => [
'my_workflow_source' => [
'class' => 'raoul2000\workflow\source\file\WorkflowFileSource',
// Cache component name
'definitionCache' => 'cache',
// load workflow as PHP class from the @app/models/workflows namespace
'definitionLoader' => [
'class' => 'raoul2000\workflow\source\file\PhpClassLoader',
'namespace' => '@app/models/workflows'
],
// workflow provided by PHP class will be defined as a minimal array
'parser' => 'raoul2000\workflow\source\file\MinimalArrayParser',
// we provide our own implementation for simple workflow base objects
'classMap' => [
self::TYPE_WORKFLOW => 'my\custom\implementation\Workflow',
self::TYPE_STATUS => 'my\custom\implementation\Status',
self::TYPE_TRANSITION => 'my\custom\implementation\Transition'
]
],
// .. other app components here ..
]
];
Insert a Model in A Workflow
$post1 = new Post();
// the safe way : insert into default workflow (defaultWorkflowId)
$post1->enterWorkflow(); // the status change is done here
$post1->save();
$post2 = new Post();
// the safe way : insert into specific workflow
$post2->enterWorkflow('myWorkflow'); // the status change is done here
$post2->save();
// the not-so-safe way
$post3 = new Post();
$post3->status = 'Post/draft'; // must be initial status Id
$post3->save(); // the status change is done here
Getting The Current Status Of a Model
$post = Post::findOne(['id' => 42]);
if( $post->hasWorkflowStatus()) {
// the safe way
echo 'status id = ' . $post->getWorkflowStatus()->getId();
echo 'status label = ' . $post->getWorkflowStatus()->getLabel();
echo 'status color = ' . $post->getWorkflowStatus()->getMetadata('color');
// the not so safe way
echo 'status = ' . $post->status;
}
Changing Status
$post1 = Post::find(['id'=>42]);
// Two steps : assignment + call to save()
$post1->status = 'Post/published';
$post1->save(); // the status change is done here
$post2 = Post::find(['id'=>42]);
// One step : call to sendToStatus()
$post2->sendToStatus('Post/published'); // the status change is done here
$post->save();
Leaving A Workflow
$post1 = Post::find(['id'=>42]);
// Two steps : assignment + call to save()
$post1->status = null;
$post1->save(); // the status change is done here
$post2 = Post::find(['id'=>42]);
// One step : call to sendToStatus()
$post2->sendToStatus(null); // the status change is done here
$post->save();
Comparing Two Statuses
// the usual way : compare status ids
$post->getWorkflowStatus()->getId() == $otherPost->getWorkflowStatus()->getId();
// the lazy way
$post->statusEquals($otherPost->getWorkflowStatus());
Getting The WorkflowSource Used By A Model
$workflowSource = $post->getWorkflowSource();
Use a reference to the Workflow Source to access the workflow directly (not through the model).
Looping on all Next Statuses
ask the Status Object
$post = Post::find(['id'=>42]);
if( $post->hasWorkflowStatus()) {
// let's ask the Status object then
$transitions = $post
->getWorkflowStatus()
->getTransitions();
foreach( $transitions as $transition ) {
echo $transition->getEndStatus()->getId();
}
}
Through the Workflow Source
$post = Post::find(['id'=>42]);
if( $post->hasWorkflowStatus()) {
// ask the WorkflowSource
$transitions = $post
->getWorkflowSource()
->getTransitions($post->getWorkflowStatus()->getId());
foreach( $transitions as $transition ) {
echo $transition->getEndStatus()->getId();
}
}
Use the ChangeStatusAction
Since version 1.1.0 it is possible to change the workflow of a model using a Standalone Action ready to use in your controller. To do so you must declare the action and provide 2 callable variables :
findModel
: return the model from its idresponse
: customize the response
Here is an example of a controller class using the ChangeStatus action :
namespace app\controllers\workflow;
use Yii;
use yii\web\Controller;
use app\models\Post;
use yii\web\NotFoundHttpException;
class WorkflowController extends Controller
{
public function actions()
{
return [
'change' => [
'class' => 'app\actions\workflow\ChangeStatusAction',
'findModel' => [$this, 'findModel'],
'response' => [$this, 'response']
]
];
}
public function response($changedStatus, $model) {
return $changeStatus;
}
public function findModel($id)
{
if (($model = Post::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}