Sequencing

A sequencer executes a list of tasks and watches the tasks as they execute. This allows the sequencer to respond to unfolding events — including making changes to the task list. Once the app has been started up it can re-write itself from the pool of available task classes. The current action can be refined in some way or the app can change track altogether and try something else.

Sequencing might be used when there are a series of loosely-coupled tasks to be performed or you need some kind of self-assembling intelligence. That probably fits php cli apps better than web pages — the sequencing code was originally developed for Rephactor.

Include the sequencing file...

<?php
require_once('aperiplus/lib/control/sequencing.php');

...and define a sequence:

<?php

$sequence 
FromPhemto(array('ThisTask''ThatTask'));

(#!! pass in a Phemto..?)

The above example uses Phemto to instantiate the given tasks. You can also use a hand-written factory.

<?php

$sequence 
= new FromFactory(
    array(
'ThisTask''ThatTask'), 
    new 
YourFactory);

The factory class should have a getter for each Task object it's supposed to provide. Note that you must use the naming convention "getClassName":

<?php

class YourFactory {

    function 
getThisTask() {
    }
    function 
getThatTask() {
    }
}

Tasks should implement:

<?php

interface Task {
    function 
execute();
}

In Sequencer, successfully executed tasks will be passed to a namesake method, if implemented, or to _defaultSuccess() if not.

Failed tasks must throw an exception of some kind to signify failure and the exception will similarly be passed to a namesake method, if implemented, or _defaultFailure if not.

Method names must be class names prefixed with an underscore.

Although Sequencer will work as-is, you will probably want to extend it with your own custom sequencer class in order to define how the app will respond to events of interest.

Handler methods can do anything they like including altering the task sequence. You can add tasks to the front or the end of the sequence or reset it altogether. Here I've got a custom handler for each of Foo, Bar, and Busted — the names of task classes or exceptions thrown by them. The task (or exception) object is passed to the handler method in case you want to query it.

<?php

class MySequencer extends Sequencer {

    function 
_Foo($task) {
        
$this->_sequence->addToFront(
            array(
'AnotherTask')); // array of class names
    
}
    function 
_Bar($task) {
        
$this->_sequence->addToBack(
            array(
'YetAnother''AndAnother'));
    }
    function 
_Busted($exception) {
        
$this->_sequence = new FromPhemto(
            array(
'Change''Direction')); // reset
    
}

Finally, instantiate and run the sequencer:

<?php

$sequencer 
= new MySequencer($sequence);
$sequencer->execute();

This is a bit of an experiment. I'm not sure how easy it would be to follow a complicated app with a lot of re-sequencing rules. At least they are all in one place (MySequencer).

Although it would be possible to allow a Sequencer instance as an item in a tasks list, that might again make things very hard to follow?

SourceForge.net Logo