Git Product home page Git Product logo

yii2-workflow's Introduction

yii2-workflow

Build Latest Stable Version Total Downloads License

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist raoul2000/yii2-workflow "*"

or add

"raoul2000/yii2-workflow": "*"

to the require section of your composer.json file.

Quick Start

Configuration

For this "Quick start Guide" we will be using default configuration settings, but remember that yii2-workflow is designed to be highly flexible so to adapt to a lot of execution contexts... well at least that was my goal.

Create A Workflow

A workflow is defined as a PHP class that implements the \raoul2000\workflow\source\file\IWorkflowDefinitionProvider interface. which declares the getDefinition() method. This method must return an array representing the workflow definition.

Let's define a very simple workflow that will be used to manage posts in a basic blog system.

Here is the PHP class that implements the definition for our workflow :

@app/models/PostWorkflow.php

namespace app\models;

class PostWorkflow implements \raoul2000\workflow\source\file\IWorkflowDefinitionProvider
{
	public function getDefinition() {
		return [
			'initialStatusId' => 'draft',
			'status' => [
				'draft' => [
					'transition' => ['publish','deleted']
				],
				'publish' => [
					'transition' => ['draft','deleted']
				],
				'deleted' => [
					'transition' => ['draft']
				]
			]
		];
	}
}

Attach To The Model

Now let's have a look to our Post model: we store the status of a post in a column named status of type STRING(40).

The last step is to associate the workflow definition with posts models. To do so we must declare the SimpleWorkflowBehavior behavior in the Post model class and let the default configuration settings do the rest.

@app/models/Post.php

namespace app\models;
/**
 * @property integer $id
 * @property string $title
 * @property string $body
 * @property string $status column used to store the status of the post
 */
