To use *SimpleWorkflowBehavior* with the default parameters, simply attach it to the model class like you would do for any standard Yii2 behavior.
use raoul2000\workflow\base\SimpleWorkflowBehavior;

public function behaviors()
{
    return [
        'simpleWorkflow' => [
            'class' => SimpleWorkflowBehavior::className()
        ],
    ];
}
To learn more about Yii2 behaviors refer to the Yii2 Definitive Guide You can customize the *SimpleWorkflowBehavior* with the following parameters : - statusAttribute : name of the attribute that is used by the owner model to hold the status value. The default value is "status". - defaultWorkflowId : identifier of the default workflow for the owner model. If no value is provided, the behavior creates a default workflow identifier (see [[getDefaultWorkflowId]]). - source : name of the *Workflow Source Component* that the behavior uses to read the workflow definition. By default the component id "workflowSource" is used. If it is not already available in the current application it is created by the behavior using the default workflow source component class. Below is an example behavior initialization :
use raoul2000\workflow\base\SimpleWorkflowBehavior;

public function behaviors()
{
    return [
        'simpleWorkflow' => [
            'class' => SimpleWorkflowBehavior::className(),
            'statusAttribute' => 'col_status',
            'defaultWorkflowId' => 'MyWorkflow',
            'source' => 'myWorkflowSource',
        ],
    ];
}
Наследование: extends yii\base\Behavior
 /**
  * (non-PHPdoc)
  * @see \yii\base\Object::init()
  */
 public function init()
 {
     parent::init();
     if (!isset($this->containerId)) {
         throw new InvalidConfigException("Parameter 'containerId' is missing ");
     }
     if (!isset($this->visNetworkId)) {
         $this->visNetworkId = uniqid('vis_');
     }
     if (!isset($this->workflow)) {
         throw new InvalidConfigException("Parameter 'workflow' is missing ");
     }
     if ($this->workflow instanceof \yii\base\Model) {
         if (!\raoul2000\workflow\base\SimpleWorkflowBehavior::isAttachedTo($this->workflow)) {
             throw new InvalidConfigException("The model passed as parameter 'workflow' is not attached to a SimpleWorkflowBehavior.");
         }
         $this->_workflow = $this->workflow->getWorkflow();
         if ($this->_workflow == null) {
             $this->_workflow = $this->workflow->getWorkflowSource()->getWorkflow($this->workflow->getDefaultWorkflowId());
         }
     } elseif ($this->workflow instanceof \raoul2000\workflow\base\WorkflowInterface) {
         $this->_workflow = $this->workflow;
     }
     if ($this->_workflow == null) {
         throw new InvalidConfigException("Failed to find workflow instance from parameter 'workflow'");
     }
     $this->_visId = uniqid();
 }
 public function testAttachFails3()
 {
     $this->specify('the status attribute must exist in the owner model', function () {
         $model = new Item01();
         $model->detachBehavior('workflow');
         $model->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'statusAttribute' => 'not_found']);
     }, ['throws' => 'yii\\base\\InvalidConfigException']);
 }
 public function testConfiguredWorkflowId()
 {
     $this->specify('use the configured workflow Id', function () {
         $model = new Item01();
         $model->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'myWorkflow']);
         expect('model should have workflow id set to "myWorkflow"', $model->getDefaultWorkflowId() == 'myWorkflow')->true();
     });
 }
Пример #4
0
 public function testGetNextStatusFails()
 {
     $item = new Item04();
     $item->detachBehavior('workflow');
     $item->attachBehavior('workflowForTest', ['class' => SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'INVALID_ID']);
     $this->specify('getNextStatus throws exception if default workflow Id is invalid', function () use($item) {
         $this->setExpectedException('raoul2000\\workflow\\base\\WorkflowException', "Invalid workflow Id : 'INVALID_ID'");
         $item->getNextStatuses();
     });
 }
 protected function setup()
 {
     parent::setUp();
     $this->eventsBefore = [];
     $this->eventsAfter = [];
     Yii::$app->set('workflowSource', ['class' => 'raoul2000\\workflow\\source\\file\\WorkflowFileSource', 'definitionLoader' => ['class' => 'raoul2000\\workflow\\source\\file\\PhpClassLoader', 'namespace' => 'tests\\codeception\\unit\\models']]);
     Yii::$app->set('eventSequence', ['class' => 'raoul2000\\workflow\\events\\ReducedEventSequence']);
     $this->model = new Item04();
     $this->model->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className()]);
 }
 public function testConvertionOnLeaveWorkflow()
 {
     $item = new Item04();
     $item->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'statusConverter' => 'converter']);
     $this->assertEquals(null, $item->status);
     $this->assertEquals('Item04Workflow/B', $item->getWorkflowStatus()->getId());
     $this->specify('convertion is done when leaving workflow', function () use($item) {
         $item->sendToStatus(null);
         expect('item to not be in a workflow', $item->getWorkflow())->equals(null);
         expect('item to not have status', $item->hasWorkflowStatus())->false();
         expect('status attribut to be converted into 55', $item->status)->equals(55);
     });
 }
