XML-Parser-Beispiel¶
Mit Hilfe des XML-Parser lässt sich eine Workflow-Struktur als XML-Datei beschreiben.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Definition des Workflows -->
<workflow>
<!-- Mit diesem Tag kann der Eintritszustand in den Workflow festgelegt werden.
Besitzt ein Objekt kein Status, so wird dieser Status angenommen.
class, state-class und step-class sind optional.
-->
<admission state="created"
step="create"
class="\Alvine\Application\Workflow\Admission"
state-class="\Alvine\Application\Workflow\State"
step-class="\Alvine\Application\Workflow\Step"
container-class="\MyNamespace\Item" />
<!-- Definition aller vorhandenen Status die ein Objekt annehmen kann -->
<states>
<!-- Ein Status muss einen Namen besitzen, es kann eine von \Alvine\Application\Workflow\State
abgeleitete Klasse angegeben werden. -->
<state name="created" class="\Alvine\Application\Workflow\State" />
<state name="start" />
<state name="end" />
</states>
<!-- Steps definieren die Aktionen, die beim Übergang von einem Status,
zu einem anderem Status gegangen werden. -->
<steps>
<!-- Jeder Step muss einen eindeutigen Namen enthalten, zusätzlich
kann noch eine von \Alvine\Application\Workflow\Step abgeleitetet Klasse
definiert werden. -->
<!-- Dieser Step wird in <admission> referenziert und beim Erstellen eines
Containers getriggert. -->
<step name="create">
<actions>
<!-- Es können Aktionen, die beim Übergang ausgeführt werden, definiert werden. -->
<action class="\MyNamespace\MyCreateAction" />
</actions>
</step>
<step name="step1" class="\Alvine\Application\Workflow\Step">
<actions>
<!-- Es können Aktionen, die beim Übergang ausgeführt werden, definiert werden. -->
<action class="\MyNamespace\MyAction" />
</actions>
<validations>
<!-- Mittels Validatoren kann geprüft werden, ob ein Statusübergang möglich ist. -->
<validation class="\MyNamespace\MyValidation" />
</validations>
</step>
<step name="step2">
<actions>
<action class="\MyNamespace\MyAction" />
</actions>
</step>
</steps>
<!-- Automation des Workflows;
Mit diesen Regeln lassen sich unabhänging von einem
Übergang Änderungen an einem Container vornehmen -->
<automation>
<rules>
<!-- Jede Regel verfügt über Bedingungen (die alles zutreffen müssen)
und Aktionen, die ausgeführt werden. Diese Regel wird
automatisch nach jeder Transition (\Alvine\Application\Workflow\Event\EndTransition)
ausgeführt -->
<rule class="\Alvine\Application\Workflow\Automation\Rule"
name="my-rule"
on="\Alvine\Application\Workflow\Event\EndTransition">
<conditions>
<!-- Beide Bedingungen müssen erfüllt sein; die Methode müssen
true zurück geben -->
<condition class="\MyNamespace\AutomationCondition1" />
<condition class="\MyNamespace\AutomationCondition2" />
</conditions>
<actions>
<!-- Diese Aktionen werden ausgeführt -->
<action class="\MyNamespace\AutomationMyAction1" />
<action class="\MyNamespace\AutomationMyAction2" />
</actions>
</rule>
</rules>
</automation>
<!-- transitions definieren eine Zustandsänderung eines Objektes. -->
<transitions>
<!-- Ein Übergang hat einen eindeutigen Namen und einen Zielstatus.
Wird kein Ausgagsstatus (from) definiert, so ist dieser Übergang
von allen Status aus möglich. -->
<transition name="transfer1" to="start" />
<!-- Zusätzlich kann noch ein Step und ein Ausgangsstatus definiert werden.
Es kann eine von \Alvine\Application\Workflow\Transition abgeleitete Klasse verwendet werden. -->
<transition name="transfer2" class="\Alvine\Application\Workflow\Transition" from="start" to="end" with="step2">
<!-- Überprüfung vor dem Übergang -->
<validations>
<!-- Mittels Validatoren kann geprüft werden, ob ein Statusübergang möglich ist. -->
<validation class="\MyNamespace\MyTransitionValidation" />
</validations>
<!-- Fehler / Exceptions abfangen -->
<exceptions>
<exception match="\Alvine\Core\FrameworkException" >
<!-- Exception ignorieren -->
<handler class="\Alvine\Application\Workflow\Transition\Exception\Handler\ThrowAway" />
</exception>
</exceptions>
</transition>
</transitions>
</workflow>
Das folgende Programm verwendet die XML und führt die definierten Übergänge aus. Zuerst wird eine Klasse die bearbeitet werden soll definiert.
class Item implements \Alvine\Application\Workflow\Container {
use \Alvine\Application\Workflow\Container\Implementation;
}
Nun brauchen wir noch eine Aktion für den Übergang
class MyAction extends \Alvine\Core\Alvine implements \Alvine\Application\Workflow\Action {
public function run(\Alvine\Application\Workflow\Container $container): \Alvine\Application\Workflow\Container {
echo "tue etwas ...\n";
return $container;
}
public static function getInstanceFromParameterMap(\Alvine\Types\Map\ParameterMap $data): \Alvine\Application\Workflow\Action {
return new static();
}
}
class MyCreateAction extends \Alvine\Core\Alvine implements \Alvine\Application\Workflow\Action {
public function run(\Alvine\Application\Workflow\Container $container): \Alvine\Application\Workflow\Container {
echo "erstelle einen Container ...\n";
return $container;
}
public static function getInstanceFromParameterMap(\Alvine\Types\Map\ParameterMap $data): \Alvine\Application\Workflow\Action {
return new static();
}
}
und eine Überprüfung.
class MyValidation extends \Alvine\Core\Alvine implements \Alvine\Application\Workflow\Step\Validation {
public function isValid(\Alvine\Application\Workflow\Container $container): bool {
return true;
}
}
class MyTransitionValidation extends \Alvine\Core\Alvine implements \Alvine\Application\Workflow\Transition\Validation {
public function isValid(\Alvine\Application\Workflow\Transition $transition, \Alvine\Application\Workflow\Container $container): bool {
return true;
}
}
Jetzt wird die oben definierte XML-Datei eingelesen und der Workflow initialisiert.
$processor=(new \Alvine\Application\Workflow\Parser\XMLParser)->parse($xml);
Jetzt führen wir einige Übergänge aus.
$container=$processor->create(1224);
echo "Aktueller Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/** Ersten Übergang ausführen */
echo "Übergang transfer1\n";
$processor->run($container, 'transfer1');
echo "Neuer Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/** Zweiten Übergang ausführen */
echo "Übergang\n";
$processor->run($container, 'transfer2');
echo "Neuer Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/** Übergang ausführen */
echo "Übergang transfer1\n";
$processor->run($container, 'transfer1');
echo "Neuer Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/** Übergang ausführen */
echo "Übergang transfer2\n";
$processor->run($container, 'transfer2');
echo "Neuer Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/** Übergang von end -> end ist nicht erlaubt */
try {
echo "Übergang von end zu end (nicht definiert)\n";
$processor->run($container, 'transfer2');
} catch(\Alvine\Application\Workflow\Transition\NotPermittedException $x) {
echo "Nicht erlaubt!";
}
echo "Neuer Status des Containers: ".$container->getState()."\n";
echo "------------------------------------------\n\n";
echo "Aktueller Status des Containers: ".$container->getState()."\n";
/**
* Ausgabe:
* start
* tue etwas ...
* end
* start
* tue etwas ...
* end
* Nicht erlaubt!
*/