class Post extends \yii\db\ActiveRecord
{
    public function behaviors()
    {
    	return [
			\raoul2000\workflow\base\SimpleWorkflowBehavior::className()
    	];
    }
    // ...

That's it ! We are ready to play with SimpleWorkflowBehavior.

Use It !

Now that we are all setup, we can use the SimpleWorkflowBehavior methods to set/get the status of our posts : the SimpleWorkflowBehavior will take care that the post doesn't reach a status where it is not supposed to go to, depending on the workflow definition that we have provided.

$post = new Post();
$post->status = 'draft';
$post->save();
echo 'post status is : '. $post->workflowStatus->label;

This will print the following message :

post status is : Draft

If you do the same thing but instead of draft set the status to publish and try to save it, the following exception is thrown :

Not an initial status : PostWorkflow/publish ("PostWorkflow/draft" expected)

That's because in your workflow definition the initial status is set to draft and not publish.

Ok, one more example for the fun ! This time we are not going to perform the transition when the Post is saved (like we did in the previous example), but immediately, by invoking the sendToStatus method. Our Post is going to try to reach status publish passing through deleted which is strictly forbidden by the workflow. Will it be successful in this risky attempt to break workflow rules ?

$post = new Post();
$post->sendToStatus('draft');
$post->sendToStatus('deleted');
$post->sendToStatus('publish');	// danger zone !

Game Over ! There is no transition between deleted and publish, and that's what SimpleWorkflow tries to explain to our fearless post object.

Workflow Exception – raoul2000\workflow\base\WorkflowException
No transition found between status PostWorkflow/deleted and PostWorkflow/publish

Yes, that's severe, but there was many ways to avoid this exception like for instance by first validating that the transition was possible.

What's Next ?

This is just one way of using the SimpleWorkflowBehavior but there's much more and hopefully enough to assist you in workflow management inside your Yii2 web app.

You will find additional information there :

You may also be interested in the following projects developed around yii2-workflow :

License

yii2-workflow is released under the BSD 3-Clause License. See the bundled LICENSE.md for details.

Yii2

yii2-workflow's People

Contributors

bioxyz avatar cornernote avatar faryshta avatar marcoadasilvaa avatar michelezucchini avatar pappfer avatar raoul2000 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yii2-workflow's Issues

customize node shapes based on workflow

how to add shape or symbol in meta data in a workflow definition??
like....
class ProjTaskWorkflow implements IWorkflowDefinitionProvider
{
public function getDefinition() {

return [
'initialStatusId' => 'idle',

        'status' => [
            'idle' => [
                'label'      => 'Idle Stage',
                'transition' => ['design'],
				
                'metadata'   => [
				   
                   'color' => 'yellow',
	       'shape' => ['diamond'],
					
                ],
            ],
            'design' => [
                'transition' => ['idle','approve'],
                'metadata'   => [
                    'color' => 'grey',
	   ]
            ],
            'approve' => [
                'transition' => ['idle','design','start'],
                'metadata'   => [
                    'color' => 'blue'
                ]
            ],
            'start' => [
                'transition' => ['idle','devcomplete'],
                'metadata'   => [
                    'color' => 'green'
                ]                   
            ],
            'devcomplete' => [
                'transition' => ['idle','start','review'],
                'metadata'   => [
                    'color' => 'pink'
                ]                       
            ],
			'review' => [
                'transition' => ['idle','start','testing'],
                'metadata'   => [
                    'color' => 'orange'
                ]                       
            ],
			
			'testing' => [
                'transition' => ['start','finished'],
                'metadata'   => [
                    'color' => 'blue'
                ]                       
            ],
	'finished' => [
                
                'metadata'   => [
                    'color' => 'violet'
                ]                       
            ]
			
        ]
       	
       
		
    ];
}

}

unsure how to recheck a Workflow rule on value change

Hi,

This probably isn't a bug, probably more of a dumb user question, sorry if this isn't the place to post...been reading http://raoul2000.github.io/yii2-workflow/overview/ and playing with setting a rule like this:

['teststring','required',
        'on' => 'from {myworkflowid/draft} to {myworkflowid/correction}'     
        ]

This works great, it throws an error when 'teststring' is null and I try to change the status to correction.

But the issue I have is that AFTER i have added something into teststring and successfully changed to a correction status I can then re-edit the teststring field, delete the value setting it back to null and it allows me to save with no error.

Is there some way to deal with this? either role it back to a draft or prevent them from updating, e.g recheck the rule on update that has no status change. I suspect the issue is:
'on' => 'from {myworkflowid/draft} to {myworkflowid/correction}'

only runs when a status is actually transitioning but I can't seem to see another WorkflowValidator that seems to cover both scenarios. http://raoul2000.github.io/yii2-workflow/concept-events/ doesn't list any that seem to apply.

So it leaves me wondering if I have to sort of duplicate the rule/scenario? e.g have something like:


public function rules(){
  return [
  ['teststring','required',
     'on' => 'from {myworkflowid/draft} to {myworkflowid/correction}' 
   ],
   ['teststring','required','on' =>'myworkflowid/correction']
   ]
}

Thanks

Ben

Question about afterEnterStatus Event

Hello, from what I understand, the event afterEnterStatus run before model safe this is correct?

For example, i have a relation model: Order and OrderItem in status draft i can add items and the end of the form have a list of the following status.

If the order enter to status budget send me email witch list of items, but if i change one item, send me the previous version of this list.

My order to save data:

