A Simple PHP Finite State Machine

Related tags

Architectural Finite
Overview

Finite, A Simple PHP Finite State Machine

Finite is a Simple State Machine, written in PHP. It can manage any Stateful object by defining states and transitions between these states.

Build Status Latest Stable Version Total Downloads License Scrutinizer Code Quality Code Coverage SensioLabsInsight Dependency Status Reference Status Gitter

Features

  • Managing State/Transition graph for an object
  • Defining and retrieving properties for states
  • Event Listenable transitions
  • Symfony2 integration
  • Custom state graph loaders
  • Twig Extension

Documentation

Documentation for master (1.1)

Getting started

Installation (via composer)

{
      "require": {
        "yohang/finite": "~1.1"
    }
}

Version note :

If your are using this library in a Symfony project, 1.1 version is only compatible with Symfony >=2.6. 1.0 is compatible with Symfony >=2.3, <2.6.

Define your Stateful Object

Your stateful object just need to implement the StatefulInterface Interface.

use Finite\StatefulInterface;

class Document implements StatefulInterface
{
        private $state;
        public function setFiniteState($state)
        {
                $this->state = $state;
        }

        public function getFiniteState()
        {
            return $this->state;
        }
}

Initializing a simple StateMachine

use Finite\StateMachine\StateMachine;
use Finite\State\State;
use Finite\State\StateInterface;

// $document = retrieve your stateful object

$sm = new StateMachine();

// Define states
$sm->addState(new State('s1', StateInterface::TYPE_INITIAL));
$sm->addState('s2');
$sm->addState('s3');
$sm->addState(new State('s4', StateInterface::TYPE_FINAL));

// Define transitions
$sm->addTransition('t12', 's1', 's2');
$sm->addTransition('t23', 's2', 's3');
$sm->addTransition('t34', 's3', 's4');
$sm->addTransition('t42', 's4', 's2');

// Initialize
$sm->setObject($document);
$sm->initialize();

// Retrieve current state
$sm->getCurrentState();

