├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .php_cs ├── .travis.yml ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── composer.json ├── docker-compose.yml.dist ├── docker ├── Dockerfile └── php.ini.dist ├── docs └── quick-start-guide.md ├── phpunit.xml ├── src ├── Definition │ ├── Bpmn2File.php │ ├── Bpmn2Reader.php │ ├── Bpmn2WorkflowRepository.php │ ├── ErrorToExceptionContext.php │ ├── IdAttributeNotFoundException.php │ └── ProcessDefinitionRepository.php ├── Persistence │ ├── Base64PhpWorkflowSerializer.php │ ├── PhpWorkflowSerializer.php │ ├── WorkflowSerializableInterface.php │ └── WorkflowSerializerInterface.php ├── Process │ ├── EventContext.php │ ├── EventContextInterface.php │ ├── Process.php │ ├── ProcessAwareInterface.php │ ├── ProcessContextInterface.php │ ├── WorkItemContext.php │ ├── WorkItemContextInterface.php │ ├── WorkflowAwareInterface.php │ ├── WorkflowContextInterface.php │ └── WorkflowNotFoundException.php ├── Resources │ └── config │ │ └── workflower │ │ └── schema │ │ ├── BPMN20.xsd │ │ ├── BPMNDI.xsd │ │ ├── DC.xsd │ │ ├── DI.xsd │ │ └── Semantic.xsd └── Workflow │ ├── AccessDeniedException.php │ ├── Activity │ ├── AbstractTask.php │ ├── ActivityInterface.php │ ├── CallTask.php │ ├── ManualTask.php │ ├── OperationalTask.php │ ├── ProcessTask.php │ ├── SendTask.php │ ├── ServiceTask.php │ ├── SubProcessTask.php │ ├── Task.php │ ├── UnexpectedActivityException.php │ ├── UnexpectedActivityStateException.php │ ├── UnexpectedWorkItemStateException.php │ ├── UserTask.php │ ├── WorkItem.php │ └── WorkItemInterface.php │ ├── ActivityLog.php │ ├── ActivityLogCollection.php │ ├── Connection │ └── SequenceFlow.php │ ├── Element │ ├── ConditionalInterface.php │ ├── ConnectingObjectCollection.php │ ├── ConnectingObjectInterface.php │ ├── FlowObject.php │ ├── FlowObjectCollection.php │ ├── FlowObjectInterface.php │ ├── Token.php │ ├── TransitionalInterface.php │ └── WorkflowElementInterface.php │ ├── Event │ ├── EndEvent.php │ ├── Event.php │ ├── EventInterface.php │ ├── StartEvent.php │ └── TerminateEndEvent.php │ ├── Gateway │ ├── ExclusiveGateway.php │ ├── Gateway.php │ ├── GatewayInterface.php │ ├── InclusiveGateway.php │ └── ParallelGateway.php │ ├── ItemInterface.php │ ├── ItemsCollectionInterface.php │ ├── Operation │ ├── OperationRunnerInterface.php │ └── OperationalInterface.php │ ├── Participant │ ├── LoggedParticipant.php │ ├── OperationNotSupportedException.php │ ├── ParticipantInterface.php │ ├── Role.php │ ├── RoleAwareInterface.php │ └── RoleCollection.php │ ├── ProcessDefinition.php │ ├── ProcessDefinitionInterface.php │ ├── ProcessDefinitionRepositoryInterface.php │ ├── ProcessInstance.php │ ├── ProcessInstanceInterface.php │ ├── ProcessInstancesCollection.php │ ├── Provider │ ├── DataNotFoundException.php │ ├── DataProviderInterface.php │ └── ProviderNotFoundException.php │ ├── Resource │ ├── MessageInterface.php │ └── ResourceInterface.php │ ├── SequenceFlowNotSelectedException.php │ ├── WorkItemsCollection.php │ └── WorkflowRepositoryInterface.php └── tests ├── Definition └── Bpmn2ReaderTest.php ├── Resources └── config │ └── workflower │ ├── CallActivity.bpmn │ ├── InclusiveGateway.bpmn │ ├── LoanRequestProcess.bpmn │ ├── MultipleEndEvents.bpmn │ ├── NoLanesProcess.bpmn │ ├── ParallelGatewayProcess.bpmn │ ├── ParallelSequenceFlows.bpmn │ ├── ParallelUserTasks.bpmn │ ├── SendTasksProcess.bpmn │ ├── SequentialUserTasks.bpmn │ ├── ServiceTasksProcess.bpmn │ └── SubProcess.bpmn ├── Workflow ├── ProcessInstanceTest.php └── WorkflowRepository.php └── bootstrap.php /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ------------- | --- 3 | | Branch? | master for new features / 1.4 for fixes 4 | | Bug fix? | yes/no 5 | | New feature? | yes/no 6 | | BC breaks? | yes/no 7 | | Deprecations? | yes/no 8 | | Tests pass? | yes/no 9 | | Fixed tickets | comma-separated list of tickets fixed by the PR, if any 10 | | License | BSD-2-Clause 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.buildpath 2 | /.composer/ 3 | /.idea/ 4 | /.php_cs.cache 5 | /.project 6 | /.settings/ 7 | /.vscode/ 8 | /composer.lock 9 | /composer.phar 10 | /docker-compose.yml 11 | /docker/php.ini 12 | /php-cs-fixer.phar 13 | /vendor/ 14 | *.iml 15 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | in(__DIR__.'/src') 4 | ->in(__DIR__.'/tests') 5 | ; 6 | 7 | return PhpCsFixer\Config::create() 8 | ->setRules([ 9 | '@Symfony' => true, 10 | 'no_useless_return' => false, 11 | 'blank_line_after_opening_tag' => false, 12 | 'ordered_imports' => true, 13 | 'phpdoc_no_empty_return' => false, 14 | 'yoda_style' => false, 15 | 'no_superfluous_phpdoc_tags' => false, 16 | ]) 17 | ->setFinder($finder) 18 | ; 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/.composer/cache 8 | 9 | php: 10 | - 7.1 11 | - 7.2 12 | - 7.3 13 | 14 | matrix: 15 | fast_finish: true 16 | 17 | before_script: 18 | - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini 19 | - composer self-update 20 | - COMPOSER_MEMORY_LIMIT=-1 travis_retry composer install --no-interaction 21 | 22 | script: 23 | - ./vendor/bin/phpunit 24 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | This is the list of contributors to Workflower. 4 | 5 | * Atsuhiro Kubo [@iteman](https://github.com/iteman) 6 | * 77web [@77web](https://github.com/77web) 7 | * Waddlesworth [@SirWaddles](https://github.com/SirWaddles) 8 | * Adrian Teodorescu [@ateodorescu](https://github.com/ateodorescu) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2019 Atsuhiro Kubo and contributors, 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Workflower 2 | 3 | A BPMN 2.0 workflow engine for PHP 4 | 5 | `Workflower` is a BPMN 2.0 workflow engine for PHP. `Workflower` runs business processes using [the BPMN 2.0 specification](http://www.omg.org/spec/BPMN/2.0/). It's open-source and distributed under [the BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause). 6 | 7 | [![Total Downloads](https://poser.pugx.org/phpmentors/workflower/downloads)](https://packagist.org/packages/phpmentors/workflower) 8 | [![Latest Stable Version](https://poser.pugx.org/phpmentors/workflower/v/stable)](https://packagist.org/packages/phpmentors/workflower) 9 | [![Latest Unstable Version](https://poser.pugx.org/phpmentors/workflower/v/unstable)](https://packagist.org/packages/phpmentors/workflower) 10 | [![Build Status](https://travis-ci.org/phpmentors-jp/workflower.svg?branch=master)](https://travis-ci.org/phpmentors-jp/workflower) 11 | 12 | ## Features 13 | 14 | * Workflow 15 | * The workflow engine and domain model 16 | * Process 17 | * Some interfaces to work with `ProcessInstance` objects 18 | * Definition 19 | * `ProcessDefinitionRepository` to store all process definitions 20 | * BPMN 2.0 process definitions importer 21 | * Persistence 22 | * Serialize/deserialize interfaces for `ProcessInstance` objects 23 | 24 | ### Supported workflow elements 25 | 26 | * Connecting objects 27 | * Sequence flows 28 | * Flow objects 29 | * Activities 30 | * Tasks 31 | * Service tasks 32 | * Send tasks 33 | * User tasks 34 | * Manual tasks 35 | * CallActivity tasks 36 | * SubProcess tasks 37 | * Events 38 | * Start events 39 | * End events 40 | * TerminateEnd events 41 | * Gateways 42 | * Exclusive gateways 43 | * Inclusive gateways 44 | * Parallel gateways 45 | * Swimlanes 46 | * Lanes 47 | 48 | ## Installation 49 | 50 | `Workflower` can be installed using [Composer](http://getcomposer.org/). 51 | 52 | Add the dependency to `phpmentors/workflower` into your `composer.json` file as the following: 53 | 54 | **Stable version:** 55 | 56 | ``` 57 | composer require phpmentors/workflower "1.4.*" 58 | ``` 59 | 60 | **Development version:** 61 | 62 | ``` 63 | composer require phpmentors/workflower "~2.0@dev" 64 | ``` 65 | 66 | ## Documentation 67 | 68 | * [Quick Start Guide](https://github.com/phpmentors-jp/workflower/blob/master/docs/quick-start-guide.md) 69 | * [Release Notes](https://github.com/phpmentors-jp/workflower/releases) 70 | 71 | ## Support 72 | 73 | If you find a bug or have a question, or want to request a feature, create an issue or pull request for it on [Issues](https://github.com/phpmentors-jp/workflower/issues). 74 | 75 | ## Copyright 76 | 77 | Copyright (c) 2015-2019 Atsuhiro Kubo and [contributors](https://github.com/phpmentors-jp/workflower/wiki/Contributors), All rights reserved. 78 | 79 | ## License 80 | 81 | [The BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause) 82 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpmentors/workflower", 3 | "type": "library", 4 | "description": "A BPMN 2.0 workflow engine for PHP", 5 | "keywords": ["flow", "workflow", "process", "bpm", "bpmn", "bpms"], 6 | "license": "BSD-2-Clause", 7 | "authors": [ 8 | { 9 | "name": "Atsuhiro Kubo", 10 | "email": "kubo@iteman.jp" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.1.3", 15 | "ext-dom": "*", 16 | "symfony/expression-language": "~3.4|~4.0|~5.0" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": "~6.5" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "PHPMentors\\Workflower\\": "src/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "PHPMentors\\Workflower\\": "tests/" 29 | } 30 | }, 31 | "extra": { 32 | "branch-alias": { 33 | "dev-master": "2.0.x-dev" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docker-compose.yml.dist: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: docker 5 | network_mode: bridge 6 | volumes: 7 | - .:/var/app 8 | working_dir: /var/app 9 | environment: 10 | TZ: "Asia/Tokyo" 11 | LANG: "ja_JP.UTF-8" 12 | # PHP_INI: "docker/php.ini" 13 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phpmentors/php-app:php72 2 | 3 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections 4 | RUN apt-get update -y 5 | RUN apt-get upgrade -y 6 | 7 | # Other tools 8 | RUN apt-get install -y less unzip 9 | -------------------------------------------------------------------------------- /docker/php.ini.dist: -------------------------------------------------------------------------------- 1 | ;memory_limit=256M 2 | ;xdebug.remote_autostart=on 3 | ;xdebug.remote_port=9000 4 | ;xdebug.remote_host=172.17.0.1 5 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | ./tests 11 | 12 | 13 | 14 | 15 | 16 | ./src 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Definition/Bpmn2File.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | class Bpmn2File 16 | { 17 | /** 18 | * @var string 19 | */ 20 | private $file; 21 | 22 | /** 23 | * @param string $file 24 | */ 25 | public function __construct($file) 26 | { 27 | $this->file = $file; 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public function getId() 34 | { 35 | return static::getWorkflowId($this->file); 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getFile() 42 | { 43 | return $this->file; 44 | } 45 | 46 | /** 47 | * @param string $file 48 | * 49 | * @return string 50 | */ 51 | public static function getWorkflowId($file) 52 | { 53 | return pathinfo($file, PATHINFO_FILENAME); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Definition/Bpmn2WorkflowRepository.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | use PHPMentors\Workflower\Workflow\WorkflowRepositoryInterface; 17 | 18 | class Bpmn2WorkflowRepository implements WorkflowRepositoryInterface 19 | { 20 | /** 21 | * @var array 22 | */ 23 | private $bpmn2Files = []; 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function add($processInstance): void 29 | { 30 | assert($processInstance instanceof Bpmn2File); 31 | 32 | $this->bpmn2Files[$processInstance->getId()] = $processInstance; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function remove($processInstance): void 39 | { 40 | assert($processInstance instanceof Bpmn2File); 41 | 42 | if (array_key_exists($processInstance->getId(), $this->bpmn2Files)) { 43 | unset($this->bpmn2Files[$processInstance->getId()]); 44 | } 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | * 50 | * @return ProcessInstance 51 | */ 52 | public function findById($id): ?ProcessInstance 53 | { 54 | if (!array_key_exists($id, $this->bpmn2Files)) { 55 | return null; 56 | } 57 | 58 | $bpmn2Reader = new Bpmn2Reader(); 59 | 60 | return $bpmn2Reader->read($this->bpmn2Files[$id]->getFile()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Definition/ErrorToExceptionContext.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | class ErrorToExceptionContext 16 | { 17 | /** 18 | * @var int 19 | */ 20 | private $errorReportingLevel; 21 | 22 | /** 23 | * @var \Closure 24 | */ 25 | private $target; 26 | 27 | /** 28 | * @param int $errorReportingLevel 29 | * @param \Closure $target 30 | */ 31 | public function __construct($errorReportingLevel, \Closure $target) 32 | { 33 | $this->errorReportingLevel = $errorReportingLevel; 34 | $this->target = $target; 35 | } 36 | 37 | /** 38 | * @return mixed 39 | * 40 | * @throws \Exception 41 | */ 42 | public function invoke() 43 | { 44 | set_error_handler(function ($code, $message, $file, $line) { 45 | throw new \ErrorException($message, 0, $code, $file, $line); 46 | }, $this->errorReportingLevel === null ? error_reporting() : $this->errorReportingLevel 47 | ); 48 | 49 | try { 50 | $returnValue = call_user_func($this->target); 51 | } catch (\Exception $e) { 52 | restore_error_handler(); 53 | throw $e; 54 | } 55 | 56 | restore_error_handler(); 57 | 58 | return $returnValue; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Definition/IdAttributeNotFoundException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | class IdAttributeNotFoundException extends \UnexpectedValueException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Definition/ProcessDefinitionRepository.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessDefinitionInterface; 16 | use PHPMentors\Workflower\Workflow\ProcessDefinitionRepositoryInterface; 17 | 18 | /** 19 | * @since Class available since Release 2.0.0 20 | */ 21 | class ProcessDefinitionRepository implements ProcessDefinitionRepositoryInterface 22 | { 23 | /** 24 | * @var array 25 | */ 26 | private $items = []; 27 | 28 | public function add(ProcessDefinitionInterface $definition) 29 | { 30 | $this->items[] = $definition; 31 | $definition->setProcessDefinitions($this); 32 | 33 | return $definition; 34 | } 35 | 36 | public function getLatestById(string $id) 37 | { 38 | $results = array_filter($this->items, function (ProcessDefinitionInterface $item) use ($id) { 39 | return $item->getId() === $id; 40 | }); 41 | 42 | return $this->getLatestVersion($results); 43 | } 44 | 45 | public function getLatestByName(string $name) 46 | { 47 | $results = array_filter($this->items, function (ProcessDefinitionInterface $item) use ($name) { 48 | return $item->getName() === $name; 49 | }); 50 | 51 | return $this->getLatestVersion($results); 52 | } 53 | 54 | public function getVersionById(string $id, int $version) 55 | { 56 | $results = array_filter($this->items, function (ProcessDefinitionInterface $item) use ($id, $version) { 57 | return $item->getId() === $id && $item->getVersion() === $version; 58 | }); 59 | 60 | return count($results) > 0 ? $results[0] : null; 61 | } 62 | 63 | public function getVersionByName(string $name, int $version) 64 | { 65 | $results = array_filter($this->items, function (ProcessDefinitionInterface $item) use ($name, $version) { 66 | return $item->getName() === $name && $item->getVersion() === $version; 67 | }); 68 | 69 | return count($results) > 0 ? $results[0] : null; 70 | } 71 | 72 | /** 73 | * @param string $file 74 | */ 75 | public function importFromFile(string $file) 76 | { 77 | $import = new Bpmn2Reader(); 78 | 79 | $definitions = $import->read($file); 80 | 81 | foreach ($definitions as $definition) { 82 | $this->add($definition); 83 | } 84 | } 85 | 86 | /** 87 | * @param string $source 88 | */ 89 | public function importFromSource(string $source) 90 | { 91 | $import = new Bpmn2Reader(); 92 | 93 | $definitions = $import->readSource($source); 94 | 95 | foreach ($definitions as $definition) { 96 | $this->add($definition); 97 | } 98 | } 99 | 100 | private function getLatestVersion(array $results) 101 | { 102 | $max = 0; 103 | $item = null; 104 | 105 | foreach ($results as $result) { 106 | $version = $result->getVersion(); 107 | if ($version > $max) { 108 | $max = $version; 109 | $item = $result; 110 | } 111 | } 112 | 113 | return $item; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Persistence/Base64PhpWorkflowSerializer.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Persistence; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | 17 | class Base64PhpWorkflowSerializer extends PhpWorkflowSerializer 18 | { 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function serialize(ProcessInstance $processInstance) 23 | { 24 | return base64_encode(parent::serialize($processInstance)); 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function deserialize($processInstance) 31 | { 32 | return parent::deserialize(base64_decode($processInstance)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Persistence/PhpWorkflowSerializer.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Persistence; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | 17 | class PhpWorkflowSerializer implements WorkflowSerializerInterface 18 | { 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function serialize(ProcessInstance $processInstance) 23 | { 24 | return serialize($processInstance); 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function deserialize($processInstance) 31 | { 32 | return unserialize($processInstance); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Persistence/WorkflowSerializableInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Persistence; 14 | 15 | use PHPMentors\Workflower\Process\WorkflowAwareInterface; 16 | use PHPMentors\Workflower\Workflow\ProcessInstance; 17 | 18 | interface WorkflowSerializableInterface extends WorkflowAwareInterface 19 | { 20 | /** 21 | * @param string $serializedWorkflow 22 | */ 23 | public function setSerializedWorkflow($serializedWorkflow); 24 | 25 | /** 26 | * @return string 27 | */ 28 | public function getSerializedWorkflow(); 29 | 30 | /** 31 | * @return ProcessInstance 32 | */ 33 | public function getProcessInstance(); 34 | } 35 | -------------------------------------------------------------------------------- /src/Persistence/WorkflowSerializerInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Persistence; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | 17 | interface WorkflowSerializerInterface 18 | { 19 | /** 20 | * @param ProcessInstance $processInstance 21 | * 22 | * @return string 23 | */ 24 | public function serialize(ProcessInstance $processInstance); 25 | 26 | /** 27 | * @param string $processInstance 28 | * 29 | * @return ProcessInstance 30 | */ 31 | public function deserialize($processInstance); 32 | } 33 | -------------------------------------------------------------------------------- /src/Process/EventContext.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | class EventContext implements EventContextInterface 16 | { 17 | /** 18 | * @var int|string 19 | */ 20 | private $eventId; 21 | 22 | /** 23 | * @var ProcessContextInterface 24 | */ 25 | private $processContext; 26 | 27 | /** 28 | * @param int|string $eventId 29 | * @param ProcessContextInterface $processContext 30 | */ 31 | public function __construct($eventId, ProcessContextInterface $processContext) 32 | { 33 | $this->eventId = $eventId; 34 | $this->processContext = $processContext; 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function getEventId() 41 | { 42 | return $this->eventId; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function getProcessContext() 49 | { 50 | return $this->processContext; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Process/EventContextInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | interface EventContextInterface 16 | { 17 | /** 18 | * @return int|string 19 | */ 20 | public function getEventId(); 21 | 22 | /** 23 | * @return ProcessContextInterface 24 | */ 25 | public function getProcessContext(); 26 | } 27 | -------------------------------------------------------------------------------- /src/Process/Process.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | use PHPMentors\Workflower\Workflow\Activity\ActivityInterface; 16 | use PHPMentors\Workflower\Workflow\Activity\UnexpectedActivityStateException; 17 | use PHPMentors\Workflower\Workflow\Event\StartEvent; 18 | use PHPMentors\Workflower\Workflow\Operation\OperationRunnerInterface; 19 | use PHPMentors\Workflower\Workflow\ProcessInstance; 20 | use PHPMentors\Workflower\Workflow\WorkflowRepositoryInterface; 21 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage; 22 | 23 | class Process 24 | { 25 | /** 26 | * @var int|string|WorkflowContextInterface 27 | */ 28 | private $workflowContext; 29 | 30 | /** 31 | * @var WorkflowRepositoryInterface 32 | */ 33 | private $workflowRepository; 34 | 35 | /** 36 | * @var ExpressionLanguage 37 | * 38 | * @since Property available since Release 1.2.0 39 | */ 40 | private $expressionLanguage; 41 | 42 | /** 43 | * @var OperationRunnerInterface 44 | * 45 | * @since Property available since Release 1.2.0 46 | */ 47 | private $operationRunner; 48 | 49 | /** 50 | * @param int|string|WorkflowContextInterface $workflowContext 51 | * @param WorkflowRepositoryInterface $workflowRepository 52 | * @param OperationRunnerInterface $operationRunner 53 | */ 54 | public function __construct($workflowContext, WorkflowRepositoryInterface $workflowRepository, OperationRunnerInterface $operationRunner) 55 | { 56 | $this->workflowContext = $workflowContext; 57 | $this->workflowRepository = $workflowRepository; 58 | $this->operationRunner = $operationRunner; 59 | } 60 | 61 | /** 62 | * @param ExpressionLanguage $expressionLanguage 63 | * 64 | * @since Method available since Release 1.2.0 65 | */ 66 | public function setExpressionLanguage(ExpressionLanguage $expressionLanguage) 67 | { 68 | $this->expressionLanguage = $expressionLanguage; 69 | } 70 | 71 | /** 72 | * @param EventContextInterface $eventContext 73 | */ 74 | public function start(EventContextInterface $eventContext) 75 | { 76 | assert($eventContext->getProcessContext() !== null); 77 | assert($eventContext->getProcessContext()->getProcessInstance() === null); 78 | assert($eventContext->getEventId() !== null); 79 | 80 | $processInstance = $this->configureWorkflow($this->createWorkflow()); 81 | $eventContext->getProcessContext()->setProcessInstance($processInstance); 82 | $processInstance->setProcessData($eventContext->getProcessContext()->getProcessData()); 83 | $flowObject = $processInstance->getFlowObject($eventContext->getEventId()); 84 | $processInstance->start(/* @var $flowObject StartEvent */ $flowObject); 85 | } 86 | 87 | /** 88 | * @param WorkItemContextInterface $workItemContext 89 | */ 90 | public function allocateWorkItem(WorkItemContextInterface $workItemContext) 91 | { 92 | assert($workItemContext->getProcessContext() !== null); 93 | assert($workItemContext->getProcessContext()->getProcessInstance() !== null); 94 | assert($workItemContext->getActivityId() !== null); 95 | 96 | $processInstance = $this->configureWorkflow($workItemContext->getProcessContext()->getProcessInstance()); 97 | $flowObject = $processInstance->getFlowObject($workItemContext->getActivityId()); 98 | $processInstance->allocateWorkItem(/* @var $flowObject ActivityInterface */ $flowObject, $workItemContext->getParticipant()); 99 | } 100 | 101 | /** 102 | * @param WorkItemContextInterface $workItemContext 103 | */ 104 | public function startWorkItem(WorkItemContextInterface $workItemContext) 105 | { 106 | assert($workItemContext->getProcessContext() !== null); 107 | assert($workItemContext->getProcessContext()->getProcessInstance() !== null); 108 | assert($workItemContext->getActivityId() !== null); 109 | 110 | $processInstance = $this->configureWorkflow($workItemContext->getProcessContext()->getProcessInstance()); 111 | $flowObject = $processInstance->getFlowObject($workItemContext->getActivityId()); 112 | $processInstance->startWorkItem(/* @var $flowObject ActivityInterface */ $flowObject, $workItemContext->getParticipant()); 113 | } 114 | 115 | /** 116 | * @param WorkItemContextInterface $workItemContext 117 | */ 118 | public function completeWorkItem(WorkItemContextInterface $workItemContext) 119 | { 120 | assert($workItemContext->getProcessContext() !== null); 121 | assert($workItemContext->getProcessContext()->getProcessInstance() !== null); 122 | assert($workItemContext->getActivityId() !== null); 123 | 124 | $processInstance = $this->configureWorkflow($workItemContext->getProcessContext()->getProcessInstance()); 125 | $processInstance->setProcessData($workItemContext->getProcessContext()->getProcessData()); 126 | $flowObject = $processInstance->getFlowObject($workItemContext->getActivityId()); 127 | $processInstance->completeWorkItem(/* @var $flowObject ActivityInterface */ $flowObject, $workItemContext->getParticipant()); 128 | } 129 | 130 | /** 131 | * @param WorkItemContextInterface $workItemContext 132 | * 133 | * @throws UnexpectedActivityStateException 134 | */ 135 | public function executeWorkItem(WorkItemContextInterface $workItemContext) 136 | { 137 | assert($workItemContext->getProcessContext() !== null); 138 | assert($workItemContext->getProcessContext()->getProcessInstance() !== null); 139 | assert($workItemContext->getActivityId() !== null); 140 | assert($workItemContext->getProcessContext()->getProcessInstance()->getFlowObject($workItemContext->getActivityId()) instanceof ActivityInterface); 141 | 142 | $activity = $workItemContext->getProcessContext()->getProcessInstance()->getFlowObject($workItemContext->getActivityId()); /* @var $activity ActivityInterface */ 143 | if ($activity->isAllocatable()) { 144 | $this->allocateWorkItem($workItemContext); 145 | $nextWorkItemContext = new WorkItemContext($workItemContext->getParticipant()); 146 | $nextWorkItemContext->setActivityId($workItemContext->getProcessContext()->getProcessInstance()->getCurrentFlowObject()->getId()); 147 | $nextWorkItemContext->setProcessContext($workItemContext->getProcessContext()); 148 | 149 | return $this->executeWorkItem($nextWorkItemContext); 150 | } elseif ($activity->isStartable()) { 151 | $this->startWorkItem($workItemContext); 152 | $nextWorkItemContext = new WorkItemContext($workItemContext->getParticipant()); 153 | $nextWorkItemContext->setActivityId($workItemContext->getProcessContext()->getProcessInstance()->getCurrentFlowObject()->getId()); 154 | $nextWorkItemContext->setProcessContext($workItemContext->getProcessContext()); 155 | 156 | return $this->executeWorkItem($nextWorkItemContext); 157 | } elseif ($activity->isCompletable()) { 158 | $this->completeWorkItem($workItemContext); 159 | } else { 160 | throw new UnexpectedActivityStateException(sprintf('The current work item of the activity "%s" is not executable.', $activity->getId())); 161 | } 162 | } 163 | 164 | /** 165 | * @return int|string|WorkflowContextInterface 166 | * 167 | * @since Method available since Release 1.1.0 168 | */ 169 | public function getWorkflowContext() 170 | { 171 | return $this->workflowContext; 172 | } 173 | 174 | /** 175 | * @return ProcessInstance 176 | * 177 | * @throws WorkflowNotFoundException 178 | */ 179 | private function createWorkflow() 180 | { 181 | $workflowId = $this->workflowContext instanceof WorkflowContextInterface ? $this->workflowContext->getWorkflowId() : $this->workflowContext; 182 | $processInstance = $this->workflowRepository->findById($workflowId); 183 | if ($processInstance === null) { 184 | throw new WorkflowNotFoundException(sprintf('The processInstance "%s" is not found.', $workflowId)); 185 | } 186 | 187 | return $processInstance; 188 | } 189 | 190 | /** 191 | * @param ProcessInstance $processInstance 192 | * 193 | * @return ProcessInstance 194 | * 195 | * @since Method available since Release 1.2.0 196 | */ 197 | private function configureWorkflow(ProcessInstance $processInstance) 198 | { 199 | if ($this->expressionLanguage !== null) { 200 | $processInstance->setExpressionLanguage($this->expressionLanguage); 201 | } 202 | 203 | if ($this->operationRunner !== null) { 204 | $processInstance->setOperationRunner($this->operationRunner); 205 | } 206 | 207 | return $processInstance; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/Process/ProcessAwareInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | interface ProcessAwareInterface 16 | { 17 | /** 18 | * @param Process $process 19 | */ 20 | public function setProcess(Process $process); 21 | } 22 | -------------------------------------------------------------------------------- /src/Process/ProcessContextInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | 17 | interface ProcessContextInterface extends WorkflowAwareInterface 18 | { 19 | /** 20 | * @return array 21 | */ 22 | public function getProcessData(); 23 | 24 | /** 25 | * @return ProcessInstance 26 | */ 27 | public function getProcessInstance(); 28 | } 29 | -------------------------------------------------------------------------------- /src/Process/WorkItemContext.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | use PHPMentors\Workflower\Workflow\Participant\ParticipantInterface; 16 | 17 | class WorkItemContext implements WorkItemContextInterface 18 | { 19 | /** 20 | * @var int|string 21 | */ 22 | private $activityId; 23 | 24 | /** 25 | * @var ParticipantInterface 26 | */ 27 | private $participant; 28 | 29 | /** 30 | * @var ProcessContextInterface 31 | */ 32 | private $processContext; 33 | 34 | /** 35 | * @param ParticipantInterface $participant 36 | */ 37 | public function __construct(ParticipantInterface $participant) 38 | { 39 | $this->participant = $participant; 40 | } 41 | 42 | /** 43 | * @param int|string $activityId 44 | */ 45 | public function setActivityId($activityId) 46 | { 47 | $this->activityId = $activityId; 48 | } 49 | 50 | /** 51 | * @param ProcessContextInterface $processContext 52 | */ 53 | public function setProcessContext(ProcessContextInterface $processContext) 54 | { 55 | $this->processContext = $processContext; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function getActivityId() 62 | { 63 | return $this->activityId; 64 | } 65 | 66 | /** 67 | * @param ParticipantInterface $participant 68 | * 69 | * @since Method available since Release 1.1.0 70 | */ 71 | public function setParticipant(ParticipantInterface $participant) 72 | { 73 | $this->participant = $participant; 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function getParticipant() 80 | { 81 | return $this->participant; 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function getProcessContext() 88 | { 89 | return $this->processContext; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Process/WorkItemContextInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | use PHPMentors\Workflower\Workflow\Participant\ParticipantInterface; 16 | 17 | interface WorkItemContextInterface 18 | { 19 | /** 20 | * @return int|string 21 | */ 22 | public function getActivityId(); 23 | 24 | /** 25 | * @return int|string 26 | */ 27 | public function getWorkItemId(); 28 | 29 | /** 30 | * @return ParticipantInterface 31 | */ 32 | public function getParticipant(); 33 | 34 | /** 35 | * @return ProcessContextInterface 36 | */ 37 | public function getProcessContext(); 38 | } 39 | -------------------------------------------------------------------------------- /src/Process/WorkflowAwareInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | use PHPMentors\Workflower\Workflow\ProcessInstance; 16 | 17 | interface WorkflowAwareInterface 18 | { 19 | /** 20 | * @param ProcessInstance $processInstance 21 | */ 22 | public function setProcessInstance(ProcessInstance $processInstance); 23 | } 24 | -------------------------------------------------------------------------------- /src/Process/WorkflowContextInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | /** 16 | * @since Interface available since Release 1.1.0 17 | */ 18 | interface WorkflowContextInterface 19 | { 20 | /** 21 | * @return int|string 22 | */ 23 | public function getWorkflowId(); 24 | } 25 | -------------------------------------------------------------------------------- /src/Process/WorkflowNotFoundException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Process; 14 | 15 | class WorkflowNotFoundException extends \LogicException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Resources/config/workflower/schema/BPMN20.xsd: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Resources/config/workflower/schema/BPMNDI.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/Resources/config/workflower/schema/DC.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Resources/config/workflower/schema/DI.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/Workflow/AccessDeniedException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | class AccessDeniedException extends \RuntimeException 16 | { 17 | /** 18 | * @param string $message 19 | * @param \Exception $previous 20 | */ 21 | public function __construct($message = 'Access Denied', \Exception $previous = null) 22 | { 23 | parent::__construct($message, 403, $previous); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Workflow/Activity/ActivityInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | use PHPMentors\Workflower\Workflow\Element\ConditionalInterface; 16 | use PHPMentors\Workflower\Workflow\Element\FlowObjectInterface; 17 | use PHPMentors\Workflower\Workflow\Element\TransitionalInterface; 18 | use PHPMentors\Workflower\Workflow\ItemsCollectionInterface; 19 | 20 | interface ActivityInterface extends FlowObjectInterface, TransitionalInterface, ConditionalInterface 21 | { 22 | const STATE_INACTIVE = 'inactive'; 23 | const STATE_READY = 'ready'; 24 | const STATE_ACTIVE = 'active'; 25 | const STATE_COMPLETED = 'completed'; 26 | const STATE_FAILED = 'failed'; 27 | const STATE_CLOSED = 'closed'; 28 | 29 | /** 30 | * @return ItemsCollectionInterface 31 | */ 32 | public function getWorkItems(); 33 | 34 | /** 35 | * @param ItemsCollectionInterface $collection 36 | * 37 | * @return void 38 | */ 39 | public function setWorkItems(ItemsCollectionInterface $collection); 40 | 41 | /** 42 | * @return void 43 | */ 44 | public function createWork(): void; 45 | 46 | /** 47 | * @return void 48 | */ 49 | public function completeWork(): void; 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getState(); 55 | 56 | /** 57 | * @return bool 58 | */ 59 | public function isClosed(); 60 | 61 | /** 62 | * @return bool 63 | */ 64 | public function isFailed(); 65 | 66 | /** 67 | * @return void 68 | * 69 | * @since Method available since Release 2.0.0 70 | */ 71 | public function cancel(); 72 | } 73 | -------------------------------------------------------------------------------- /src/Workflow/Activity/CallTask.php: -------------------------------------------------------------------------------- 1 | $value) { 20 | if (property_exists(self::class, $name)) { 21 | $this->{$name} = $value; 22 | } 23 | } 24 | } 25 | 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | public function serialize() 30 | { 31 | return serialize([ 32 | get_parent_class($this) => parent::serialize(), 33 | 'calledElement' => $this->calledElement, 34 | ]); 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function unserialize($serialized) 41 | { 42 | foreach (unserialize($serialized) as $name => $value) { 43 | if ($name == get_parent_class($this)) { 44 | parent::unserialize($value); 45 | continue; 46 | } 47 | 48 | if (property_exists($this, $name)) { 49 | $this->$name = $value; 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getCalledElement() 58 | { 59 | return $this->calledElement; 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | public function getProcessDefinition() 66 | { 67 | if ($this->processDefinition === null) { 68 | // by the time this is called we assume that our process definition 69 | // is already in our repository. Maybe we should throw an error 70 | // if we don't find it there 71 | $this->processDefinition = $this->getProcessInstance()->getProcessDefinition()->getProcessDefinitions()->getLatestById($this->calledElement); 72 | } 73 | 74 | return $this->processDefinition; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Workflow/Activity/ManualTask.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | use PHPMentors\Workflower\Workflow\Operation\OperationalInterface; 16 | 17 | /** 18 | * @since Class available since Release 2.0.0 19 | */ 20 | abstract class OperationalTask extends Task implements OperationalInterface 21 | { 22 | /** 23 | * @var int|string 24 | */ 25 | protected $operation; 26 | 27 | public function __construct(array $config = []) 28 | { 29 | parent::__construct($config); 30 | 31 | foreach ($config as $name => $value) { 32 | if (property_exists(self::class, $name)) { 33 | $this->{$name} = $value; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function serialize() 42 | { 43 | return serialize([ 44 | get_parent_class($this) => parent::serialize(), 45 | 'operation' => $this->operation, 46 | ]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function unserialize($serialized) 53 | { 54 | foreach (unserialize($serialized) as $name => $value) { 55 | if ($name == get_parent_class($this)) { 56 | parent::unserialize($value); 57 | continue; 58 | } 59 | 60 | if (property_exists($this, $name)) { 61 | $this->$name = $value; 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function getOperation() 70 | { 71 | return $this->operation; 72 | } 73 | 74 | /** 75 | * @param int|string $operation 76 | */ 77 | public function setOperation($operation): void 78 | { 79 | $this->operation = $operation; 80 | } 81 | 82 | public function createWork(): void 83 | { 84 | // create work items 85 | parent::createWork(); 86 | 87 | $processInstance = $this->getProcessInstance(); 88 | $operationRunner = $processInstance->getOperationRunner(); 89 | 90 | $participant = $operationRunner->provideParticipant($this, $processInstance); 91 | 92 | // execute work items 93 | foreach ($this->workItems as $workItem) { 94 | if (!$workItem->isEnded()) { 95 | $workItem->allocate($participant); 96 | $workItem->start(); 97 | $operationRunner->run($workItem); 98 | $workItem->complete($participant); 99 | } 100 | } 101 | 102 | $this->end(); 103 | } 104 | 105 | public function completeWork(): void 106 | { 107 | // do nothing here because we completed the work inside "createWork" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Workflow/Activity/ProcessTask.php: -------------------------------------------------------------------------------- 1 | $value) { 19 | if (property_exists(self::class, $name)) { 20 | $this->{$name} = $value; 21 | } 22 | } 23 | } 24 | 25 | /** 26 | * @return ProcessDefinitionInterface 27 | */ 28 | public function getProcessDefinition() 29 | { 30 | return $this->processDefinition; 31 | } 32 | 33 | protected function createWorkItem($data) 34 | { 35 | if ($this->isClosed()) { 36 | throw new UnexpectedActivityStateException(sprintf('The activity "%s" is closed.', $this->getId())); 37 | } 38 | 39 | $instance = $this->getProcessDefinition()->createProcessInstance(); 40 | $instance->setProcessInstance($this->getProcessInstance()); 41 | $instance->setActivity($this); 42 | 43 | $instance->setProcessData($data); 44 | $this->getWorkItems()->add($instance); 45 | 46 | $instance->start($instance->getFirstStartEvent()); 47 | 48 | return $instance; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Workflow/Activity/SendTask.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | use PHPMentors\Workflower\Workflow\Resource\MessageInterface; 16 | 17 | /** 18 | * @since Class available since Release 1.3.0 19 | */ 20 | class SendTask extends OperationalTask implements MessageInterface 21 | { 22 | /** 23 | * @var int|string 24 | */ 25 | private $message; 26 | 27 | public function __construct(array $config = []) 28 | { 29 | parent::__construct($config); 30 | 31 | foreach ($config as $name => $value) { 32 | if (property_exists(self::class, $name)) { 33 | $this->{$name} = $value; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function serialize() 42 | { 43 | return serialize([ 44 | get_parent_class($this) => parent::serialize(), 45 | 'message' => $this->message, 46 | ]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function unserialize($serialized) 53 | { 54 | foreach (unserialize($serialized) as $name => $value) { 55 | if ($name == get_parent_class($this)) { 56 | parent::unserialize($value); 57 | continue; 58 | } 59 | 60 | if (property_exists($this, $name)) { 61 | $this->$name = $value; 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function getMessage() 70 | { 71 | return $this->message; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Workflow/Activity/ServiceTask.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | /** 16 | * @since Class available since Release 1.2.0 17 | */ 18 | class ServiceTask extends OperationalTask 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Workflow/Activity/SubProcessTask.php: -------------------------------------------------------------------------------- 1 | $value) { 17 | if (property_exists(self::class, $name)) { 18 | $this->{$name} = $value; 19 | } 20 | } 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function serialize() 27 | { 28 | return serialize([ 29 | get_parent_class($this) => parent::serialize(), 30 | 'triggeredByEvent' => $this->triggeredByEvent, 31 | ]); 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function unserialize($serialized) 38 | { 39 | foreach (unserialize($serialized) as $name => $value) { 40 | if ($name == get_parent_class($this)) { 41 | parent::unserialize($value); 42 | continue; 43 | } 44 | 45 | if (property_exists($this, $name)) { 46 | $this->$name = $value; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Workflow/Activity/Task.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | use PHPMentors\Workflower\Workflow\Provider\DataNotFoundException; 16 | use PHPMentors\Workflower\Workflow\Provider\ProviderNotFoundException; 17 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage; 18 | 19 | class Task extends AbstractTask 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | protected function createWorkItem($data) 25 | { 26 | if ($this->isClosed()) { 27 | throw new UnexpectedActivityStateException(sprintf('The activity "%s" is closed.', $this->getId())); 28 | } 29 | 30 | $workItem = $this->getProcessInstance()->generateWorkItem($this); 31 | $workItem->setData($data); 32 | $this->getWorkItems()->add($workItem); 33 | 34 | return $workItem; 35 | } 36 | 37 | public function createWork(): void 38 | { 39 | $provider = $this->getProcessInstance()->getDataProvider(); 40 | 41 | if ($this->isMultiInstance()) { 42 | // If not sequential then create parallel work items. 43 | // If it's sequential then create a work item and when it's completed create 44 | // the next one if required. 45 | // After completing each work item check "completionCondition" to see if we 46 | // cancel all remaining work items. 47 | 48 | if (!$provider) { 49 | throw new ProviderNotFoundException(); 50 | } 51 | 52 | if ($this->isSequential()) { 53 | $this->createWorkItem($provider->getSequentialInstanceData($this)); 54 | } else { 55 | // calculate how many parallel instances we have to create 56 | $parallelData = $provider->getParallelInstancesData($this); 57 | 58 | if (count($parallelData) === 0) { 59 | throw new DataNotFoundException(); 60 | } 61 | 62 | foreach ($parallelData as $data) { 63 | $this->createWorkItem($data); 64 | } 65 | } 66 | } else { 67 | // just one work item has be to created 68 | $this->createWorkItem($provider ? $provider->getSingleInstanceData($this) : []); 69 | } 70 | } 71 | 72 | public function completeWork(): void 73 | { 74 | if ($this->isMultiInstance()) { 75 | $workItems = $this->getWorkItems(); 76 | $processInstance = $this->getProcessInstance(); 77 | 78 | $completed = $workItems->countOfCompletedInstances(); 79 | $active = $workItems->countOfActiveInstances(); 80 | 81 | $expression = $processInstance->getExpressionLanguage() ?: new ExpressionLanguage(); 82 | $condition = $this->getCompletionCondition(); 83 | $stop = false; 84 | 85 | if ($condition) { 86 | // check if we have to stop processing the other active work items 87 | $conditionData = [ 88 | 'nrOfInstances' => $workItems->count(), 89 | 'nrOfCompletedInstances' => $completed, 90 | 'nrOfActiveInstances' => $active, 91 | ]; 92 | 93 | $conditionData = array_merge($conditionData, $processInstance->getProcessData() ?: []); 94 | $stop = $expression->evaluate($condition, $conditionData); 95 | } 96 | 97 | if ($stop) { 98 | // we need to cancel all active work items left 99 | $this->cancelActiveInstances(); 100 | } else { 101 | if ($this->isSequential()) { 102 | $this->createWork(); 103 | 104 | return; 105 | } else { 106 | if ($completed !== $active) { 107 | // we have to wait until all work items are completed 108 | return; 109 | } 110 | } 111 | } 112 | 113 | // merge all instances data 114 | $provider = $processInstance->getDataProvider(); 115 | $provider->mergeInstancesData($this); 116 | } 117 | 118 | // if no more instance needs to be created then end the activity 119 | $this->end(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Workflow/Activity/UnexpectedActivityException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | class UnexpectedActivityException extends \UnexpectedValueException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Workflow/Activity/UnexpectedActivityStateException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | class UnexpectedActivityStateException extends \UnexpectedValueException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Workflow/Activity/UnexpectedWorkItemStateException.php: -------------------------------------------------------------------------------- 1 | id = $id; 74 | $this->creationDate = new \DateTime(); 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function serialize() 81 | { 82 | return serialize([ 83 | 'id' => $this->id, 84 | 'parentProcessInstance' => $this->parentProcessInstance, 85 | 'parentActivity' => $this->parentActivity, 86 | 'state' => $this->state, 87 | 'participant' => $this->participant === null ? null : ($this->participant instanceof LoggedParticipant ? $this->participant : new LoggedParticipant($this->participant)), 88 | 'creationDate' => $this->creationDate, 89 | 'allocationDate' => $this->allocationDate, 90 | 'startDate' => $this->startDate, 91 | 'endDate' => $this->endDate, 92 | 'endParticipant' => $this->endParticipant === null ? null : ($this->endParticipant instanceof LoggedParticipant ? $this->endParticipant : new LoggedParticipant($this->endParticipant)), 93 | 'endResult' => $this->endResult, 94 | ]); 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function unserialize($serialized) 101 | { 102 | foreach (unserialize($serialized) as $name => $value) { 103 | if (property_exists($this, $name)) { 104 | $this->$name = $value; 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * {@inheritdoc} 111 | */ 112 | public function getId() 113 | { 114 | return $this->id; 115 | } 116 | 117 | /** 118 | * {@inheritdoc} 119 | */ 120 | public function setProcessInstance(ProcessInstanceInterface $processInstance) 121 | { 122 | $this->parentProcessInstance = $processInstance; 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | */ 128 | public function getProcessInstance() 129 | { 130 | return $this->parentProcessInstance; 131 | } 132 | 133 | /** 134 | * {@inheritdoc} 135 | */ 136 | public function setActivity(ActivityInterface $activity) 137 | { 138 | $this->parentActivity = $activity; 139 | } 140 | 141 | /** 142 | * {@inheritdoc} 143 | */ 144 | public function getActivity() 145 | { 146 | return $this->parentActivity; 147 | } 148 | 149 | /** 150 | * {@inheritdoc} 151 | */ 152 | public function setData($data) 153 | { 154 | $this->data = $data; 155 | } 156 | 157 | /** 158 | * {@inheritdoc} 159 | */ 160 | public function getData() 161 | { 162 | return $this->data; 163 | } 164 | 165 | /** 166 | * {@inheritdoc} 167 | */ 168 | public function isAllocatable() 169 | { 170 | return $this->getState() == WorkItem::STATE_CREATED; 171 | } 172 | 173 | /** 174 | * {@inheritdoc} 175 | */ 176 | public function isStartable() 177 | { 178 | return $this->getState() == WorkItem::STATE_ALLOCATED; 179 | } 180 | 181 | /** 182 | * {@inheritdoc} 183 | */ 184 | public function isCompletable() 185 | { 186 | return $this->getState() == WorkItem::STATE_STARTED; 187 | } 188 | 189 | /** 190 | * {@inheritdoc} 191 | */ 192 | public function isCancelled() 193 | { 194 | return $this->getState() == WorkItem::STATE_CANCELLED; 195 | } 196 | 197 | /** 198 | * {@inheritdoc} 199 | */ 200 | public function isEnded() 201 | { 202 | $state = $this->getState(); 203 | 204 | return $state == WorkItem::STATE_ENDED || $state == WorkItem::STATE_CANCELLED; 205 | } 206 | 207 | /** 208 | * {@inheritdoc} 209 | */ 210 | public function getState() 211 | { 212 | return $this->state; 213 | } 214 | 215 | /** 216 | * {@inheritdoc} 217 | */ 218 | public function getParticipant() 219 | { 220 | return $this->participant; 221 | } 222 | 223 | /** 224 | * {@inheritdoc} 225 | */ 226 | public function getCreationDate() 227 | { 228 | return $this->creationDate; 229 | } 230 | 231 | /** 232 | * {@inheritdoc} 233 | */ 234 | public function getAllocationDate() 235 | { 236 | return $this->allocationDate; 237 | } 238 | 239 | /** 240 | * {@inheritdoc} 241 | */ 242 | public function getStartDate() 243 | { 244 | return $this->startDate; 245 | } 246 | 247 | /** 248 | * {@inheritdoc} 249 | */ 250 | public function getEndDate() 251 | { 252 | return $this->endDate; 253 | } 254 | 255 | /** 256 | * {@inheritdoc} 257 | */ 258 | public function getEndParticipant() 259 | { 260 | return $this->endParticipant; 261 | } 262 | 263 | /** 264 | * {@inheritdoc} 265 | */ 266 | public function getEndResult() 267 | { 268 | return $this->endResult; 269 | } 270 | 271 | /** 272 | * {@inheritdoc} 273 | */ 274 | public function allocate(ParticipantInterface $participant) 275 | { 276 | if (!$this->isAllocatable()) { 277 | throw new UnexpectedWorkItemStateException(sprintf('The current work item of the activity "%s" is not allocatable.', $this->getId())); 278 | } 279 | 280 | $this->state = self::STATE_ALLOCATED; 281 | $this->allocationDate = new \DateTime(); 282 | $this->participant = $participant; 283 | } 284 | 285 | /** 286 | * {@inheritdoc} 287 | */ 288 | public function start(): void 289 | { 290 | if (!$this->isStartable()) { 291 | throw new UnexpectedWorkItemStateException(sprintf('The current work item of the activity "%s" is not startable.', $this->getId())); 292 | } 293 | 294 | $this->state = self::STATE_STARTED; 295 | $this->startDate = new \DateTime(); 296 | } 297 | 298 | /** 299 | * {@inheritdoc} 300 | */ 301 | public function complete(ParticipantInterface $participant = null) 302 | { 303 | if (!$this->isCompletable()) { 304 | throw new UnexpectedWorkItemStateException(sprintf('The current work item of the activity "%s" is not completable.', $this->getId())); 305 | } 306 | 307 | $this->state = self::STATE_ENDED; 308 | $this->endDate = new \DateTime(); 309 | $this->endParticipant = $participant === null ? $this->participant : $participant; 310 | $this->endResult = self::END_RESULT_COMPLETION; 311 | 312 | $this->getActivity()->completeWork(); 313 | } 314 | 315 | public function cancel(): void 316 | { 317 | $this->state = self::STATE_CANCELLED; 318 | $this->endDate = new \DateTime(); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/Workflow/Activity/WorkItemInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Activity; 14 | 15 | use PHPMentors\Workflower\Workflow\ItemInterface; 16 | use PHPMentors\Workflower\Workflow\Participant\ParticipantInterface; 17 | 18 | interface WorkItemInterface extends ItemInterface 19 | { 20 | const STATE_CREATED = 'created'; 21 | const STATE_ALLOCATED = 'allocated'; 22 | const STATE_STARTED = 'started'; 23 | const STATE_ENDED = 'ended'; 24 | const STATE_CANCELLED = 'cancelled'; 25 | const END_RESULT_COMPLETION = 'completion'; 26 | 27 | /** 28 | * @param array $data 29 | * 30 | * @return void 31 | */ 32 | public function setData($data); 33 | 34 | /** 35 | * @return array 36 | */ 37 | public function getData(); 38 | 39 | /** 40 | * @return bool 41 | */ 42 | public function isAllocatable(); 43 | 44 | /** 45 | * @return bool 46 | */ 47 | public function isStartable(); 48 | 49 | /** 50 | * @return bool 51 | */ 52 | public function isCompletable(); 53 | 54 | /** 55 | * @return bool 56 | */ 57 | public function isCancelled(); 58 | 59 | /** 60 | * @return bool 61 | */ 62 | public function isEnded(); 63 | 64 | /** 65 | * @return ParticipantInterface 66 | */ 67 | public function getParticipant(); 68 | 69 | /** 70 | * @return \DateTime 71 | */ 72 | public function getCreationDate(); 73 | 74 | /** 75 | * @return \DateTime 76 | */ 77 | public function getAllocationDate(); 78 | 79 | /** 80 | * @return \DateTime 81 | */ 82 | public function getStartDate(); 83 | 84 | /** 85 | * @return \DateTime 86 | */ 87 | public function getEndDate(); 88 | 89 | /** 90 | * @return ParticipantInterface 91 | */ 92 | public function getEndParticipant(); 93 | 94 | /** 95 | * @return string 96 | */ 97 | public function getEndResult(); 98 | 99 | /** 100 | * @param ParticipantInterface $participant 101 | */ 102 | public function allocate(ParticipantInterface $participant); 103 | 104 | /** 105 | * @return void 106 | */ 107 | public function start(): void; 108 | 109 | /** 110 | * @param ParticipantInterface $participant 111 | */ 112 | public function complete(ParticipantInterface $participant); 113 | 114 | /** 115 | * @return void 116 | */ 117 | public function cancel(): void; 118 | } 119 | -------------------------------------------------------------------------------- /src/Workflow/ActivityLog.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | use PHPMentors\Workflower\Workflow\Activity\ActivityInterface; 16 | use PHPMentors\Workflower\Workflow\Activity\WorkItemInterface; 17 | 18 | class ActivityLog 19 | { 20 | /** 21 | * @var ActivityInterface 22 | */ 23 | private $activity; 24 | 25 | /** 26 | * @var WorkItemInterface 27 | */ 28 | private $workItem; 29 | 30 | /** 31 | * @param WorkItemInterface $workItem 32 | */ 33 | public function __construct(WorkItemInterface $workItem) 34 | { 35 | $this->workItem = $workItem; 36 | $this->activity = $workItem->getActivity(); 37 | } 38 | 39 | /** 40 | * @return ActivityInterface 41 | */ 42 | public function getActivity() 43 | { 44 | return $this->activity; 45 | } 46 | 47 | /** 48 | * @return WorkItemInterface 49 | */ 50 | public function getWorkItem() 51 | { 52 | return $this->workItem; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Workflow/ActivityLogCollection.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | class ActivityLogCollection implements \Countable, \IteratorAggregate 16 | { 17 | /** 18 | * @var ActivityLog[] 19 | */ 20 | private $activityLogs = []; 21 | 22 | /** 23 | * @var array 24 | */ 25 | private $lastWorkItemIndexByActivity = []; 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function add(ActivityLog $activityLog) 31 | { 32 | $this->activityLogs[] = $activityLog; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | * 38 | * @return ActivityLog|null 39 | */ 40 | public function get($key) 41 | { 42 | if (!array_key_exists($key, $this->activityLogs)) { 43 | return null; 44 | } 45 | 46 | return $this->activityLogs[$key]; 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function count() 53 | { 54 | return count($this->activityLogs); 55 | } 56 | 57 | /** 58 | * {@inheritdoc} 59 | */ 60 | public function getIterator() 61 | { 62 | return new \ArrayIterator($this->activityLogs); 63 | } 64 | 65 | /* 66 | * {@inheritDoc} 67 | */ 68 | public function toArray() 69 | { 70 | return $this->activityLogs; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Workflow/Connection/SequenceFlow.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Connection; 14 | 15 | use PHPMentors\Workflower\Workflow\Element\ConnectingObjectInterface; 16 | use PHPMentors\Workflower\Workflow\Element\FlowObjectInterface; 17 | use PHPMentors\Workflower\Workflow\Element\TransitionalInterface; 18 | use Symfony\Component\ExpressionLanguage\Expression; 19 | 20 | class SequenceFlow implements ConnectingObjectInterface, \Serializable 21 | { 22 | /** 23 | * @var int|string 24 | */ 25 | private $id; 26 | 27 | /** 28 | * @var string 29 | */ 30 | private $name; 31 | 32 | /** 33 | * @var TransitionalInterface 34 | */ 35 | private $source; 36 | 37 | /** 38 | * @var FlowObjectInterface 39 | */ 40 | private $destination; 41 | 42 | /** 43 | * @var Expression 44 | */ 45 | private $condition; 46 | 47 | public function __construct(array $config = []) 48 | { 49 | foreach ($config as $name => $value) { 50 | if (property_exists(self::class, $name)) { 51 | $this->{$name} = $value; 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function serialize() 60 | { 61 | return serialize([ 62 | 'id' => $this->id, 63 | 'name' => $this->name, 64 | 'source' => $this->source, 65 | 'destination' => $this->destination, 66 | 'condition' => $this->condition, 67 | ]); 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public function unserialize($serialized) 74 | { 75 | foreach (unserialize($serialized) as $name => $value) { 76 | if (property_exists($this, $name)) { 77 | $this->$name = $value; 78 | } 79 | } 80 | } 81 | 82 | /** 83 | * {@inheritdoc} 84 | * 85 | * @return int|string 86 | */ 87 | public function getId() 88 | { 89 | return $this->id; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function getName() 96 | { 97 | return $this->name; 98 | } 99 | 100 | /** 101 | * {@inheritdoc} 102 | */ 103 | public function getSource() 104 | { 105 | return $this->source; 106 | } 107 | 108 | /** 109 | * {@inheritdoc} 110 | */ 111 | public function getDestination() 112 | { 113 | return $this->destination; 114 | } 115 | 116 | /** 117 | * @return Expression 118 | */ 119 | public function getCondition() 120 | { 121 | return $this->condition; 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function equals($target) 128 | { 129 | if (!($target instanceof self)) { 130 | return false; 131 | } 132 | 133 | return $this->id === $target->getId(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Workflow/Element/ConditionalInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | interface ConditionalInterface 16 | { 17 | /** 18 | * @param int|string $sequenceFlowId 19 | */ 20 | public function setDefaultSequenceFlowId($sequenceFlowId); 21 | 22 | /** 23 | * @return int|string 24 | */ 25 | public function getDefaultSequenceFlowId(); 26 | } 27 | -------------------------------------------------------------------------------- /src/Workflow/Element/ConnectingObjectCollection.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | class ConnectingObjectCollection implements \Countable, \IteratorAggregate, \Serializable 16 | { 17 | /** 18 | * @var array 19 | */ 20 | private $connectingObjects = []; 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function serialize() 26 | { 27 | return serialize([ 28 | 'connectingObjects' => $this->connectingObjects, 29 | ]); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function unserialize($serialized) 36 | { 37 | foreach (unserialize($serialized) as $name => $value) { 38 | if (property_exists($this, $name)) { 39 | $this->$name = $value; 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function add(ConnectingObjectInterface $connectingObject) 48 | { 49 | $this->connectingObjects[$connectingObject->getId()] = $connectingObject; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | * 55 | * @return ConnectingObjectInterface|null 56 | */ 57 | public function get($key) 58 | { 59 | if (!array_key_exists($key, $this->connectingObjects)) { 60 | return null; 61 | } 62 | 63 | return $this->connectingObjects[$key]; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function count() 70 | { 71 | return count($this->connectingObjects); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function getIterator() 78 | { 79 | return new \ArrayIterator($this->connectingObjects); 80 | } 81 | 82 | /** 83 | * @param TransitionalInterface $flowObject 84 | * 85 | * @return ConnectingObjectCollection 86 | */ 87 | public function filterBySource(TransitionalInterface $flowObject) 88 | { 89 | $collection = new static(); 90 | 91 | foreach ($this as $connectingObject) { /* @var $connectingObject ConnectingObjectInterface */ 92 | if ($connectingObject->getSource()->getId() === $flowObject->getId()) { 93 | $collection->add($connectingObject); 94 | } 95 | } 96 | 97 | return $collection; 98 | } 99 | 100 | /** 101 | * @param TransitionalInterface $flowObject 102 | * 103 | * @return ConnectingObjectCollection 104 | * 105 | * @since Method available since Release 2.0.0 106 | */ 107 | public function filterByDestination(TransitionalInterface $flowObject): ConnectingObjectCollection 108 | { 109 | $collection = new static(); 110 | 111 | foreach ($this as $connectingObject) { /* @var $connectingObject ConnectingObjectInterface */ 112 | if ($connectingObject->getDestination()->getId() === $flowObject->getId()) { 113 | $collection->add($connectingObject); 114 | } 115 | } 116 | 117 | return $collection; 118 | } 119 | 120 | /* 121 | * {@inheritDoc} 122 | */ 123 | public function toArray() 124 | { 125 | return $this->connectingObjects; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Workflow/Element/ConnectingObjectInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | interface ConnectingObjectInterface extends WorkflowElementInterface 16 | { 17 | /** 18 | * @return TransitionalInterface 19 | */ 20 | public function getSource(); 21 | 22 | /** 23 | * @return FlowObjectInterface 24 | */ 25 | public function getDestination(); 26 | } 27 | -------------------------------------------------------------------------------- /src/Workflow/Element/FlowObject.php: -------------------------------------------------------------------------------- 1 | $value) { 32 | if (property_exists(self::class, $name)) { 33 | $this->{$name} = $value; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function serialize() 42 | { 43 | return serialize([ 44 | 'token' => $this->token, 45 | 'started' => $this->started, 46 | ]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function unserialize($serialized) 53 | { 54 | foreach (unserialize($serialized) as $name => $value) { 55 | if (property_exists($this, $name)) { 56 | $this->$name = $value; 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function getToken(): iterable 65 | { 66 | return $this->token; 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | public function attachToken(Token $token): void 73 | { 74 | $this->token[$token->getId()] = $token; 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function detachToken(Token $token): void 81 | { 82 | assert(array_key_exists($token->getId(), $this->getToken())); 83 | 84 | unset($this->token[$token->getId()]); 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | public function setProcessInstance(ProcessInstance $processInstance): void 91 | { 92 | $this->processInstance = $processInstance; 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | public function getProcessInstance(): ProcessInstance 99 | { 100 | return $this->processInstance; 101 | } 102 | 103 | /** 104 | * @return bool 105 | */ 106 | public function isStarted(): bool 107 | { 108 | return $this->started; 109 | } 110 | 111 | /** 112 | * {@inheritdoc} 113 | */ 114 | public function start(): void 115 | { 116 | $this->started = true; 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | public function end(): void 123 | { 124 | $this->started = false; 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | public function run(Token $token): void 131 | { 132 | $token->flow($this); 133 | 134 | if (!$this->isStarted()) { 135 | $this->start(); 136 | } 137 | 138 | $this->end(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Workflow/Element/FlowObjectCollection.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | class FlowObjectCollection implements \Countable, \IteratorAggregate, \Serializable 16 | { 17 | /** 18 | * @var array 19 | */ 20 | private $flowObjects = []; 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function serialize() 26 | { 27 | return serialize([ 28 | 'flowObjects' => $this->flowObjects, 29 | ]); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function unserialize($serialized) 36 | { 37 | foreach (unserialize($serialized) as $name => $value) { 38 | if (property_exists($this, $name)) { 39 | $this->$name = $value; 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function add(FlowObjectInterface $flowObject) 48 | { 49 | assert($flowObject instanceof FlowObjectInterface); 50 | 51 | $this->flowObjects[$flowObject->getId()] = $flowObject; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | * 57 | * @return FlowObjectInterface|null 58 | */ 59 | public function get($key) 60 | { 61 | if (!array_key_exists($key, $this->flowObjects)) { 62 | return null; 63 | } 64 | 65 | return $this->flowObjects[$key]; 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | */ 71 | public function count() 72 | { 73 | return count($this->flowObjects); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function getIterator() 80 | { 81 | return new \ArrayIterator($this->flowObjects); 82 | } 83 | 84 | /* 85 | * {@inheritDoc} 86 | */ 87 | public function toArray() 88 | { 89 | return $this->flowObjects; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Workflow/Element/FlowObjectInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | use PHPMentors\Workflower\Workflow\Participant\RoleAwareInterface; 16 | use PHPMentors\Workflower\Workflow\ProcessInstance; 17 | 18 | interface FlowObjectInterface extends RoleAwareInterface, WorkflowElementInterface 19 | { 20 | /** 21 | * @param Token $token 22 | * 23 | * @since Method available since Release 2.0.0 24 | */ 25 | public function attachToken(Token $token): void; 26 | 27 | /** 28 | * @param Token $token 29 | * 30 | * @since Method available since Release 2.0.0 31 | */ 32 | public function detachToken(Token $token): void; 33 | 34 | /** 35 | * @param ProcessInstance $processInstance 36 | * 37 | * @since Method available since Release 2.0.0 38 | */ 39 | public function setProcessInstance(ProcessInstance $processInstance): void; 40 | 41 | /** 42 | * @return ProcessInstance 43 | * 44 | * @since Method available since Release 2.0.0 45 | */ 46 | public function getProcessInstance(): ProcessInstance; 47 | 48 | /** 49 | * @return bool 50 | * 51 | * @since Method available since Release 2.0.0 52 | */ 53 | public function isStarted(): bool; 54 | 55 | /** 56 | * @since Method available since Release 2.0.0 57 | */ 58 | public function start(): void; 59 | 60 | /** 61 | * @since Method available since Release 2.0.0 62 | */ 63 | public function end(): void; 64 | 65 | /** 66 | * @param Token $token 67 | * 68 | * @since Method available since Release 2.0.0 69 | */ 70 | public function run(Token $token): void; 71 | } 72 | -------------------------------------------------------------------------------- /src/Workflow/Element/Token.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved.p 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | class Token 16 | { 17 | /** 18 | * @var string 19 | */ 20 | private $id; 21 | 22 | /** 23 | * @var FlowObjectInterface 24 | */ 25 | private $currentFlowObject; 26 | 27 | /** 28 | * @var FlowObjectInterface 29 | */ 30 | private $previousFlowObject; 31 | 32 | /** 33 | * @param string $id 34 | * @param FlowObjectInterface $flowObject 35 | */ 36 | public function __construct(string $id, FlowObjectInterface $flowObject) 37 | { 38 | $this->id = $id; 39 | $this->currentFlowObject = $flowObject; 40 | $this->currentFlowObject->attachToken($this); 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getId(): string 47 | { 48 | return $this->id; 49 | } 50 | 51 | /** 52 | * @return FlowObjectInterface 53 | */ 54 | public function getCurrentFlowObject(): FlowObjectInterface 55 | { 56 | return $this->currentFlowObject; 57 | } 58 | 59 | /** 60 | * @return FlowObjectInterface|null 61 | */ 62 | public function getPreviousFlowObject(): ?FlowObjectInterface 63 | { 64 | return $this->previousFlowObject; 65 | } 66 | 67 | /** 68 | * @param FlowObjectInterface $flowObject 69 | * 70 | * @return Token 71 | */ 72 | public function flow(FlowObjectInterface $flowObject): Token 73 | { 74 | $this->currentFlowObject->detachToken($this); 75 | $flowObject->attachToken($this); 76 | $this->previousFlowObject = $this->currentFlowObject; 77 | $this->currentFlowObject = $flowObject; 78 | 79 | return $this; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Workflow/Element/TransitionalInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | interface TransitionalInterface 16 | { 17 | /** 18 | * @return Token[] 19 | */ 20 | public function getToken(): iterable; 21 | } 22 | -------------------------------------------------------------------------------- /src/Workflow/Element/WorkflowElementInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Element; 14 | 15 | interface WorkflowElementInterface 16 | { 17 | /** 18 | * @return string 19 | */ 20 | public function getName(); 21 | } 22 | -------------------------------------------------------------------------------- /src/Workflow/Event/EndEvent.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Event; 14 | 15 | class EndEvent extends Event 16 | { 17 | /** 18 | * @var \DateTime 19 | * 20 | * @since Property available since Release 2.0.0 21 | */ 22 | private $endDate; 23 | 24 | /** 25 | * {@inheritdoc} 26 | * 27 | * @since Method available since Release 2.0.0 28 | */ 29 | public function serialize() 30 | { 31 | return serialize([ 32 | get_parent_class($this) => parent::serialize(), 33 | 'endDate' => $this->endDate, 34 | ]); 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function unserialize($serialized) 41 | { 42 | foreach (unserialize($serialized) as $name => $value) { 43 | if ($name == get_parent_class($this)) { 44 | parent::unserialize($value); 45 | continue; 46 | } 47 | 48 | if (property_exists($this, $name)) { 49 | $this->$name = $value; 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * @return \DateTime|null 56 | */ 57 | public function getEndDate(): ?\DateTime 58 | { 59 | return $this->endDate; 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | public function end(): void 66 | { 67 | $this->endDate = new \DateTime(); 68 | $this->getProcessInstance()->end($this); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Workflow/Event/Event.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Event; 14 | 15 | use PHPMentors\Workflower\Workflow\Element\FlowObject; 16 | use PHPMentors\Workflower\Workflow\Participant\Role; 17 | 18 | /** 19 | * @since Class available since Release 2.0.0 20 | */ 21 | abstract class Event extends FlowObject implements EventInterface 22 | { 23 | /** 24 | * @var int|string 25 | */ 26 | private $id; 27 | 28 | /** 29 | * @var string 30 | */ 31 | private $name; 32 | 33 | /** 34 | * @var Role 35 | */ 36 | private $role; 37 | 38 | public function __construct(array $config = []) 39 | { 40 | parent::__construct($config); 41 | 42 | foreach ($config as $name => $value) { 43 | if (property_exists(self::class, $name)) { 44 | $this->{$name} = $value; 45 | } 46 | } 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function serialize() 53 | { 54 | return serialize([ 55 | get_parent_class($this) => parent::serialize(), 56 | 'id' => $this->id, 57 | 'name' => $this->name, 58 | 'role' => $this->role, 59 | ]); 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | public function unserialize($serialized) 66 | { 67 | foreach (unserialize($serialized) as $name => $value) { 68 | if ($name == get_parent_class($this)) { 69 | parent::unserialize($value); 70 | continue; 71 | } 72 | 73 | if (property_exists($this, $name)) { 74 | $this->$name = $value; 75 | } 76 | } 77 | } 78 | 79 | /** 80 | * {@inheritdoc} 81 | * 82 | * @return string 83 | */ 84 | public function getId() 85 | { 86 | return $this->id; 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | public function getName() 93 | { 94 | return $this->name; 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function getRole() 101 | { 102 | return $this->role; 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | */ 108 | public function equals($target) 109 | { 110 | if (!($target instanceof self)) { 111 | return false; 112 | } 113 | 114 | return $this->id === $target->getId(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Workflow/Event/EventInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Event; 14 | 15 | use PHPMentors\Workflower\Workflow\Element\FlowObjectInterface; 16 | 17 | interface EventInterface extends FlowObjectInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /src/Workflow/Event/StartEvent.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved.p 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Event; 14 | 15 | use PHPMentors\Workflower\Workflow\Connection\SequenceFlow; 16 | use PHPMentors\Workflower\Workflow\Element\ConnectingObjectInterface; 17 | use PHPMentors\Workflower\Workflow\Element\TransitionalInterface; 18 | use PHPMentors\Workflower\Workflow\SequenceFlowNotSelectedException; 19 | 20 | class StartEvent extends Event implements TransitionalInterface, \Serializable 21 | { 22 | /** 23 | * @var \DateTime 24 | * 25 | * @since Property available since Release 2.0.0 26 | */ 27 | private $startDate; 28 | 29 | /** 30 | * {@inheritdoc} 31 | * 32 | * @since Method available since Release 2.0.0 33 | */ 34 | public function serialize() 35 | { 36 | return serialize([ 37 | get_parent_class($this) => parent::serialize(), 38 | 'startDate' => $this->startDate, 39 | ]); 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function unserialize($serialized) 46 | { 47 | foreach (unserialize($serialized) as $name => $value) { 48 | if ($name == get_parent_class($this)) { 49 | parent::unserialize($value); 50 | continue; 51 | } 52 | 53 | if (property_exists($this, $name)) { 54 | $this->$name = $value; 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * @return \DateTime|null 61 | */ 62 | public function getStartDate(): ?\DateTime 63 | { 64 | return $this->startDate; 65 | } 66 | 67 | public function start(): void 68 | { 69 | parent::start(); 70 | $this->startDate = new \DateTime(); 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | */ 76 | public function end(): void 77 | { 78 | $selectedSequenceFlows = []; 79 | $processInstance = $this->getProcessInstance(); 80 | 81 | // for each sequence flow that leaves a start event start a parallel token 82 | foreach ($processInstance->getConnectingObjectCollectionBySource($this) as $connectingObject) { /* @var $connectingObject ConnectingObjectInterface */ 83 | if ($connectingObject instanceof SequenceFlow) { 84 | $selectedSequenceFlows[] = $connectingObject; 85 | } 86 | } 87 | 88 | if (count($selectedSequenceFlows) == 0) { 89 | throw new SequenceFlowNotSelectedException(sprintf('No sequence flow can be selected on "%s".', $this->getId())); 90 | } 91 | 92 | foreach ($this->getToken() as $token) { 93 | $processInstance->removeToken($this, $token); 94 | } 95 | 96 | // if there are multiple sequence flows available then the processInstance runs in parallel 97 | foreach ($selectedSequenceFlows as $selectedSequenceFlow) { 98 | $token = $processInstance->generateToken($this); 99 | $selectedSequenceFlow->getDestination()->run($token); 100 | } 101 | 102 | parent::end(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Workflow/Event/TerminateEndEvent.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Gateway; 14 | 15 | use PHPMentors\Workflower\Workflow\Connection\SequenceFlow; 16 | use PHPMentors\Workflower\Workflow\Element\ConditionalInterface; 17 | use PHPMentors\Workflower\Workflow\SequenceFlowNotSelectedException; 18 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage; 19 | 20 | /** 21 | * @since Class available since Release 2.0.0 22 | */ 23 | class ExclusiveGateway extends Gateway implements ConditionalInterface 24 | { 25 | /** 26 | * @var int|string 27 | */ 28 | private $defaultSequenceFlowId; 29 | 30 | public function __construct(array $config = []) 31 | { 32 | parent::__construct($config); 33 | 34 | foreach ($config as $name => $value) { 35 | if (property_exists(self::class, $name)) { 36 | $this->{$name} = $value; 37 | } 38 | } 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function serialize() 45 | { 46 | return serialize([ 47 | get_parent_class($this) => parent::serialize(), 48 | 'defaultSequenceFlowId' => $this->defaultSequenceFlowId, 49 | ]); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function unserialize($serialized) 56 | { 57 | foreach (unserialize($serialized) as $name => $value) { 58 | if ($name == get_parent_class($this)) { 59 | parent::unserialize($value); 60 | continue; 61 | } 62 | 63 | if (property_exists($this, $name)) { 64 | $this->$name = $value; 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | public function setDefaultSequenceFlowId($sequenceFlowId) 73 | { 74 | $this->defaultSequenceFlowId = $sequenceFlowId; 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function getDefaultSequenceFlowId() 81 | { 82 | return $this->defaultSequenceFlowId; 83 | } 84 | 85 | /** 86 | * {@inheritdoc} 87 | */ 88 | public function end(): void 89 | { 90 | $processInstance = $this->getProcessInstance(); 91 | $selectedSequenceFlow = null; 92 | 93 | // Each token arriving at any incoming Sequence Flows activates the 94 | // gateway and is routed to exactly one of the outgoing Sequence Flows. 95 | // In order to determine the outgoing Sequence Flows that receives the 96 | // token, the conditions are evaluated in order. The first condition that 97 | // evaluates to true determines the Sequence Flow the token is sent to. 98 | // No more conditions are henceforth evaluated. 99 | // If and only if none of the conditions evaluates to true, the token is passed 100 | // on the default Sequence Flow. 101 | // In case all conditions evaluate to false and a default flow has not been 102 | // specified, an exception is thrown. 103 | 104 | foreach ($processInstance->getConnectingObjectCollectionBySource($this) as $outgoing) { 105 | if ($outgoing instanceof SequenceFlow && $outgoing->getId() !== $this->getDefaultSequenceFlowId()) { 106 | $condition = $outgoing->getCondition(); 107 | if ($condition === null) { 108 | // find the next one that has a condition 109 | continue; 110 | } else { 111 | $expressionLanguage = $processInstance->getExpressionLanguage() ?: new ExpressionLanguage(); 112 | if ($expressionLanguage->evaluate($condition, $processInstance->getProcessData())) { 113 | $selectedSequenceFlow = $outgoing; 114 | break; 115 | } 116 | } 117 | } 118 | } 119 | 120 | if (!$selectedSequenceFlow) { 121 | $selectedSequenceFlow = $processInstance->getConnectingObject($this->getDefaultSequenceFlowId()); 122 | } 123 | 124 | if (!$selectedSequenceFlow) { 125 | throw new SequenceFlowNotSelectedException(sprintf('No sequence flow can be selected on "%s".', $this->getId())); 126 | } 127 | 128 | $token = $this->getToken(); 129 | assert(count($token) === 1); 130 | $token = current($token); 131 | 132 | $selectedSequenceFlow->getDestination()->run($token); 133 | parent::end(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Workflow/Gateway/Gateway.php: -------------------------------------------------------------------------------- 1 | $value) { 30 | if (property_exists(self::class, $name)) { 31 | $this->{$name} = $value; 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function serialize() 40 | { 41 | return serialize([ 42 | get_parent_class($this) => parent::serialize(), 43 | 'id' => $this->id, 44 | 'name' => $this->name, 45 | 'role' => $this->role, 46 | ]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function unserialize($serialized) 53 | { 54 | foreach (unserialize($serialized) as $name => $value) { 55 | if ($name == get_parent_class($this)) { 56 | parent::unserialize($value); 57 | continue; 58 | } 59 | 60 | if (property_exists($this, $name)) { 61 | $this->$name = $value; 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | * 69 | * @return int|string 70 | */ 71 | public function getId() 72 | { 73 | return $this->id; 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function getRole() 80 | { 81 | return $this->role; 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function getName() 88 | { 89 | return $this->name; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function equals($target) 96 | { 97 | if (!($target instanceof self)) { 98 | return false; 99 | } 100 | 101 | return $this->id === $target->getId(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Workflow/Gateway/GatewayInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Gateway; 14 | 15 | use PHPMentors\Workflower\Workflow\Element\FlowObjectInterface; 16 | use PHPMentors\Workflower\Workflow\Element\TransitionalInterface; 17 | 18 | interface GatewayInterface extends FlowObjectInterface, TransitionalInterface 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Workflow/Gateway/InclusiveGateway.php: -------------------------------------------------------------------------------- 1 | $value) { 24 | if (property_exists(self::class, $name)) { 25 | $this->{$name} = $value; 26 | } 27 | } 28 | } 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public function serialize() 34 | { 35 | return serialize([ 36 | get_parent_class($this) => parent::serialize(), 37 | 'defaultSequenceFlowId' => $this->defaultSequenceFlowId, 38 | ]); 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function unserialize($serialized) 45 | { 46 | foreach (unserialize($serialized) as $name => $value) { 47 | if ($name == get_parent_class($this)) { 48 | parent::unserialize($value); 49 | continue; 50 | } 51 | 52 | if (property_exists($this, $name)) { 53 | $this->$name = $value; 54 | } 55 | } 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function setDefaultSequenceFlowId($sequenceFlowId) 62 | { 63 | $this->defaultSequenceFlowId = $sequenceFlowId; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function getDefaultSequenceFlowId() 70 | { 71 | return $this->defaultSequenceFlowId; 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function end(): void 78 | { 79 | $processInstance = $this->getProcessInstance(); 80 | $incoming = $processInstance->getConnectingObjectCollectionByDestination($this); 81 | $incomingTokens = $this->getToken(); 82 | 83 | $valid = count($incomingTokens) === count($incoming); 84 | 85 | if (!$valid) { 86 | $tokensToWait = 0; 87 | // check if there is another token that can arrive here 88 | foreach ($processInstance->getCurrentFlowObjects() as $flowObject) { 89 | if ($flowObject !== $this && $this->isPathLeadingOurWay($flowObject)) { 90 | ++$tokensToWait; 91 | break; 92 | } 93 | } 94 | $valid = $tokensToWait === 0; 95 | } 96 | 97 | // Upon execution, a token is consumed from each incoming Sequence Flow that 98 | // has a token. A token will be produced on some of the outgoing Sequence 99 | // Flows. 100 | // In order to determine the outgoing Sequence Flows that receive a token, all 101 | // conditions on the outgoing Sequence Flows are evaluated. The evaluation 102 | // does not have to respect a certain order. 103 | // For every condition which evaluates to true, a token MUST be passed on the 104 | // respective Sequence Flow. 105 | // If and only if none of the conditions evaluates to true, the token is passed on the 106 | // default Sequence Flow. 107 | // In case all conditions evaluate to false and a default flow has not been specified, 108 | // the Inclusive Gateway throws an exception. 109 | 110 | if ($valid) { 111 | $selectedSequenceFlows = []; 112 | 113 | foreach ($processInstance->getConnectingObjectCollectionBySource($this) as $outgoing) { 114 | if ($outgoing instanceof SequenceFlow && $outgoing->getId() !== $this->getDefaultSequenceFlowId()) { 115 | $condition = $outgoing->getCondition(); 116 | if ($condition === null) { 117 | // find the next one that has a condition 118 | continue; 119 | } else { 120 | $expressionLanguage = $processInstance->getExpressionLanguage() ?: new ExpressionLanguage(); 121 | if ($expressionLanguage->evaluate($condition, $processInstance->getProcessData())) { 122 | $selectedSequenceFlows[] = $outgoing; 123 | } 124 | } 125 | } 126 | } 127 | 128 | if (count($selectedSequenceFlows) === 0) { 129 | $next = $processInstance->getConnectingObject($this->getDefaultSequenceFlowId()); 130 | 131 | if ($next) { 132 | $selectedSequenceFlows[] = $next; 133 | } 134 | } 135 | 136 | if (count($selectedSequenceFlows) === 0) { 137 | throw new SequenceFlowNotSelectedException(sprintf('No sequence flow can be selected on "%s".', $this->getId())); 138 | } 139 | 140 | foreach ($incomingTokens as $incomingToken) { 141 | $processInstance->removeToken($this, $incomingToken); 142 | } 143 | 144 | foreach ($selectedSequenceFlows as $selectedSequenceFlow) { 145 | $token = $processInstance->generateToken($this); 146 | $selectedSequenceFlow->getDestination()->run($token); 147 | } 148 | 149 | parent::end(); 150 | } 151 | } 152 | 153 | private function isPathLeadingOurWay($flowObject) 154 | { 155 | $found = false; 156 | $flows = $this->getProcessInstance()->getConnectingObjectCollectionBySource($flowObject); 157 | 158 | foreach ($flows as $flow) { 159 | if ($flow instanceof SequenceFlow) { 160 | $next = $flow->getDestination(); 161 | if ($next === $this) { 162 | $found = true; 163 | } else { 164 | $found = $this->isPathLeadingOurWay($next); 165 | } 166 | 167 | if ($found) { 168 | break; 169 | } 170 | } 171 | } 172 | 173 | return $found; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Workflow/Gateway/ParallelGateway.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Gateway; 14 | 15 | use PHPMentors\Workflower\Workflow\Connection\SequenceFlow; 16 | 17 | /** 18 | * @since Class available since Release 2.0.0 19 | */ 20 | class ParallelGateway extends Gateway 21 | { 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function serialize() 26 | { 27 | return serialize([ 28 | get_parent_class($this) => parent::serialize(), 29 | ]); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function unserialize($serialized) 36 | { 37 | foreach (unserialize($serialized) as $name => $value) { 38 | if ($name == get_parent_class($this)) { 39 | parent::unserialize($value); 40 | continue; 41 | } 42 | 43 | if (property_exists($this, $name)) { 44 | $this->$name = $value; 45 | } 46 | } 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function end(): void 53 | { 54 | $processInstance = $this->getProcessInstance(); 55 | $incoming = $processInstance->getConnectingObjectCollectionByDestination($this); 56 | $incomingTokens = $this->getToken(); 57 | 58 | // The Parallel Gateway is activated if there is at least one token on each 59 | // incoming Sequence Flow. 60 | // The Parallel Gateway consumes exactly one token from each incoming 61 | // Sequence Flow and produces exactly one token at each outgoing Sequence 62 | // Flow. 63 | // If there are excess tokens at an incoming Sequence Flow, these tokens remain at 64 | // this Sequence Flow after execution of the Gateway. 65 | 66 | if (count($incomingTokens) == count($incoming)) { 67 | foreach ($incomingTokens as $incomingToken) { 68 | $processInstance->removeToken($this, $incomingToken); 69 | } 70 | 71 | foreach ($processInstance->getConnectingObjectCollectionBySource($this) as $outgoing) { 72 | if ($outgoing instanceof SequenceFlow) { 73 | $token = $processInstance->generateToken($this); 74 | $destination = $outgoing->getDestination(); 75 | $destination->run($token); 76 | } 77 | } 78 | } 79 | 80 | parent::end(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Workflow/ItemInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | use PHPMentors\Workflower\Workflow\Activity\ActivityInterface; 16 | 17 | /** 18 | * @since Interface available since Release 2.0.0 19 | */ 20 | interface ItemInterface 21 | { 22 | /** 23 | * @return int|string 24 | */ 25 | public function getId(); 26 | 27 | /** 28 | * @param ProcessInstanceInterface $processInstance 29 | * 30 | * @return void 31 | */ 32 | public function setProcessInstance(ProcessInstanceInterface $processInstance); 33 | 34 | /** 35 | * @return ProcessInstanceInterface|null 36 | */ 37 | public function getProcessInstance(); 38 | 39 | /** 40 | * @param ActivityInterface $activity 41 | */ 42 | public function setActivity(ActivityInterface $activity); 43 | 44 | /** 45 | * @return ActivityInterface 46 | */ 47 | public function getActivity(); 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function getState(); 53 | 54 | /** 55 | * @return void 56 | */ 57 | public function cancel(); 58 | } 59 | -------------------------------------------------------------------------------- /src/Workflow/ItemsCollectionInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Operation; 14 | 15 | use PHPMentors\Workflower\Workflow\Activity\WorkItemInterface; 16 | use PHPMentors\Workflower\Workflow\Participant\ParticipantInterface; 17 | use PHPMentors\Workflower\Workflow\ProcessInstance; 18 | 19 | /** 20 | * @since Interface available since Release 1.2.0 21 | */ 22 | interface OperationRunnerInterface 23 | { 24 | /** 25 | * @param OperationalInterface $operational 26 | * @param ProcessInstance $processInstance 27 | * 28 | * @return ParticipantInterface 29 | */ 30 | public function provideParticipant(OperationalInterface $operational, ProcessInstance $processInstance); 31 | 32 | /** 33 | * @param WorkItemInterface $workItem 34 | * 35 | * @return void 36 | */ 37 | public function run(WorkItemInterface $workItem); 38 | } 39 | -------------------------------------------------------------------------------- /src/Workflow/Operation/OperationalInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Operation; 14 | 15 | /** 16 | * @since Interface available since Release 1.2.0 17 | */ 18 | interface OperationalInterface 19 | { 20 | /** 21 | * @return int|string 22 | */ 23 | public function getOperation(); 24 | } 25 | -------------------------------------------------------------------------------- /src/Workflow/Participant/LoggedParticipant.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | use PHPMentors\Workflower\Workflow\Resource\ResourceInterface; 16 | 17 | class LoggedParticipant implements ParticipantInterface, \Serializable 18 | { 19 | /** 20 | * @var int|string 21 | */ 22 | private $id; 23 | 24 | /** 25 | * @var string 26 | */ 27 | private $name; 28 | 29 | /** 30 | * @param ParticipantInterface $participant 31 | */ 32 | public function __construct(ParticipantInterface $participant) 33 | { 34 | $this->id = $participant->getId(); 35 | $this->name = $participant->getName(); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function serialize() 42 | { 43 | return serialize([ 44 | 'id' => $this->id, 45 | 'name' => $this->name, 46 | ]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function unserialize($serialized) 53 | { 54 | foreach (unserialize($serialized) as $name => $value) { 55 | if (property_exists($this, $name)) { 56 | $this->$name = $value; 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function hasRole($role) 65 | { 66 | throw $this->createOperationNotFoundException(__FUNCTION__); 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | public function setResource(ResourceInterface $resource) 73 | { 74 | throw $this->createOperationNotFoundException(__FUNCTION__); 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function getResource() 81 | { 82 | throw $this->createOperationNotFoundException(__FUNCTION__); 83 | } 84 | 85 | /** 86 | * {@inheritdoc} 87 | */ 88 | public function getId() 89 | { 90 | return $this->id; 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | public function getName() 97 | { 98 | return $this->name; 99 | } 100 | 101 | /** 102 | * @param string $method 103 | * 104 | * @return OperationNotSupportedException 105 | */ 106 | private function createOperationNotFoundException($method) 107 | { 108 | return new OperationNotSupportedException(sprintf( 109 | 'The method "%s" is not supported by "%s". Use your ParticipantInterface object instead.', 110 | $method, 111 | get_class($this) 112 | )); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Workflow/Participant/OperationNotSupportedException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | class OperationNotSupportedException extends \LogicException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Workflow/Participant/ParticipantInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | use PHPMentors\Workflower\Workflow\Resource\ResourceInterface; 16 | 17 | interface ParticipantInterface 18 | { 19 | /** 20 | * @param string $role 21 | * 22 | * @return bool 23 | */ 24 | public function hasRole($role); 25 | 26 | /** 27 | * @param ResourceInterface $resource 28 | */ 29 | public function setResource(ResourceInterface $resource); 30 | 31 | /** 32 | * @return ResourceInterface 33 | */ 34 | public function getResource(); 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getName(); 40 | } 41 | -------------------------------------------------------------------------------- /src/Workflow/Participant/Role.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | class Role implements \Serializable 16 | { 17 | /** 18 | * @var int|string 19 | */ 20 | private $id; 21 | 22 | /** 23 | * @var string 24 | */ 25 | private $name; 26 | 27 | public function __construct(array $config = []) 28 | { 29 | foreach ($config as $name => $value) { 30 | if (property_exists(self::class, $name)) { 31 | $this->{$name} = $value; 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function serialize() 40 | { 41 | return serialize([ 42 | 'id' => $this->id, 43 | 'name' => $this->name, 44 | ]); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function unserialize($serialized) 51 | { 52 | foreach (unserialize($serialized) as $name => $value) { 53 | if (property_exists($this, $name)) { 54 | $this->$name = $value; 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | * 62 | * @return int|string 63 | */ 64 | public function getId() 65 | { 66 | return $this->id; 67 | } 68 | 69 | /** 70 | * @return string 71 | */ 72 | public function getName() 73 | { 74 | return $this->name; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Workflow/Participant/RoleAwareInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | interface RoleAwareInterface 16 | { 17 | /** 18 | * @return Role 19 | */ 20 | public function getRole(); 21 | } 22 | -------------------------------------------------------------------------------- /src/Workflow/Participant/RoleCollection.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Participant; 14 | 15 | class RoleCollection implements \Countable, \IteratorAggregate, \Serializable 16 | { 17 | /** 18 | * @var array 19 | */ 20 | private $roles = []; 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function serialize() 26 | { 27 | return serialize([ 28 | 'roles' => $this->roles, 29 | ]); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function unserialize($serialized) 36 | { 37 | foreach (unserialize($serialized) as $name => $value) { 38 | if (property_exists($this, $name)) { 39 | $this->$name = $value; 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function add(Role $role) 48 | { 49 | assert($role instanceof Role); 50 | 51 | $this->roles[$role->getId()] = $role; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | * 57 | * @return Role|null 58 | */ 59 | public function get($key) 60 | { 61 | if (array_key_exists($key, $this->roles)) { 62 | return $this->roles[$key]; 63 | } else { 64 | return null; 65 | } 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | */ 71 | public function count() 72 | { 73 | return count($this->roles); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function getIterator() 80 | { 81 | return new \ArrayIterator($this->roles); 82 | } 83 | 84 | /* 85 | * {@inheritDoc} 86 | */ 87 | public function toArray() 88 | { 89 | return $this->roles; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Workflow/ProcessDefinitionInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | /** 16 | * @since Class available since Release 2.0.0 17 | */ 18 | interface ProcessDefinitionRepositoryInterface 19 | { 20 | /** 21 | * @param ProcessDefinitionInterface $definition 22 | * 23 | * @return ProcessDefinitionInterface} 24 | */ 25 | public function add(ProcessDefinitionInterface $definition); 26 | 27 | /** 28 | * @param string $id 29 | * 30 | * @return ProcessDefinitionInterface 31 | */ 32 | public function getLatestById(string $id); 33 | 34 | /** 35 | * @param string $name 36 | * 37 | * @return ProcessDefinitionInterface 38 | */ 39 | public function getLatestByName(string $name); 40 | 41 | /** 42 | * @param string $id 43 | * @param int $version 44 | * 45 | * @return ProcessDefinitionInterface 46 | */ 47 | public function getVersionById(string $id, int $version); 48 | 49 | /** 50 | * @param string $name 51 | * @param int $version 52 | * 53 | * @return ProcessDefinitionInterface 54 | */ 55 | public function getVersionByName(string $name, int $version); 56 | } 57 | -------------------------------------------------------------------------------- /src/Workflow/ProcessInstanceInterface.php: -------------------------------------------------------------------------------- 1 | items, function (ItemInterface $item) { 10 | $state = $item->getState(); 11 | 12 | return $state !== ProcessInstanceInterface::STATE_ENDED && $state !== ProcessInstanceInterface::STATE_CANCELLED; 13 | }); 14 | } 15 | 16 | public function getCompletedInstances() 17 | { 18 | return array_filter($this->items, function (ItemInterface $item) { 19 | $state = $item->getState(); 20 | 21 | return $state === ProcessInstanceInterface::STATE_ENDED || $state === ProcessInstanceInterface::STATE_CANCELLED; 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Workflow/Provider/DataNotFoundException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Resource; 14 | 15 | /** 16 | * @since Interface available since Release 1.3.0 17 | */ 18 | interface MessageInterface 19 | { 20 | /** 21 | * @return int|string 22 | */ 23 | public function getMessage(); 24 | } 25 | -------------------------------------------------------------------------------- /src/Workflow/Resource/ResourceInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow\Resource; 14 | 15 | interface ResourceInterface 16 | { 17 | /** 18 | * @return string 19 | */ 20 | public function getName(); 21 | } 22 | -------------------------------------------------------------------------------- /src/Workflow/SequenceFlowNotSelectedException.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | class SequenceFlowNotSelectedException extends \RuntimeException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Workflow/WorkItemsCollection.php: -------------------------------------------------------------------------------- 1 | $this->items, 15 | ]); 16 | } 17 | 18 | public function unserialize($serialized) 19 | { 20 | foreach (unserialize($serialized) as $name => $value) { 21 | if (property_exists($this, $name)) { 22 | $this->$name = $value; 23 | } 24 | } 25 | } 26 | 27 | public function add(ItemInterface $item) 28 | { 29 | $this->items[] = $item; 30 | } 31 | 32 | public function remove(ItemInterface $item) 33 | { 34 | $this->items = array_filter($this->items, function (ItemInterface $currentItem) use ($item) { 35 | return $currentItem !== $item; 36 | }); 37 | } 38 | 39 | public function get($id) 40 | { 41 | foreach ($this->items as $item) { 42 | if ($item->getId() === $id) { 43 | return $item; 44 | } 45 | } 46 | throw new \OutOfBoundsException(sprintf('The item "%s" was not found.', $id)); 47 | } 48 | 49 | public function getAt(int $index) 50 | { 51 | if (!array_key_exists($index, $this->items)) { 52 | return null; 53 | } 54 | 55 | return $this->items[$index]; 56 | } 57 | 58 | public function getIterator() 59 | { 60 | return new \ArrayIterator($this->items); 61 | } 62 | 63 | public function count() 64 | { 65 | return count($this->items); 66 | } 67 | 68 | public function countOfActiveInstances(): int 69 | { 70 | return count($this->getActiveInstances()); 71 | } 72 | 73 | public function countOfCompletedInstances(): int 74 | { 75 | return count($this->getCompletedInstances()); 76 | } 77 | 78 | public function getActiveInstances() 79 | { 80 | return array_filter($this->items, function (ItemInterface $item) { 81 | $state = $item->getState(); 82 | 83 | return $state !== WorkItemInterface::STATE_ENDED && $state !== WorkItemInterface::STATE_CANCELLED; 84 | }); 85 | } 86 | 87 | public function getCompletedInstances() 88 | { 89 | return array_filter($this->items, function (ItemInterface $item) { 90 | $state = $item->getState(); 91 | 92 | return $state === WorkItemInterface::STATE_ENDED || $state === WorkItemInterface::STATE_CANCELLED; 93 | }); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Workflow/WorkflowRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Workflow; 14 | 15 | interface WorkflowRepositoryInterface 16 | { 17 | /** 18 | * @param int|string $id 19 | * 20 | * @return ProcessInstance|null 21 | */ 22 | public function findById($id): ?ProcessInstance; 23 | 24 | /** 25 | * @param ProcessInstance $processInstance 26 | */ 27 | public function add($processInstance): void; 28 | 29 | /** 30 | * @param ProcessInstance $processInstance 31 | */ 32 | public function remove($processInstance): void; 33 | } 34 | -------------------------------------------------------------------------------- /tests/Definition/Bpmn2ReaderTest.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | namespace PHPMentors\Workflower\Definition; 14 | 15 | use PHPMentors\Workflower\Workflow\WorkflowRepository; 16 | use PHPUnit\Framework\TestCase; 17 | 18 | class Bpmn2ReaderTest extends TestCase 19 | { 20 | /** 21 | * @test 22 | */ 23 | public function read() 24 | { 25 | $workflowRepository = new WorkflowRepository(); 26 | $bpmn2Reader = new Bpmn2Reader(); 27 | $definitions = $bpmn2Reader->read(dirname(__DIR__).'/Resources/config/workflower/LoanRequestProcess.bpmn'); 28 | 29 | $instance = $definitions[0]->createProcessInstance(); 30 | $dest = $workflowRepository->findById('LoanRequestProcess'); 31 | $definitions[0]->setProcessDefinitions($dest->getProcessDefinition()->getProcessDefinitions()); 32 | 33 | $this->assertThat($instance, $this->equalTo($dest)); 34 | } 35 | 36 | /** 37 | * @test 38 | * 39 | * @since Method available since Release 1.3.0 40 | */ 41 | public function readSource() 42 | { 43 | $workflowRepository = new WorkflowRepository(); 44 | $bpmn2Reader = new Bpmn2Reader(); 45 | $definitions = $bpmn2Reader->readSource(file_get_contents(dirname(__DIR__).'/Resources/config/workflower/LoanRequestProcess.bpmn')); 46 | 47 | $instance = $definitions[0]->createProcessInstance(); 48 | $dest = $workflowRepository->findById('LoanRequestProcess'); 49 | $definitions[0]->setProcessDefinitions($dest->getProcessDefinition()->getProcessDefinitions()); 50 | 51 | $this->assertThat($instance, $this->equalTo($dest)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/CallActivity.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | Flow_039u5vm 7 | Flow_0mtgdir 8 | 9 | 10 | 11 | SequenceFlow_2 12 | Flow_039u5vm 13 | Flow_1ir70xo 14 | 15 | 16 | 17 | SequenceFlow_1 18 | SequenceFlow_2 19 | 20 | 21 | 22 | 23 | 24 | Flow_0mtgdir 25 | Flow_1ir70xo 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/InclusiveGateway.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flow_1bdkzxf 6 | 7 | 8 | Flow_024hmut 9 | 10 | 11 | Flow_0ullg0q 12 | Flow_0uuwfkd 13 | 14 | 15 | Flow_1r2muxu 16 | Flow_0inmxft 17 | 18 | 19 | 20 | Flow_1bdkzxf 21 | Flow_0ullg0q 22 | Flow_1r2muxu 23 | 24 | 25 | paymentReceived == false 26 | 27 | 28 | shipOrder == true 29 | 30 | 31 | Flow_0uuwfkd 32 | Flow_0inmxft 33 | Flow_197saqg 34 | 35 | 36 | 37 | 38 | 39 | 40 | Flow_197saqg 41 | Flow_024hmut 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/NoLanesProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SequenceFlow_1 7 | 8 | 9 | 10 | SequenceFlow_2 11 | 12 | 13 | SequenceFlow_1 14 | SequenceFlow_2 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/ParallelGatewayProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_078pndg 6 | 7 | 8 | SequenceFlow_078pndg 9 | SequenceFlow_1wjbn1c 10 | SequenceFlow_02buwo5 11 | 12 | 13 | SequenceFlow_1wjbn1c 14 | SequenceFlow_11y8rqn 15 | 16 | 17 | SequenceFlow_02buwo5 18 | SequenceFlow_0c5g9hq 19 | 20 | 21 | SequenceFlow_11y8rqn 22 | SequenceFlow_0c5g9hq 23 | SequenceFlow_0o2q11g 24 | 25 | 26 | SequenceFlow_0o2q11g 27 | SequenceFlow_1mvlhdt 28 | 29 | 30 | SequenceFlow_1mvlhdt 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/ParallelSequenceFlows.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flow_07k30ec 6 | 7 | 8 | Flow_097c4uw 9 | Flow_0bkzntc 10 | 11 | 12 | Flow_07k30ec 13 | Flow_0my403k 14 | Flow_0djo966 15 | 16 | 17 | Flow_0my403k 18 | Flow_0bkzntc 19 | 20 | 21 | Flow_0djo966 22 | Flow_097c4uw 23 | 24 | 25 | stock < 10 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/ParallelUserTasks.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | 7 | 8 | 9 | SequenceFlow_2 10 | 11 | 12 | 13 | SequenceFlow_1 14 | SequenceFlow_2 15 | 16 | nrOfCompletedInstances == 2 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/SendTasksProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Message_1 17 | 18 | 19 | Message_2 20 | 21 | 22 | 23 | 24 | 25 | Start 26 | EndEvent_1 27 | SendTask_2 28 | SendTask_1 29 | 30 | 31 | 32 | SequenceFlow_4 33 | 34 | 35 | SequenceFlow_6 36 | 37 | 38 | SequenceFlow_4 39 | SequenceFlow_5 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | SequenceFlow_5 48 | SequenceFlow_6 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/SequentialUserTasks.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | 7 | 8 | 9 | SequenceFlow_2 10 | 11 | 12 | 13 | SequenceFlow_1 14 | SequenceFlow_2 15 | 16 | nrOfCompletedInstances == 2 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/ServiceTasksProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Message_2 12 | 13 | 14 | Message_2 15 | 16 | 17 | 18 | 19 | 20 | ServiceTask_2 21 | Start 22 | EndEvent_1 23 | ServiceTask_1 24 | 25 | 26 | 27 | SequenceFlow_1 28 | 29 | 30 | 31 | SequenceFlow_3 32 | 33 | 34 | SequenceFlow_1 35 | SequenceFlow_2 36 | 37 | 38 | 39 | 40 | 41 | 42 | SequenceFlow_2 43 | SequenceFlow_3 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /tests/Resources/config/workflower/SubProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | Flow_039u5vm 7 | Flow_0mtgdir 8 | 9 | 10 | 11 | SequenceFlow_2 12 | Flow_039u5vm 13 | Flow_1ir70xo 14 | 15 | 16 | 17 | SequenceFlow_1 18 | SequenceFlow_2 19 | 20 | 21 | 22 | Flow_0mtgdir 23 | Flow_1ir70xo 24 | 25 | Flow_0cs8lpp 26 | 27 | 28 | Flow_0cs8lpp 29 | Flow_05mr6lr 30 | 31 | 32 | Flow_05mr6lr 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | and contributors, 4 | * All rights reserved. 5 | * 6 | * This file is part of Workflower. 7 | * 8 | * This program and the accompanying materials are made available under 9 | * the terms of the BSD 2-Clause License which accompanies this 10 | * distribution, and is available at http://opensource.org/licenses/BSD-2-Clause 11 | */ 12 | 13 | error_reporting(E_ALL ^ E_DEPRECATED); 14 | 15 | require dirname(__DIR__).'/vendor/autoload.php'; 16 | --------------------------------------------------------------------------------