  • OrderItem
  • Order
  • Order sendToStatus

thanks for you attention

Call to undefined method ::attach()

Hello,

I was using your workflow plugin with Yii1, and now I'm trying to move on yii2.

I updated my model and Workflow description, but I'm receiving an error:

Call to undefined method app\models\workflows\InternalWorkflow::attach() in /app/vendor/yiisoft/yii2/base/Component.php at line 672

Any idea?

Attach two workflow to a model

It is possible, to attach two different workflow to a model stored in two attributes?
I have this error
Not a valid status id : incorrect status local id format in 'MY_STATUS_VALUE'
and don't understand why.

Model attribute value

@raoul2000,

First of all, bravo and thanks for this amazing workflow engine.
Really cool.

I read everything I found about WorkflowDbSource. Very interesting.
A lot of tips and good examples.

I wonder if there is a way to get a dynamic workflow definitions for a model according to its type.
I am after something like a task_type which will provide a json encoded workflow rules to be used per task. Meaning definitions would be stored in the task type table.
Any tips or suggestion would be welcome.
In advance thanks

Question: A model can have various Workflows?

Saludos raoul, estaba evaluando la posibilidad de que un modelo posee 2 tipos de workflow. A modo de pruebas agregue 2 veces en behaviors la declaración de Workflow, en consecuencia los events comenzaron a ejecutarse 2 veces.

Por lo tanto te consulto si es factible agregar 2 workflows distintos a un mismo modelo y cual seria la aplicación adecuada?

Agradecido!


Hello raoul!
Was evaluating the possibility that a model has 2 types of workflow. But, for tests i add twice in behaviors the declaration of Workflow, consequently the events execute twice also.

it is possible add 2 different workflows on the same model and what would be appropriate configuration?

I have a few question if you would

Can the workflow manager page be integrated, relatively easily, into other pages instead of the default workflow page it comes with? Ideally it would be integrated with our admin panel.

In terms of each status. Let's say there's a draft, ready, published, deleted state (going off of the example provided). How does that affect the actual item? Using a blog as an example, obviously you would only want to display an article after it's been published. Would the workflow table have to be queried for the status or as it goes through the workflow a column on the actual table would be updated with it's status?

In terms of referencing a workflow item, if an editor leaves comments when sending an article back to the draft state, how easy is it to reference the workflow item?

Sorry if these questions are answered somewhere in the docs and I just missed it. It seems flexible enough and it's stated in the docs if needed it can be extended to add additional functionality. It seems to do the bulk of what we would like, so if we can use this as a base instead of recreating the wheel that would be preferable.

Issues loading graphml file

Thank you for your hard work.

I am trying to load a graphml file and receive a "failed to extract id for attribute n-label".

The graphml file is below

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
  <!--Created by yEd 3.14.2-->
  <key attr.name="initialStatusId" attr.type="string" for="graph" id="d0">
    <default><![CDATA[DRAFT
]]></default>
  </key>
  <key for="port" id="d1" yfiles.type="portgraphics"/>
  <key for="port" id="d2" yfiles.type="portgeometry"/>
  <key for="port" id="d3" yfiles.type="portuserdata"/>
  <key attr.name="url" attr.type="string" for="node" id="d4"/>
  <key attr.name="description" attr.type="string" for="node" id="d5"/>
  <key for="node" id="d6" yfiles.type="nodegraphics"/>
  <key for="graphml" id="d7" yfiles.type="resources"/>
  <key attr.name="url" attr.type="string" for="edge" id="d8"/>
  <key attr.name="description" attr.type="string" for="edge" id="d9"/>
  <key for="edge" id="d10" yfiles.type="edgegraphics"/>
  <graph edgedefault="directed" id="G">
    <node id="n0">
      <data key="d5"><![CDATA[Article is in draft]]></data>
      <data key="d6">
        <y:GenericNode configuration="com.yworks.flowchart.start1">
          <y:Geometry height="40.0" width="80.0" x="230.0" y="-50.0"/>
          <y:Fill color="#E8EEF7" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.876953125" x="18.5615234375" y="10.93359375">DRAFT<y:LabelModel>
              <y:SmartNodeLabelModel distance="4.0"/>
            </y:LabelModel>
            <y:ModelParameter>
              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
            </y:ModelParameter>
          </y:NodeLabel>
          <y:StyleProperties>
            <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="false"/>
          </y:StyleProperties>
        </y:GenericNode>
      </data>
    </node>
    <node id="n1">
      <data key="d5"/>
      <data key="d6">
        <y:GenericNode configuration="com.yworks.flowchart.start1">
          <y:Geometry height="40.0" width="80.0" x="50.0" y="100.0"/>
          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="66.478515625" x="6.7607421875" y="10.93359375">PUBLISHED<y:LabelModel>
              <y:SmartNodeLabelModel distance="4.0"/>
            </y:LabelModel>
            <y:ModelParameter>
              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
            </y:ModelParameter>
          </y:NodeLabel>
        </y:GenericNode>
      </data>
    </node>
    <node id="n2">
      <data key="d5"/>
      <data key="d6">
        <y:GenericNode configuration="com.yworks.flowchart.start1">
          <y:Geometry height="40.0" width="80.0" x="410.0" y="100.0"/>
          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="73.28125" x="3.359375" y="10.93359375">SCHEDULED<y:LabelModel>
              <y:SmartNodeLabelModel distance="4.0"/>
            </y:LabelModel>
            <y:ModelParameter>
              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
            </y:ModelParameter>
          </y:NodeLabel>
        </y:GenericNode>
      </data>
    </node>
    <node id="n3">
      <data key="d5"/>
      <data key="d6">
        <y:GenericNode configuration="com.yworks.flowchart.start1">
          <y:Geometry height="40.0" width="80.0" x="50.0" y="220.0"/>
          <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" width="1.0"/>
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="51.185546875" x="14.4072265625" y="10.93359375">EXPIRED<y:LabelModel>
              <y:SmartNodeLabelModel distance="4.0"/>
            </y:LabelModel>
            <y:ModelParameter>
              <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
            </y:ModelParameter>
          </y:NodeLabel>
        </y:GenericNode>
      </data>
    </node>
    <edge id="e0" source="n0" target="n1">
      <data key="d9"/>
      <data key="d10">
        <y:PolyLineEdge>
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
          <y:LineStyle color="#000000" type="line" width="1.0"/>
          <y:Arrows source="none" target="standard"/>
          <y:BendStyle smoothed="false"/>
        </y:PolyLineEdge>
      </data>
    </edge>
    <edge id="e1" source="n0" target="n2">
      <data key="d9"/>
      <data key="d10">
        <y:PolyLineEdge>
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
          <y:LineStyle color="#000000" type="line" width="1.0"/>
          <y:Arrows source="none" target="standard"/>
          <y:BendStyle smoothed="false"/>
        </y:PolyLineEdge>
      </data>
    </edge>
    <edge id="e2" source="n2" target="n1">
      <data key="d9"/>
      <data key="d10">
        <y:PolyLineEdge>
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
          <y:LineStyle color="#000000" type="line" width="1.0"/>
          <y:Arrows source="none" target="standard"/>
          <y:BendStyle smoothed="false"/>
        </y:PolyLineEdge>
      </data>
    </edge>
    <edge id="e3" source="n1" target="n3">
      <data key="d9"/>
      <data key="d10">
        <y:PolyLineEdge>
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
          <y:LineStyle color="#000000" type="line" width="1.0"/>
          <y:Arrows source="none" target="standard"/>
          <y:BendStyle smoothed="false"/>
        </y:PolyLineEdge>
      </data>
    </edge>
    <edge id="e4" source="n3" target="n1">
      <data key="d9"/>
      <data key="d10">
        <y:PolyLineEdge>
          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
          <y:LineStyle color="#000000" type="line" width="1.0"/>
          <y:Arrows source="none" target="standard"/>
          <y:BendStyle smoothed="false"/>
        </y:PolyLineEdge>
      </data>
    </edge>
  </graph>
  <data key="d7">
    <y:Resources/>
  </data>
</graphml>

Endstate with no transitions throws an error

Hi @raoul2000 ,

raoul2000\workflow\base\WorkflowValidationException: One or more end status are not defined : [
    0 => ‘PostWorkflow/archived’
] in /var/www/app/vendor/raoul2000/yii2-workflow/src/source/file/WorkflowArrayParser.php:85

Take the use case in your examples but add the requirement of a business rule that once an article is archived, it is never re-used in any form therefore no transitions can be made from the archived node.

It seems that the simple workflow does not accept an end state that has no transitions?
How can I address this use case or am I doing something fundamentally wrong?

Thanks

Two workflow in a model - disable validation between the two statuses

I have problem validating the status attribute of two workflow attached to a model.

Saving the model it try to validate the passage from status of workflow 1 (STATO attribute) to status of workflow 2 (STATO_INTERNO attribute), the error is:
{"STATO_INTERNO":["Workflow validation failed : No transition found between status DomandeWorkflow/VALIDATA and DomandeWorkflowBackoffice/DALAVORARE"]}

How I can not validate passage from a workflow to another?

Unsafe attributes

How can I declare an attribute as unsafe? That means it can be massively assigned using the Model::load() method.

Regulary if I want the 'paymet_method' to only be asigned during 'select-payment'. The code looks like this.

public function rules()
{
    return [['!payment_method'], 'safe', 'except' => 'select-payment'];
}

Unfortunately workflow makes its own behaviors and they won't work during the load() execution

public function rules()
{
    return [['!payment_method'], 'safe', 'except' => WorkflowScenario::enterStatus('select-method')];
}

This one won't work since the scenario only exists during transitions, not during loading.

Preserve event status (isValid) set by other componets

In order to preserve how $event->isValid value setted by others componets/behaviours, it's better to change:

public function beforeSaveStatus($event)
{
	$event->isValid = $this->sendToStatusInternal($this->getOwnerStatus(), true);
}

public function beforeDelete($event)
{
	$event->isValid = $this->sendToStatusInternal(null, true);
}

to

$event->isValid&= $this->......

In my situation, i have a softdelete behaviour that set $event->isValid to FALSE to preserve the record, but SimpleWorkflowBehavior set it to TRUE!

And the record was really deleted..

Was it the best way to solve this problem?

Gridview filter dropdown

Hello,

On my index page, I have a GridView widget, using an ActiveDataProvider object (from ->search() )
So I don't have any model object.
So, I did a bit of 'hack' to get the full list of statues:

$model = MyModel::find()->one();
	$allStatuses = WorkflowHelper::getAllStatusListData(
	 	$model->getWorkflow()->getId(),
	 	$model->getWorkflowSource()
	);

GridView::widget([
	'dataProvider' => $dataProvider,
	'filterModel' => $searchModel,
	'columns'=>[
		[
			'attribute' => 'status',
			'filter' =>$allStatuses,
		]
]
]);


Is there a better way to generate the dropdown filter menu that this?

Thanks

dynamic maps for status conversion

I've been having a solid play with status conversion. I'm implementing work flows into an existing table and can't change the status strings - so conversions looked good

However, I believe it's not possible to dynamically assign the conversion map.

What I want to do is have the behaviour provide the map so I can iterate over my existing status strings and generate the mapping

However, I can't find a way to write to the map once the status conversion component is loaded

Is this the expected behaviour?

If so, I'd there any way to write to the map after component instantiation?

null not being handled properly in combination with setmap

I am calling setMap() as below

        $this->registerWorkFlowEvents();

        $map = array();

        $converter = Yii::$app->get('statusConverter');

        foreach (self::$state as $state) {
            $map[$this->collectionName() . '/' . $state] = $state;
        }

        $map['null'] = 1;
        $converter->setMap($map);

which is providing me the following map

Array
(
    [article/DRAFT] => DRAFT
    [article/PUBLISHED] => PUBLISHED
    [article/EXPIRED] => EXPIRED
    [article/SCHEDULED] => SCHEDULED
    [article/MODERATED] => MODERATED
    [null] => 1
)

However, Im seeing the following

Exception 'yii\base\Exception' with message 'Conversion to SimpleWorkflow failed : no value found for id = null'

in /vagrant/app/vendor/raoul2000/yii2-workflow/src/base/StatusIdConverter.php:105

Stack trace:
#0 /vagrant/app/vendor/raoul2000/yii2-workflow/src/base/SimpleWorkflowBehavior.php(863): raoul2000\workflow\base\StatusIdConverter->toSimpleWorkflow(NULL)
#1 /vagrant/app/vendor/raoul2000/yii2-workflow/src/base/SimpleWorkflowBehavior.php(308): raoul2000\workflow\base\SimpleWorkflowBehavior->getOwnerStatus()
#2 /vagrant/app/vendor/raoul2000/yii2-workflow/src/base/SimpleWorkflowBehavior.php(248): raoul2000\workflow\base\SimpleWorkflowBehavior->initStatus()

I have tried all combination of null, ' null', NULL, 'NULL' etc, with the same results

The check on line 100

if ($id === null) {
            $id = self::VALUE_NULL;
        }

Leads me to think that if I pass in NULL, or null, then $id gets replaced. then line 103

