Skip to content

Instantly share code, notes, and snippets.

@markkimsal
Created April 9, 2015 19:10
Show Gist options
  • Save markkimsal/5333142aab19eff90af1 to your computer and use it in GitHub Desktop.
Save markkimsal/5333142aab19eff90af1 to your computer and use it in GitHub Desktop.
workflow with callbacks
<?php
namespace PHPWorkflow;
trait EventEmitterTrait {
protected $listeners = [];
public function on($event, callable $listener)
{
if (!isset($this->listeners[$event])) {
$this->listeners[$event] = [];
}
$this->listeners[$event][] = $listener;
}
public function once($event, callable $listener)
{
$onceListener = function () use (&$onceListener, $event, $listener) {
$this->removeListener($event, $onceListener);
call_user_func_array($listener, func_get_args());
};
$this->on($event, $onceListener);
}
public function removeListener($event, callable $listener)
{
if (isset($this->listeners[$event])) {
$index = array_search($listener, $this->listeners[$event], true);
if (false !== $index) {
unset($this->listeners[$event][$index]);
}
}
}
public function removeAllListeners($event = null)
{
if ($event !== null) {
unset($this->listeners[$event]);
} else {
$this->listeners = [];
}
}
public function listeners($event)
{
return isset($this->listeners[$event]) ? $this->listeners[$event] : [];
}
public function emit($event, array $arguments = [])
{
foreach ($this->listeners($event) as $listener) {
call_user_func_array($listener, $arguments);
}
}
};
trait DefaultWorkflow {
public $currentState = 0;
protected $listTransitions;
public function addTransitionFrom($state, $cb) {
$this->listTransitions[$state] = $cb;
}
public function process($input) {
$newstate = $this->listTransitions[$this->currentState]($input);
if ($newstate == NULL) {
return $this;
}
if ($newstate !== $this->currentState) {
$this->emit('statechange', array($this->currentState, $newstate));
$this->emit($newstate);
}
$this->currentState = $newstate;
return $this;
}
}
class DocumentPublish {
use DefaultWorkflow;
use EventEmitterTrait;
public $currentState = '';
public function __construct() {
$this->addTransitionFrom('', function($input) {
if ($input == 'promote') {
return 'draft';
}
});
$this->addTransitionFrom('draft', function($input) {
if ($input == 'promote') {
return 'review';
}
});
$this->addTransitionFrom('review', function($input) {
if ($input == 'promote') {
return 'published';
}
if ($input == 'demote') {
return 'draft';
}
});
$this->addTransitionFrom('published', function($input) {
if ($input == 'demote') {
return 'review';
}
});
}
}
$wf = new DocumentPublish();
$record = (object)array();// simulate active record pattern
$record->status = '';
$wf->on('draft', function() use($record) {
$record->status = 'draft';
//$record->save();
});
$wf->on('review', function() use($record) {
$record->status = 'review';
//$record->save();
});
$wf->on('published', function() use($record) {
$record->status = 'published';
//$record->save();
});
$wf->on('statechange', function($oldstate, $newstate) use($record) {
echo "My state changed, it was $oldstate, it's now $newstate.\n";
});
echo 'workflow state: ['.$wf->currentState."]\n";
echo 'record status: ['.$record->status."]\n";
$wf->process('promote');
echo 'workflow state: ['.$wf->currentState."]\n";
echo 'record status: ['.$record->status."]\n";
$wf->process('promote');
echo 'workflow state: ['.$wf->currentState."]\n";
echo 'record status: ['.$record->status."]\n";
$wf->process('promote');
echo 'workflow state: ['.$wf->currentState."]\n";
echo 'record status: ['.$record->status."]\n";
$wf->process('demote');
echo 'workflow state: ['.$wf->currentState."]\n";
echo 'record status: ['.$record->status."]\n";
//output
/*
workflow state: []
record status: []
My state changed, it was , it's now draft.
workflow state: [draft]
record status: [draft]
My state changed, it was draft, it's now review.
workflow state: [review]
record status: [review]
My state changed, it was review, it's now published.
workflow state: [published]
record status: [published]
My state changed, it was published, it's now review.
workflow state: [review]
record status: [review]
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment