{"id":21819350,"url":"https://github.com/dflydev/dflydev-finite-state-machine","last_synced_at":"2025-04-14T02:28:27.465Z","repository":{"id":56967310,"uuid":"256368575","full_name":"dflydev/dflydev-finite-state-machine","owner":"dflydev","description":"Yet another finite-state machine implementation","archived":false,"fork":false,"pushed_at":"2023-04-19T01:48:18.000Z","size":36,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-14T02:28:23.914Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dflydev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-04-17T01:17:48.000Z","updated_at":"2022-01-27T14:50:36.000Z","dependencies_parsed_at":"2023-09-25T02:07:55.518Z","dependency_job_id":null,"html_url":"https://github.com/dflydev/dflydev-finite-state-machine","commit_stats":{"total_commits":8,"total_committers":1,"mean_commits":8.0,"dds":0.0,"last_synced_commit":"53cb14f86c497cc016a7aca5e2c3f974447bb1f7"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dflydev%2Fdflydev-finite-state-machine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dflydev%2Fdflydev-finite-state-machine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dflydev%2Fdflydev-finite-state-machine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dflydev%2Fdflydev-finite-state-machine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dflydev","download_url":"https://codeload.github.com/dflydev/dflydev-finite-state-machine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248810766,"owners_count":21165177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-27T16:18:36.243Z","updated_at":"2025-04-14T02:28:27.446Z","avatar_url":"https://github.com/dflydev.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Finite-State Machine\n\nThis library is yet another finite-state machine implementation.\n\n![Build Status](https://github.com/dflydev/dflydev-finite-state-machine/workflows/Build%20Status/badge.svg)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/?branch=master)\n[![Code Coverage](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/dflydev/dflydev-finite-state-machine/?branch=master)\n[![Code Climate](https://codeclimate.com/github/dflydev/dflydev-finite-state-machine/badges/gpa.svg)](https://codeclimate.com/github/dflydev/dflydev-finite-state-machine)\n\n## Installation\n\n```bash\ncomposer require dflydev/finite-state-machine\n```\n\n## Usage\n\nGiven the following definition for a domain class:\n\n```php\nclass DomainObject\n{\n    public string $state;\n    public ?string $spy = null;\n\n    public function __construct(string $state = 'new')\n    {\n        $this-\u003estate = $state;\n    }\n}\n```\n\nGiven the following state definition for the \"graphA\" graph of our domain object:\n\n```php\n$domainObjectGraphDefinition = [\n   'class' =\u003e DomainObject::class,\n   'graph' =\u003e 'graphA', // default is \"default\"\n   'property_path' =\u003e 'state', // Configures `PropertyObjectProxy`\n   'metadata' =\u003e [\n       'title' =\u003e 'Graph A',\n   ],\n   'states' =\u003e [\n       // a state as associative array\n       ['name' =\u003e 'new'],\n       // a state as associative array with metadata\n       [\n           'name' =\u003e 'pending_review',\n           'metadata' =\u003e ['title' =\u003e 'Pending Review'],\n       ],\n       // states as string\n       'awaiting_changes',\n       'accepted',\n       'published',\n       'rejected',\n   ],\n\n   // list of all possible transitions\n   'transitions' =\u003e [\n       'create' =\u003e [\n           'from' =\u003e ['new'],\n           'to' =\u003e 'pending_review',\n       ],\n       'ask_for_changes' =\u003e [\n           'from' =\u003e  ['pending_review', 'accepted'],\n           'to' =\u003e 'awaiting_changes',\n           'metadata' =\u003e ['title' =\u003e 'Ask for changes'],\n       ],\n       'cancel_changes' =\u003e [\n           'from' =\u003e ['awaiting_changes'],\n           'to' =\u003e 'pending_review',\n       ],\n       'submit_changes' =\u003e [\n           'from' =\u003e ['awaiting_changes'],\n           'to' =\u003e  'pending_review',\n       ],\n       'approve' =\u003e [\n           'from' =\u003e ['pending_review', 'rejected'],\n           'to' =\u003e  'accepted',\n       ],\n       'publish' =\u003e [\n           'from' =\u003e ['accepted'],\n           'to' =\u003e  'published',\n       ],\n   ],\n\n   // list of all callbacks\n   'callbacks' =\u003e [\n       // will be called when testing a transition\n       'guard' =\u003e [\n           'guard_on_approving_from_rejected' =\u003e [\n               // call the callback on a specific transition\n               'on' =\u003e 'approve',\n               'from' =\u003e 'rejected',\n               // will call the method of this class\n               'do' =\u003e function (\n                   object $object,\n                   Transition $transition,\n                   State $fromState,\n                   State $toState\n               ) {\n                   $object-\u003espy = 'guard_on_approving_from_rejected';\n\n                   // If a guard returns false, the transition will not happen\n                   return false;\n               },\n               // arguments for the callback\n               'args' =\u003e ['object'],\n           ],\n       ],\n\n       // will be called before applying a transition\n       'before' =\u003e [\n           'spy-before-approve' =\u003e [\n               'on' =\u003e 'ask_for_changes',\n               'from' =\u003e 'accepted',\n               'do' =\u003e function (\n                   string $when,\n                   object $object,\n                   Transition $transition,\n                   State $fromState,\n                   State $toState\n               ) {\n                   Assert::equals($fromState-\u003ename(), $object-\u003estate);\n\n                   $object-\u003espy = $when . ' ask_for_changes from accepted';\n               },\n           ]\n       ],\n\n       // will be called after applying a transition\n       'after' =\u003e [\n           'spy-after-approve' =\u003e [\n               'on' =\u003e 'ask_for_changes',\n               'from' =\u003e 'accepted',\n               'do' =\u003e function (\n                   string $when,\n                   object $object,\n                   Transition $transition,\n                   State $fromState,\n                   State $toState\n               ) {\n                   Assert::equals($toState-\u003ename(), $object-\u003estate);\n                   Assert::equals('before ask_for_changes from accepted', $object-\u003espy);\n\n                   $object-\u003espy = $when . ' ask_for_changes from accepted';\n               },\n           ]\n       ],\n   ]        \n];\n```\n\n```php\nuse Dflydev\\FiniteStateMachine\\FiniteStateMachineFactory;\nuse Dflydev\\FiniteStateMachine\\Graph\\GraphResolver;\nuse Dflydev\\FiniteStateMachine\\Loader\\WinzouArrayLoader;\nuse Dflydev\\FiniteStateMachine\\ObjectProxy\\ObjectProxyResolver;\nuse Dflydev\\FiniteStateMachine\\ObjectProxy\\PropertyObjectProxyFactory;\n\n$graphResolver = new GraphResolver();\n$objectProxyResolver = new ObjectProxyResolver();\n\n// Add an object proxy that can directly read the state property from our objects\n$objectProxyResolver-\u003eadd(new PropertyObjectProxyFactory());\n\n// Load a graph definition into our graph resolver\n(new WinzouArrayLoader($graphResolver))-\u003eload($domainObjectGraphDefinition);\n\n$finiteStateMachineFactory = new FiniteStateMachineFactory(\n    $this-\u003egetGraphResolver(),\n    $this-\u003egetObjectProxyResolver()\n);\n\n$finiteStateMachine = $finiteStateMachineFactory-\u003ebuild($object);\n\n// \"new\"\n$finiteStateMachine-\u003ecurrentState()-\u003ename();\n\n// (bool) false\n$finiteStateMachine-\u003ecan('ask_for_changes');\n\n// (bool) true\n$finiteStateMachine-\u003ecan('create');\n\n$finiteStateMachine-\u003eapply('create');\n\n// \"pending_review\"\n$finiteStateMachine-\u003ecurrentState()-\u003ename();\n```\n\n## Graph Definitions and Loaders\n\nA graph is a named collection of states, transitions, and callbacks. An object may have multiple graphs defined.\n\nThe `GraphResolver` is responsible for resolving the graph definition for a given object (and optionally a graph name).\n\nA `Graph` can be created manually and added to a `GraphResolver`. A `Loader` can be used to load a `Graph` into a `GraphResolver` based on specific types of resources.\n\n### winzou/state-machine\n\nThis library ships with `WinzouArrayLoader`, a `Loader` implementation that is loosely drop-in compatible with [winzou/state-machine](https://github.com/winzou/state-machine) array-based graph definitions.\n\n### Custom\n\nThis library ships with a `Loader` contract. Implementing this interface allows for the creation of custom graph definitions.\n\n## License\n\nMIT, see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdflydev%2Fdflydev-finite-state-machine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdflydev%2Fdflydev-finite-state-machine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdflydev%2Fdflydev-finite-state-machine/lists"}