        $statusId = array_search($id, $this->_map);

tried to find a matching entry in $map.

As I already have null in $map, I would assume this would return a value of 1, but rather it throws on line 121.

any ideas ?

Use foreign key column as attribute

Hi there!
I was wondering if yii2-workflow supports foregin key column as workfow attribute, cause I'm using a related model to manage statuses dynamically, so instead 'status' col would be 'status_id'

Thanks!

Different namespace and workflow history?

  1. When I use another namespace

namespace backend\models

I get error. (Expected app\models on my PostWorkflow class)

  1. Can I see workflow history? When and who changed status?

Bug in validation

I'm doing GUI for workflow and about to finish it. Workflow is working great with me except I found a bug. In creating new record page, if the user change the status using developer tools in chrome and make the value of status empty. The validation of workflow dose not catch it.

screen shot 2015-03-28 at 12 40 42 am

missing EVENT_*_CHANGE_STATUS when autoInsert is true on ActiveRecord insert

using autoInsert => true in SimpleWorkflowBehavior when ActiveRecord is inserted events EVENT_*_CHANGE_STATUS are not fired.
As described in Generic Events section of the manual I'm expecting the following events:
getStartStatus() == null && getEndStatus() != null : the model is entering into the workflow
getStartStatus() =! null && getEndStatus() != null : the model is changing status
getStartStatus() == null && getEndStatus() == null : the model is leaving into the workflow

It only works when autoInsert is false and I manually sendToStatus() my AR to Initial status ID in beforeSave() function.

validation when not changing status