// Can we process a transition ?
$sm->can('t34');
Comments
  • Split standalone component and Symfony bundle

    Split standalone component and Symfony bundle

    First, really nice project, i love it !

    Is it possible to split Finite as standalone component without the symfony stack inside ? and add the symfony bundle on top ?

    Currently on non symfony project (like silex or cilex) it's a bit frustrating to see a bundle folder appear :D

    Is it plan ?

    opened by jjsaunier 18
  • Add a callback to cascade transitions

    Add a callback to cascade transitions

    Hi,

    This PR adds 2 useful things:

    1. The ability to pass arguments to callbacks. Currently, we are limited to the arguments $object and $transitionEvent. With this PR you can define arguments to pass to your callback directly from the graph configuration (via the args parameter).
    2. A simple callback that you can use (in combination with the callback arguments :) to cascade some transitions. I updated the callback.php example with an automatic transition from accepted to archived. This can be useful in many cases. The callback supports as well the cascade when dealing with the same object but different graph, and even with another object reachable from the main object via a PropertyAccessor (for example, when your shipment goes from ready to shipped, you may want to automatically update your order (reachable with shipment.order).

    Thanks,

    opened by winzou 13
  • fix for symfony/options-resolver 2.6+

    fix for symfony/options-resolver 2.6+

    We had an issue with Finite installing along symfony/options-resolver 2.6+ which caused E_DEPRECATED errors due to new syntax of setAllowedTypes method. This little fix removes the error, it is however optional, because you have 2.4.4 in your composer.lock file (which was somehow ignored in our system). You could add this to prevent problems with update to 2.6+/3.0 of options-resolver or simply ignore this, as manual specification of "symfony/options-resolver": "2.4.4" in our composer.json seemed to do the trick too.

    Cheers.

    Related to issue #84.

    opened by keiosweb 11
  • Event Params

    Event Params

    It would be useful to be able to pass params to transition events. See the doc for more details

    | Q | A | | --- | --- | | Test Pass? | y | | License | MIT |

    opened by Padam87 10
  • Support multiple states per object?

    Support multiple states per object?

    Hi Yohan, very nice project!

    We have been looking at it from over at https://github.com/Sylius/Sylius/issues/1037, but one problem we have that the use of the StatefulInterface limits each object to only one state. In Sylius we have an Order class which has several states, such as ShippingState, and PaymentState.

    Would it not be possible to get rid of the interface and instead rely on the PropertyAccess component to access whichever property represents the state?

    Another (more explicit) possibility would be to rely on a new StateExtractorInterface which would be used to extract a single state from an object..

    If you agree that this is a limitation that we should/could address, I would be happy to help with the implementation..

    opened by Richtermeister 9
  • [WIP] Adding a way to easily work with the State machine lifecycle

    [WIP] Adding a way to easily work with the State machine lifecycle

    TODO

    • [x] Add a callback handler
    • [x] Add Symfony EventDispatcher as an hard dependency
    • [x] Deprecate ListenableStateMachine and make the base State machine listenable
    • [x] Link ArrayLoader and the CallbackHandler to define callbacks from configuration
    • [ ] Update the Symfony Bundle
    • [x] Add docs and examples

    (Inspired by @tortuetorche work here : https://gist.github.com/tortuetorche/6365575)

    opened by yohang 8
  • Release a stable version

    Release a stable version

    Do you think you could tag a stable release? Would be great since more recent projects using Composer do only use stable releases by default. Also gives somewhat more confidence to use the project by other people.

    opened by mac-cain13 8
  • Finite don't work on Linux box

    Finite don't work on Linux box

    It does work on my windows development machine (php version 5.4.27) but it doesn't work on linux test or production server with php 5.4.33 The error I'm getting is: request.CRITICAL: Uncaught PHP Exception Symfony\Component\OptionsResolver\Exception\InvalidOptionsException: "The option "disabled" does not exist. Known options are: "exclude_from", "exclude_to", "from", "on", "to"" at /var/www/vhosts/xxxxxxx.local/httpdocs/vendor/symfony/symfony/src/Symfony/Component/OptionsResolver/OptionsResolver.php line 255 {"exception":"[object](Symfony\Component\OptionsResolver\Exception\InvalidOptionsException: The option "disabled" does not exist. Known options are: "exclude_from", "exclude_to", "from", "on", "to" at /var/www/vhosts/xxxxxxx.local/httpdocs/vendor/symfony/symfony/src/Symfony/Component/OptionsResolver/OptionsResolver.php:255)"

    state-machine.yml is

        callbacks:
          after:
            callback1:
              do:
                [@xxxxxxx_finite.transition_events, transitionEverytimeAfter]
    
    bug 
    opened by ppavlovic 7
  • [WIP] Refactor CallbackHandler

    [WIP] Refactor CallbackHandler

    Here is a draft of the refactoring of the CallbackHandler (#48).

    It introduces no BC, but it deprecates the previous usage of CallbackHandler::add* methods.

    Callbacks are now wrapped in a Callback, with a CallbackSpecification responsible of the execution, or not, of the callback on transition events.

    Callback defines an __invoke method, and instances are directly registered as event listeners.

    The Callback instantiation logic has been moved to a CallbackBuilder and to the ArrayLoader.

    I kept the options resolver, as it's pretty good at cleaning configuration arrays.

    opened by yohang 7
  • Warning and unexpected behaviour after rejecting a transaction

    Warning and unexpected behaviour after rejecting a transaction

    Only today I came across this library, after a few hours of study and running a few examples, I came across the following:

    • Warning if I do not pass a guard option when defining a transition: PHP Notice: Undefined index: guard in vendor/yohang/finite/src/Finite/Loader/ArrayLoader.php on line 109. I did not see any reference of this property in the examples.
    • I was expecting that by calling the method reject() on the TransitionEvent, this would abort the transition, but not the case, it seems it has no impact. The method apply() on StateMachine, after dispatching the pre events, call process() on the Transition, but that method has an empty body, it does not return any value, but still, we use that as the return value of the apply(). Is this by design, are we suppose to create/extend the Transition class and implement our logic in the process method()?
    opened by titomiguelcosta 6
  • Update for Symfony ~2.6

    Update for Symfony ~2.6

    We've been using your library (via kphoen/doctrine-state-machine-bundle) and as a push for getting ready for Symfony 2.8 / 3.0, we've been trying to eliminate all deprecated warnings in our code and the third party libraries that we use.

    This PR represents the changes that were required for preventing this library from causing the warnings. It represents a culmination of the code in #90, #85 and #79 (and maybe some extra too)

    In addition, I have made the following composer related changes:

    • I have also removed the composer.lock file, as it's generally superfluous in a library designed for consumption by others.
    • I have updated the composer.json requirements for Symfony versions to be ~2.6

    The required changes in symfony versions means that this PR has BC compatibility issues for people using it in projects with older versions of Symfony, so in the strictest semver terms, it would require a new major release.

    If you have any issues, please let me know. Would love to see the deprecation issues addressed.

    Thanks. :+1:

    opened by navitronic 5
  • Maintainer for this repo and the library

    Maintainer for this repo and the library

    Hey there @yohang ,

    this repo and the library does not get the love it deserves. There are multiple open issues and a LOT of PRs ready to be merged or at least tested. People invest in this repo an obviously the interest in this repo is big with over a million installs on Packagist and over 150 forks here on GitHub.

    Since you seem to be unable/unwilling to maintain this library for the community on your own, would you be willing to enable one of your contributers (if they are willing) to moderate and administer this library for or at least with you?

    @winzou @navitronic @RonRademaker @Padam87 @liuggio @tortuetorche @tompedals @pborreli @nidup @defrag @arikal @realshadow @K-Phoen @acorncom @dannykopping @ksn135 @reiz

    The other path would be to mark this project as abandoned, so people would stop installing it and then realize that there are (known) bugs, that are not fixed or missing functionality that is not merged, even when the work is done.

    This should neither be attacking nor judgemental. I know, it is hard to maintain open source and interact with a community if you already have a demanding life out there in the real world and a company whatsoever. But I also think, that it is unfair to the community to let them use software without a clear message that this library is not maintained actively.

    opened by func0der 2
  • Examples multiple-graphs-with-factory.php and multiple-graphs.php do not work

    Examples multiple-graphs-with-factory.php and multiple-graphs.php do not work

    I have tested the examples. Examples multiple-graphs-with-factory.php and multiple-graphs.php do not work. Here is what we get.

    php multiple-graphs-with-factory.php
    PHP Fatal error:  Class 'Pimple' not found in vendor/yohang/finite/examples/multiple-graphs-with-factory.php on line 77
    
    php multiple-graphs.php
    PHP Fatal error:  Uncaught exception 'Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException' with message 'Neither the property "finiteState" nor one of the methods "getFiniteState()", "finiteStat\
    e()", "isFiniteState()", "hasFiniteState()", "__get()" exist and have public access in class "Order".' in vendor/symfony/property-access/PropertyAccessor.php:516
    Stack trace:
    
    opened by kresimir71 0
  • Symfony Events require different event listener connection than normal

    Symfony Events require different event listener connection than normal

    I'm using Symfony 4.4. The documentation at https://finite.readthedocs.io/en/master/usage/symfony.html#using-callbacks say:

    Events dispatched with the EventDispatcher and works as the Symfony kernel events.

    This would seem to imply that one can simply follow the standard Symfony ways of registering an event listener. i.e. using services.yaml or Creating an Event Subscriber.

    However, neither of those work, because Finite creates its own event dispatcher! When a new StateMachine is created, it creates a new StateMachineDispatcher() which creates...a new Symfony\Component\EventDispatcher\EventDispatcher.

    So any Symfony event registered in the normal way will not listen to the event.

    Solution

    We have to connect our event listener to the StateMachine's dispatcher.

    $sm = new StateMachine();
    $dispatcher = $sm->getDispatcher();
    $dispatcher->addListener(FiniteEvents::POST_TRANSITION, [new MyPostTransitionListener(), 'onFinitePostTransition']);
    
    class MyPostTransitionListener
    {
        public function onFinitePostTransition(\Finite\Event\TransitionEvent $event)
        {
            // handle event here
        }
    }
    
    opened by BurningDog 1
  • Incompatibility of 1.2.* where symfony/contracts also exists

    Incompatibility of 1.2.* where symfony/contracts also exists

    If symfony/contracts is also used in the project, there versions 1.2.* have an issue:

    TypeError : Argument 2 passed to Symfony\Component\EventDispatcher\EventDispatcher::dispatch() must be an instance of Symfony\Component\EventDispatcher\Event or null, instance of Finite\Event\StateMachineEvent given
    

    This seems to occur when someone has both the Symfony\Contracts\EventDispatcher\Event and Symfony\Component\EventDispatcher\Event installed. This check in StateMachineEvent checks whether Symfony\Contracts\EventDispatcher\Event exists, and aliases it to Symfony\Component\EventDispatcher\Event if not.

    opened by irinikp 1
  • Upgrade to PHPUnit 8, Symfony 5, PHP 7.2

    Upgrade to PHPUnit 8, Symfony 5, PHP 7.2

    All automated tests pass, but I haven't tested all functionality in-depth. Probably want to merge this into a different branch to test further.

    This PR allows use of this repo with Laravel 7. Without these changes, composer hangs indefinitely trying to resolve dependencies that include Symfony 5.x.

    opened by Mattnmoore 0
A simple Monad library for PHP

MonadPHP This is a basic Monad library for PHP. Usage Values are "wrapped" in the monad via either the constructor: new MonadPHP\Identity($value) or t

Anthony Ferrara 283 Dec 29, 2022
sample code for several design patterns in PHP 8

DesignPatternsPHP Read the Docs of DesignPatternsPHP or Download as PDF/Epub This is a collection of known design patterns and some sample codes on ho

null 21k Jan 1, 2023
Primitives for functional programming in PHP

Functional PHP: Functional primitives for PHP NOTE: functional-php used to come with a C extension that implemented most of the functions natively. As

Lars Strojny 1.9k Jan 3, 2023
Option Type for PHP

PHP Option Type This package implements the Option type for PHP! Motivation The Option type is intended for cases where you sometimes might return a v

Johannes 2.4k Dec 26, 2022
Powerful implementation of the Specification pattern in PHP

RulerZ The central idea of Specification is to separate the statement of how to match a candidate, from the candidate object that it is matched agains

Kévin Gomez 865 Dec 22, 2022
A Finite State Machine System based on Chapter 3.1 of Game Programming Gems 1 by Eric Dybsand

A Finite State Machine System based on Chapter 3.1 of Game Programming Gems 1 by Eric Dybsand,Written by Roberto Cezar Bianchini, July 2010 ported to php by MrFerrys.

null 4 Apr 18, 2022
A simple laravel state machine to handle model transitions, based on a pre-defined list of rules

A simple state machine that allows transitioning model states based on pre-defined rules. Installation You can install the package via composer: compo

Jack Mollart 18 Apr 2, 2022
PHP Machine Learning Rain Forecaster is a simple machine learning experiment in predicting rain based on a few forecast indicators.

PHP Machine Learning Rain Forecaster is a simple machine learning experiment in predicting rain based on a few forecast indicators.: forecasted "HighT

null 4 Nov 3, 2021
XState - A State Machine for PHP

XState - A State Machine for PHP State machine library to play with any complex behavior of your PHP objects Installation You can install the package

Mouad Ziani 68 Dec 18, 2022
PHPIDS (PHP-Intrusion Detection System) is a simple to use, well structured, fast and state-of-the-art security layer for your PHP based web application

PHPIDS PHPIDS (PHP-Intrusion Detection System) is a simple to use, well structured, fast and state-of-the-art security layer for your PHP based web ap

null 752 Jan 3, 2023
A simple class that provides access to country & state list.

GeoData A simple class that provides access to country & state list. Installation composer require ahmard/geodata Usage Fetch country list <?php use

Ahmad Mustapha 4 Jun 20, 2022
A simple PHP web backdoor allows you to retrieve directory/file contents and upload file(s) from the local machine or remote URL.

Simple PHP Web Backdoor A simple PHP web backdoor allows you to retrieve directory/file contents and upload file(s) from the local machine or remote U

Aqhmal Hafizi 15 Oct 7, 2022
States allows you to create PHP classes following the State Pattern in PHP.

States allows you to create PHP classes following the State Pattern in PHP. This can be a cleaner way for an object to change its behavior at runtime without resorting to large monolithic conditional statements and this improve maintainability and workflows writing.

Teknoo Software 10 Nov 20, 2022
Geographer is a PHP library that knows how any country, state or city is called in any language

Geographer Geographer is a PHP library that knows how any country, state or city is called in any language. Documentation on the official website Incl

Menara Solutions 757 Nov 24, 2022
Generally, a graceful shutdown is preferable in the case of any OS that saves its state

Graceful Shutdown with PHP Generally, a graceful shutdown is preferable in the case of any OS that saves its state.

Leonardo Carmo 17 Oct 14, 2022
The Runtime Component enables decoupling applications from global state.

Runtime Component Symfony Runtime enables decoupling applications from global state. This Component is experimental. Experimental features are not cov

Symfony 409 Jan 3, 2023
Livewire component that provides you with a modal that supports multiple child modals while maintaining state.

About LivewireUI Modal LivewireUI Modal is a Livewire component that provides you with a modal that supports multiple child modals while maintaining s

Livewire UI 806 Jan 6, 2023
Active State Helper for Laravel Blade

laravel-activehelper Active State Helper for Laravel Blade Lightweight and simple Introduction Basically we do like this. <li class="sidebar {{ Reques

Ahmad Irsyadul Ibad 4 Sep 25, 2022
Livewire component that provides you with a modal that supports multiple child modals while maintaining state.

About Wire Elements Modal Wire Elements Modal is a Livewire component that provides you with a modal that supports multiple child modals while maintai

Wire Elements 806 Jan 6, 2023
Reset UI Bookmarks allows admin users to reset their own UI bookmarks such as state of filters, column positions and applied sorting ( e.g Sales > Orders ).

Reset Ui Bookmarks Reset UI Bookmarks becomes an invaluable tool while working daily in the admin panel, especially on Magento® instances with a large

Magenizr 23 Oct 19, 2022