PHP 5.3 library to use command/transaction design pattern
Ika relies on doing the same as SQL transations but with eclectic actions, and if an error occured roll back these actions.
An example of application will be an installer, that performs multiple actions like create folder, duplicate files, run SQL queries etc and if one of these actions doesn't work, clean previous actions.
You create several commands, each one has an up action and a down action. When you will start the transaction, all up action of your commands will be run, in the order they were added.
If an error occurred, you can roll back. It will run all down action of all succeeded commands in reverse. That's it. Simple.
Download the latest version of Ika and add the Ika
namespace
to your PSR-0 autoloading system, or simply require the src/autoload.php
Just create a composer.json file and run the php composer.phar install command to install it:
{
"require": {
"devster/ika": ">=1.0.*"
}
}
Here a small example of basic usage with thin commands:
use Ika\Transaction;
$t = new Transaction;
// Register new command to the transaction and set it up
$t->register('new_dir')->setUp(function($prev, $command) {
// the `command` var is the new command object you just registered
// $prev is the return of the previous hook/command
// Here it is NULL because there is nothing before
mkdir('test');
})->setDown(function($prev, $command) {
rmdir('test');
});
// add a second command, this library is useless for just one command :)
$t->register('create_file')->setUp(function() {
// some code that throw an exception
throw new Exception('Error !');
})->setDown(function(){});
// Here we go! We run the transaction
try {
$result = $t->begin();
} catch(TransactionException $e) {
// Execute just the down action of the first command `rmdir('test')`
$t->rollback();
}
If your commands are more complex you can extend the Ika\Command
:
use Ika\Command;
class MyCommand extends Command
{
public function getName()
{
return 'my_command';
}
public function isEnabled()
{
// your code that decide if this command
// must be run when the transaction will be executed
// By default return true
return true;
}
public function up($prev)
{
mkdir('test');
}
public function down($prev)
{
rmdir(test);
}
}
$t = new Transaction;
// add your new fresh command
$t->add(new MyCommand);
// add a bunch of commands
//$t->addCommands(array(new Command, ...));
try {
$t->begin();
} catch(TransactionException $e) {
$t->rollback();
}
There is a hooks system integrated in Ika. here's the list:
- pre // execute before any actions up or down
- post // executed after any actions up or down
- preUp // executed before up actions
- postUp // executed after up actions
- preDown // executed before down actions
- postDown // executed after down actions
$t = new Transaction;
$t->addHook('preUp', function($prev, $command) {
// $prev is the return of the previous hook/command
// $command is the current command executed
echo 'Execution of '.$command->getName();
});
If your hooks are more complex you can extends Ika\Transaction
:
use Ika\Transaction;
class MyTransaction extends Transaction
{
public function initialize()
{
$this->addHook('pre', function($prev, $command, $direction){
echo 'Execution of '.$direction.' '.$command->getName();
});
$this->addHook('postDown', function(){});
// etc
}
}
You can start the transaction at the command you want:
$t->begin('my_command');
You can start the rollback at the command you want:
$t->rollback('my_command');
- Any flavor of PHP 5.3 should do
- Jeremy Perret jeremy@devster.org
Ika is licensed under the MIT License - see the LICENSE file for details