    public function rules()
    {
        return [
            [['status'],raoul2000\workflow\validation\WorkflowValidator::className()],
            [['published_date'],'required',
                'on' => 'enter status {post/published}'],
        ];
    }

When I change to status=published I require published_date.

However once it's in published, there is no validation unless the status changes again.

It would be nice if I could say published_date was required if status=published (or if the status is in a given list). Is there any easy way to do this without making a custom validator?

Change state by timeout

Hello! How to change state by this rule: If the Post is not published after 10 days after save, then assign the status of "archive" ?

keep status updated problem (not an issue, just desperate for your help)

Hi, before all thanks for this extension. You did great job.
I am having some problem with the status current id.
Every time i save the model and start the workflow, things goes ok, but when i try the sendToStatus to make a second transition, it doesn't recognize the last initial status and asks for it again.
What i am missing from your guide, here?
Best regards

when invalidating a status change, where does the message go to?

I have the following event:

    public static function beforeEnterProduction($event)
    {
        /** @var \app\models\Job $job */
        $job = $event->sender->owner;
        if ($job->company->status == 'company/suspended') {
            $message = Yii::t('app', 'Cannot change Status to Production, the company is suspended.');
            $event->invalidate($message);
        }
    }

I would like to output this message somewhere, but I can't seem to find where it goes.

Model inheritance

Hello,
First of all, thanks for your awesome package, I've been using it since Yii1.

I have few similar models, named Archive1, Archive2...

class Archive1 extends  Archive
{
	public static function tableName()
	{
		return '{{%archive1}}';
	}
...

I'm using a common base for each named Archive, where I've added the workflow behaviour.

class Archive extends ActiveRecord
{
	public function behaviors()
	{
		return [
			[
				'class' => SimpleWorkflowBehavior::className(),
                'defaultWorkflowId'        => 'Archive',
			]
		];   
	}

My Workflow looks like:

class ArchiveWorkflow implements IWorkflowDefinitionProvider
{
	public function getDefinition() {
		return [
			'initialStatusId' => 'draft',
			'status' => [
				'draft' => [
					'transition'=>['submitted'],
					'label'=>'Draft',
				],
				'submitted' => [
					'transition'=>[],
					'label'=>'Submitted',
				]
			]
		];
	}
}

When I try to save the model...

$model = new Archive1;
$model->status = 'draft';
$model->save();

...I get the following error:

Invalid Configuration – yii\base\InvalidConfigException
The table does not exist: {{%archive}}

Looks like the workflow is trying to use the workflow name 'Archive' as table name, instead of the model name.

Is there a way to override that?

Thanks for your help.

Visualisation of Workflow Definition

Hi,

have you ever thought about a simple "Widget" that shows a visualisation of the Workflow definition?

Would love to implement something so a user can see in which state of the workflow he is and what would be the next options for him....

yii2 advanced template does not exist \bower/vis/dist

After have installed the widget and have used the code,
the bower file cannot be linked

The file or directory to be published does not exist: C:\xampp\htdocs\cis.wkt/vendor\bower/vis/dist

(ERROR this bug is for workflow view)

force model to be a given status

I have a use case where I need to bypass the workflow and directly set the status. I can't seem to find a method to do this. Is there any existing way to achieve this?

Event on enter workflow

Hello,

I use SimpleWorkflowBehavior::EVENT_AFTER_CHANGE_STATUS
To trigger an action when my workflow status changes.

But this event is not triggered when my model enters the workflow using

$model->enterWorkflow();

Is there an event that I can use,like
afterEnterWorkflow{MyWorkflow}

Thanks

problem caused by running the beforeEvents when running getNextStatuses()

The problem is a little complex, but I'll do my best to try to simplify it.

I want to get a list of the next statuses, running the beforeEvents to ensure they are allowed.

The flow is:

