PHPackages                             alterway/component-workflow - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. alterway/component-workflow

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

alterway/component-workflow
===========================

Workflow component heavily used by Alter Way

v1.0.0(12y ago)653.7k9[1 issues](https://github.com/alterway/component-workflow/issues)PHP

Since Feb 18Pushed 11y ago14 watchersCompare

[ Source](https://github.com/alterway/component-workflow)[ Packagist](https://packagist.org/packages/alterway/component-workflow)[ RSS](/packages/alterway-component-workflow/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (1)Dependencies (2)Versions (2)Used By (0)

Workflow Component [![Build Status](https://camo.githubusercontent.com/b19d5d22a52c3384b744393bd9acc7ece99114e34a71cc6f6da714a097d4f1c4/68747470733a2f2f7472617669732d63692e6f72672f616c7465727761792f636f6d706f6e656e742d776f726b666c6f772e706e673f6272616e63683d6d6173746572)](https://travis-ci.org/alterway/component-workflow)
===================================================================================================================================================================================================================================================================================================================================

[](#workflow-component-)

This component provides a workflow engine written as a PHP library.

Instead of modeling a workflow as a Petri net or trying to enumerate workflow patterns, the library consider a workflow as a simple directed graph: vertices model nodes and edges model transitions.

### Nodes

[](#nodes)

A node represents a point in a life cycle. The `Node` class implements the concept. A node is referenced by a unique name across the workflow. The constraint is the responsibility of `NodeMap` class.

### Transitions

[](#transitions)

A transition is a link between nodes. The `Transition` class implements the concept. At creation, a transition is given a specification object implementing the `SpecificationInterface`. the specification is used as a business rule to decide where to advance in the workflow.

### Tokens

[](#tokens)

A token is a simple string used to initialize the workflow in a particular node. The idea is to consider the token as a thing placed at the center of a node. When workflow engine is on, the token is moving from node to node.

### Events

[](#events)

An event is an object created each time a token arrives at a node. The `Event` class implements the concept. This class extends the `Event` class from the Symfony EventDispatcher component. You can write listeners or subscribers to implement any business behaviour.

Usage
-----

[](#usage)

Let's say you are writing a blog engine in PHP and you want to implement the following workflow:

- an article begins its existence as a draft
- when ready, the article gets published
- if controversial, the article is deleted
- when too old, the article is archived

First of all, you need to write classes implementing `SpecificationInterface` for every business rule:

```
namespace BlogEngine\Domain\Specification;

use Alterway\Component\Workflow\ContextInterface;
use Alterway\Component\Workflow\SpecificationInterface;

class DraftableArticleSpecification implements SpecificationInterface
{
    public function isSatisfiedBy(ContextInterface $context)
    {
        // an article can always be drafted
        return true;
    }
}

class PublishableArticleSpecification implements SpecificationInterface
{
    public function isSatisfiedBy(ContextInterface $context)
    {
        // an article needs two reviews to be published
        return 1 < count($context->get('article')->getReviews());
    }
}

class DeletableArticleSpecification implements SpecificationInterface
{
    public function isSatisfiedBy(ContextInterface $context)
    {
        // an article can always be deleted if requested
        return 'delete' === $context->get('action');
    }
}

class ArchivableArticleSpecification implements SpecificationInterface
{
    public function isSatisfiedBy(ContextInterface $context)
    {
        // an article needs to be one month old to be archived
        $publishedAtPlusOneMonth = clone $context->get('publishedAt');
        $publishedAtPlusOneMonth->modify('+1 month');

        return 'archive' === $context->get('action') && $publishedAtPlusOneMonth < $context->get('now');
    }
}
```

Then, you can use the `Builder` class and the specifications to describe the workflow:

```
namespace BlogEngine\Domain\Service;

use Alterway\Component\Workflow\Builder;
use Alterway\Component\Workflow\ContextInterface;
use BlogEngine\Domain\Event\ArticleSubscriber;
use BlogEngine\Domain\Specification\DraftableArticleSpecification;
use BlogEngine\Domain\Specification\PublishableArticleSpecification;
use BlogEngine\Domain\Specification\DeletableArticleSpecification;
use BlogEngine\Domain\Specification\ArchivableArticleSpecification;
use BlogEngine\Util\Context;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class ArticleService
{
    private $workflow;

    public function __construct(EventDispatcherInterface $eventDispatcher)
    {
        $this->workflow = (new Builder($eventDispatcher))
            ->open('article.draft', new DraftableArticleSpecification())
            ->link('article.draft', 'article.published', new PublishableArticleSpecification())
            ->link('article.published', 'article.deleted', new DeletableArticleSpecification())
            ->link('article.published', 'article.archived', new ArchivableArticleSpecification())
            ->getWorkflow();

        $eventDispatcher->addSubscriber(new ArticleSubscriber());
    }

    public function create(Article $article)
    {
        $this->advance($article, new Context());
    }

    public function publish(Article $article)
    {
        $context = new Context();
        $context->set('article', $article);

        $this->advance($article, $context);
    }

    public function delete(Article $article)
    {
        $context = new Context();
        $context->set('action', 'delete');

        $this->advance($article, $context);
    }

    public function archive(Article $article)
    {
        $context = new Context();
        $context->set('action', 'archive');
        $context->set('publishedAt', $article->getPublishedAt());
        $context->set('now', new \DateTime());

        $this->advance($article, $context);
    }

    private function advance($article, ContextInterface $context)
    {
        try {
            $this->workflow->initialize($article->getToken())->next($context);
        } catch (\LogicException $e) {
            // the workflow reports a problem
        }
    }
}
```

Finally, you have to listen on events dispatched by the workflow to attach the business behavior:

```
namespace BlogEngine\Domain\Event;

use Alterway\Component\Workflow\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ArticleSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            'article.draft' => array('onDraft', 0),
            'article.published' => array('onPublished', 0),
            'article.deleted' => array('onDeleted', 0),
            'article.archived' => array('onArchived', 0),
        );
    }

    public function onDraft(Event $event) { /* ... */ }

    public function onPublished(Event $event) { /* ... */ }

    public function onDeleted(Event $event) { /* ... */ }

    public function onArchived(Event $event) { /* ... */ }
}
```

Contributing
------------

[](#contributing)

Pretty please, with sugar on top, phpspec specifications are provided and should be green when contributing code.

References
----------

[](#references)

### Theory

[](#theory)

- [Petri net](http://en.wikipedia.org/wiki/Petri_net)
- [Workflow patterns](http://www.workflowpatterns.com/)
- [Graph theory](http://en.wikipedia.org/wiki/Graph_theory)
- [Specification pattern](http://en.wikipedia.org/wiki/Specification_pattern)

### PHP

[](#php)

- [An activity based workflow engine](http://www.tonymarston.net/php-mysql/workflow.html)
- [eZ Workflow component](http://www.ezcomponents.org/docs/api/latest/introduction_Workflow.html)
- [Yii simpleWorkflow extension](http://www.yiiframework.com/extension/simpleworkflow/)
- [Galaxia workflow engine](http://workflow.tikiwiki.org/tiki-index.php?page=homepage)
- [State pattern by Sebastian Bergmann](https://github.com/sebastianbergmann/state)
- [Petrinet Framework](https://github.com/florianv/petrinet)

Licencing
---------

[](#licencing)

See the bundled LICENSE file for details.

Sponsors
--------

[](#sponsors)

- [Alter Way](http://www.alterway.fr)
- [La Ruche Qui Dit Oui !](http://www.laruchequiditoui.fr)

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity31

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

4468d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/919c0dd2d4755f6195d031c004340879606dfe43946fef8758edf5161271728e?d=identicon)[herveleclerc](/maintainers/herveleclerc)

---

Top Contributors

[![trompette](https://avatars.githubusercontent.com/u/181746?v=4)](https://github.com/trompette "trompette (14 commits)")

### Embed Badge

![Health badge](/badges/alterway-component-workflow/health.svg)

```
[![Health](https://phpackages.com/badges/alterway-component-workflow/health.svg)](https://phpackages.com/packages/alterway-component-workflow)
```

###  Alternatives

[phpro/soap-client

A general purpose SoapClient library

8885.6M46](/packages/phpro-soap-client)[winzou/state-machine

A very lightweight yet powerful PHP state machine

52113.7M18](/packages/winzou-state-machine)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)[symfony/ai-platform

PHP library for interacting with AI platform provider.

51927.7k136](/packages/symfony-ai-platform)[codefog/contao-haste

haste extension for Contao Open Source CMS

42650.8k139](/packages/codefog-contao-haste)[netgen/layouts-core

Netgen Layouts enables you to build and manage complex web pages in a simpler way and with less coding. This is the core of Netgen Layouts, its heart and soul.

3689.4k10](/packages/netgen-layouts-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