Пример #7
0
 public function testInitStatusAfterFindSuccess()
 {
     $this->specify('status initialisation when reading model from db (after find)', function () {
         $model = new Item01();
         $model->detachBehavior('workflow');
         $model->id = 1;
         $model->name = 'name';
         $model->status = 'Workflow1/B';
         $model->save(false);
         $model = Item01::findOne(1);
         $model->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'Workflow1']);
         verify('current model status is "B"', $model->getWorkflowStatus()->getId())->equals('Workflow1/B');
     });
 }
Пример #8
0
 public function testNoPropagateErrorToModel()
 {
     // prepare item instance
     $item = new Item00();
     $item->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'Item04Workflow', 'propagateErrorsToModel' => false]);
     $item->on(WorkflowEvent::beforeEnterStatus('Item04Workflow/B'), [$this, 'invalidateEvent']);
     $item->sendToStatus('Item04Workflow/A');
     verify('item is in status A', $item->getWorkflowStatus()->getId())->equals('Item04Workflow/A');
     verify('item has no error', $item->hasErrors())->false();
     // send to B
     $item->sendToStatus('B');
     expect('status is still A', $item->getWorkflowStatus()->getId())->equals('Item04Workflow/A');
     expect('item has no error', $item->hasErrors())->false();
 }
Пример #9
0
 public function testDefaultEventNotFired2()
 {
     // Default event is NOT fired when fireDefaultEvent is FALSE
     $this->model = new Item04();
     $this->model->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'eventSequence' => null, 'fireDefaultEvent' => false]);
     $this->model->on(SimpleWorkflowBehavior::EVENT_BEFORE_CHANGE_STATUS, function ($event) {
         $this->eventsBefore[] = $event;
     });
     $this->model->on(SimpleWorkflowBehavior::EVENT_AFTER_CHANGE_STATUS, function ($event) {
         $this->eventsAfter[] = $event;
     });
     $this->model->enterWorkflow();
     verify('current status is set', $this->model->hasWorkflowStatus())->true();
     expect('event handlers have NOT been called (before)', count($this->eventsBefore))->equals(0);
     expect('event handlers have NOT been called (after)', count($this->eventsAfter))->equals(0);
 }
Пример #10
0
 /**
  * Returns an associative array containing all statuses that can be reached by model.
  * 
  * 
  * @param BaseActiveRecord $model
  * @param boolean $validate when TRUE only those status with successfull attribute validation are included. When FALSE (default)
  * Attribute validation is done performed.
  * @param boolean $beforeEvents when TRUE all configured *before* events are fired : only the status that don't invalidate the
  * workflow event are included in the returned array, otherwise no event is fired and all next status are included 
  * @param boolean $includeCurrent when TRUE the current model status is added to the returned array. When FALSE (default)
  * only next statuses are included
  * @throws WorkflowException
  * @return array
  */
 public static function getNextStatusListData($model, $validate = false, $beforeEvents = false, $includeCurrent = false)
 {
     if (!SimpleWorkflowBehavior::isAttachedTo($model)) {
         throw new WorkflowException('The model does not have a SimpleWorkflowBehavior behavior');
     }
     $listData = [];
     if ($includeCurrent) {
         $currentStatus = $model->getWorkflowStatus();
         $listData[$currentStatus->getId()] = $currentStatus->getLabel();
     }
     $report = $model->getNextStatuses($validate, $beforeEvents);
     foreach ($report as $endStatusId => $info) {
         if (!isset($info['isValid']) || $info['isValid'] === true) {
             $listData[$endStatusId] = $info['status']->getLabel();
         }
     }
     return $listData;
 }
 public function testStopOnFirstInvalidEventFalse()
 {
     // prepare item instance
     $item = new Item00();
     $item->attachBehavior('workflowBehavior', ['class' => SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'Item04Workflow', 'propagateErrorsToModel' => true, 'stopOnFirstInvalidEvent' => false]);
     $item->on(WorkflowEvent::beforeLeaveStatus('Item04Workflow/A'), [$this, 'invalidateEvent1']);
     $item->on(WorkflowEvent::beforeEnterStatus('Item04Workflow/B'), [$this, 'invalidateEvent2']);
     verify('stopOnFirstInvalidEvent is true', $item->stopOnFirstInvalidEvent)->false();
     $item->sendToStatus('Item04Workflow/A');
     verify('item is in status A', $item->getWorkflowStatus()->getId())->equals('Item04Workflow/A');
     verify('item has no error', $item->hasErrors())->false();
     // send to B
     $item->sendToStatus('B');
     expect('status is still A', $item->getWorkflowStatus()->getId())->equals('Item04Workflow/A');
     expect('item has error', $item->hasErrors())->true();
     expect('1 error message is set for attribute "status"', count($item->getErrors('status')))->equals(2);
     $errorMessages = $item->getErrors('status');
     expect('First error message is "err_message_1" ', $errorMessages[0])->equals("err_message_1");
     expect('Second error message is "err_message_2" ', $errorMessages[1])->equals("err_message_2");
 }