  • unit/despatch
  • unit/packed (current status)
  • unit/collected (I want to move here, but only allowed if there is a package that is collected)
$unit = Unit::findOne(1);
// the following are just to show what's already assigned to some variables:
// $unit->status = 'unit/packed'
// $unit->package->collected = 1

// valid transitions from here should be: unit/despatch and unit/collected,
// however only unit/despatch is returned
$nextStatuses = array_keys($unit->getNextStatuses(false, true));
// the above function call triggers the two methods below to run

It should be allowed to move to unit/collected, because it has a $unit->package->collected=1, however because all the before events are triggered, the $unit->package_id is unset by the first method, therefore the second method can't detect that the package is collected and then invalidates the event.

class UnitWorkflow
{
    public static function beforeLeave_packed($unit, $event)
    {
        // if we move to despatch then unset the package
        if ($event->getEndStatus()->getId() == 'unit/despatch') {
            $unit->package_id = null;
        }
    }
    public static function beforeEnter_collected($unit, $event)
    {
        // we only allow moving to collected if the package is collected
        // the problem is the $unit->package is now empty due to the last check
        if (!$unit->package || !$unit->package->collected) {
            $event->invalidate('The package is not collected.');
        }
    }
}

Perhaps internally in getNextStatuses() you should clone the object.

Or perhaps I shouldn't be using the beforeLeave events to manipulate the model's attributes, and should instead be doing it in the model's beforeSave().

Let me know your thoughts... if this even makes sense. :)

performance question

Hello @raoul2000,

I used your simpleWorkflow extension for a Yii1 application I developed a few years back. Overall I was really impressed with your work, however it did seem like it added a performance hit when dealing with many models. I don't have any actual benchmark data to back this up as it was something that kind of crept up on me.

The use case was complex, but let me give you an example of some of the transition callbacks that were used...

There are 5 models in a kind of chain:

Job < Item < Unit > Package > Pickup