Пример #12
0
 /**
  * Apply active validators for the current workflow event sequence.
  *
  * If a workflow event sequence is about to occur, this method scan all validators defined in the
  * owner model, and applies the ones which are valid for the upcomming events.
  *
  * @see \raoul2000\workflow\events\IEventSequence
  */
 public function validateAttribute($object, $attribute)
 {
     if (!SimpleWorkflowBehavior::isAttachedTo($object)) {
         throw new WorkflowException('Validation error : the model does not have the SimpleWorkflowBehavior');
     }
     try {
         $scenarioList = $object->getScenarioSequence($object->{$attribute});
     } catch (WorkflowException $e) {
         $object->addError($attribute, 'Workflow validation failed : ' . $e->getMessage());
         $scenarioList = [];
     }
     if (count($scenarioList) != 0) {
         foreach ($object->getValidators() as $validator) {
             foreach ($scenarioList as $scenario) {
                 if ($this->_isActiveValidator($validator, $scenario)) {
                     $validator->validateAttributes($object);
                 }
             }
         }
     }
 }
Пример #13
0
 public function behaviors()
 {
     return ['workflow' => ['class' => SimpleWorkflowBehavior::className()]];
 }
Пример #14
0
 /**
  * (non-PHPdoc)
  * @see \yii\base\Component::behaviors()
  */
 public function behaviors()
 {
     return ['w1' => ['class' => \raoul2000\workflow\base\SimpleWorkflowBehavior::className(), 'defaultWorkflowId' => 'Item08Workflow1'], 'w2' => ['class' => \raoul2000\workflow\base\SimpleWorkflowBehavior::className(), 'statusAttribute' => 'status_ex', 'defaultWorkflowId' => 'Item08Workflow2']];
 }
Пример #15
0
 public function behaviors()
 {
     return ['workflow' => ['class' => SimpleWorkflowBehavior::className(), 'statusAttribute' => 'statusAlias', 'statusAccessor' => 'status_accessor']];
 }
Пример #16
0
 /**
  * @expectedException raoul2000\workflow\base\WorkflowException
  * @expectedExceptionMessage failed to load workflow definition : Class tests\codeception\unit\models\NOTFOUND does not exist
  */
 public function testAutoInsertFails2()
 {
     $o = new Item00();
     $o->attachBehavior('workflow', ['class' => SimpleWorkflowBehavior::className(), 'autoInsert' => 'NOTFOUND', 'defaultWorkflowId' => 'Item04Workflow']);
 }
Пример #17
0
 /**
  * Checks if a given status is a valid transition from the current status
  *
  * @param BaseActiveRecord|SimpleWorkflowBehavior $model
  * @param string $status_id
  * @return bool
  */
 public static function isValidNextStatus($model, $status_id)
 {
     $eventSequence = $model->getEventSequence($status_id);
     foreach ($eventSequence['before'] as $event) {
         if ($model->hasEventHandlers($event->name)) {
             $model->trigger($event->name, $event);
             if ($event->isValid === false) {
                 return false;
             }
         }
     }
     return true;
 }