  • Job hasmany Item
  • Item belongsto Job & hasmany Unit
  • Unit belongsto Item & belongsto Package
  • Package hasmany Unit & belongsto Pickup
  • Pickup hasmany Package

The chain works like this (as a simple example):

  • Pickup - on status change to Done - changes related Packages to Done
  • Package - on status change to Done - changes related Units to Done
  • Unit - on status change to Done - changes related Item to Done (but only if all Units in the Item are Done)
  • Item - on status change to Done - changes related Job to Done (but only if all Items in the Job are Done)

If you then change the Pickup to be a status other than Done it has to again work it's way through the chain to eventually change the Job to not be Done.

There is more to it than this, but it gives you an overview of the number of models I could be dealing with in a single status change. Basically one status change could lead to dozens (or sometimes hundreds) of models being loaded.

The same app is now being redeveloped in Yii2 and I am considering using your yii2-workflow extension, however my primary hesitation is the performance hit that it may incur. I looked at cebe's lifecycle behavior, and it looked very light, but also a little too simple for the task at hand. The extension seems very feature rich, but this comes with complexity, and probably a performance hit.

I was wondering what your thoughts were on performance of yii2-workflow compared to simpleWorkflow.

Thanks again for sharing this great extension!

Extend Workflow Exception!

Hello , I want to change the way of displaying Workflow Exception. How can I extend this class??

thank you

ChangeStatusAction.php

Just a question.
Why in this action you are using sendToStatus and then $model->save()?
In this way if model has WorkflowValidator it doesn't validate... transition has already done so validator can't reach any scenarios.

Thanks

WorkflowDbSource

Hi! I would like a WorkflowDbSource class. Which files should extend according to best practice?

Thanks.

cebe lifecycle behaviour?

Did you see this yii2 extension, maybe you can use some of the behaviour on your side too and attach the events?

Cheers Philipp

Error Exception:

Hello, thanks for this contribution.

i'm trying implement a workflow with model Proveedor, but return Interface 'raoul2000\workflow\base\IWorkflowDefinitionProvider' not found

Model ProveedorWorkflow.php

<?php
namespace app\models;

class ProveedorWorkflow implements \raoul2000\workflow\base\IWorkflowDefinitionProvider 
{
    public function getDefinition() {
        return [
            'initialStatusId' => 'draft',
            'status' => [
                'draft' => [
                    'transition' => ['publish','deleted']
                ],
                'publish' => [
                    'transition' => ['draft','deleted']
                ],
                'deleted' => [
                    'transition' => ['draft']
                ]
            ]
        ];
    }
}

Model Proveedor

class Proveedor extends \yii\db\ActiveRecord
{

    public function behaviors()
    {
        return [
            \raoul2000\workflow\base\SimpleWorkflowBehavior::className()
        ];
    }
...

Migrate to yii3

Hi, as your component is the absolute best for implementing workflows within yii - do you plan to migrate it to yii3 - or maybe you appreciate support for the port? Or maybe I can sponsor you to migrate it (with beer, wine or anything else ;)

where to change namspace

failed to load workflow definition : Class app\models\ProspectingWorkflow does not exist

as the namespace should be app\modules\prospecting\ProspectingWorkflow

I see you have an option inside WorkflowSource.php but where to "setup" ?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.