smoren/containers-transactional

Abstract transactional containers and data structures

v0.1.3 2021-12-23 16:29 UTC

This package is auto-updated.

Last update: 2024-04-24 15:52:03 UTC


README

Abstract wrapper structure for providing transactional interface for editing objects.

Includes implementations of transactional wrappers for some data containers and structures.

How to install as dependency to your project

composer require smoren/containers-transactional

Unit testing

composer install
./vendor/bin/codecept build
./vendor/bin/codecept run unit tests/unit

Using with your class

Class definitions

use Smoren\Containers\Transactional\Base\TransactionWrapper;
use Smoren\Containers\Transactional\Base\Validator;
use Smoren\Containers\Transactional\Interfaces\ValidationRuleInterface;

/**
 * Your class that you want to wrap with transactional interface
 */
class YourClass {
    /**
     * Example attribute
     * @var int 
     */
    public $someAttribute = 1;
    // ...
}

/**
 * @see Smoren\Containers\Transactional\Structs\TLinkedList
 */
class TYourClass extends TransactionWrapper
{
    /**
     * This overriding is needed only to specify method's return type
     * @inheritDoc
     */
    public function getWrapped(): YourClass
    {
        return parent::getWrapped();
    }

    /**
     * Unnecessary override if there is not default value of YourClass
     * @inheritDoc
     */
    protected function getDefaultWrapped()
    {
        return new YourClass();
    }

    /**
     * @inheritDoc
     * @return string
     */
    protected function getWrappedType(): ?string
    {
        return YourClass::class;
    }
    
    /**
     * Unnecessary override if you are not going to use validation
     * @inheritDoc
     * @return Validator
     * @throws \Smoren\ExtendedExceptions\LogicException
     */
    protected function getDefaultValidator(): ?Validator
    {
        return (new Validator())
            ->addRule('validation_rule_alias', MyValidationRule::class);
    }
}

/**
 * This declaration is not necessary if you are not going to use validation
 * @see Smoren\Containers\Transactional\Tests\Unit\Utility\PositiveNumberValidationRule
 */
class MyValidationRule implements ValidationRuleInterface
{
    protected array $errors = [];
    
    /**
     * @inheritDoc
     */
    public function validate($data, $owner): bool
    {
        // ...
        return true;
    }

    /**
     * @inheritDoc
     */
    public function getErrors()
    {
        return $this->errors;
    }
}

Client code

use Smoren\Containers\Transactional\Exceptions\ValidationException;

$yourObject = new YourClass();
$tWrapper = new TYourClass($yourObject);

echo $yourObject->someAttribute; // output: 1
echo $tWrapper->getWrapped()->someAttribute; // output: 1

$tWrapper->interact(function(YourClass $tmpObjectState) {
    $tmpObjectState->someAttribute = 2;
});

echo $yourObject->someAttribute; // output: 1

try {
    $tWrapper->validate(); // validate only
    echo $yourObject->someAttribute; // output: 1
} catch(ValidationException $e) {
    print_r($e->getErrors()); // output: ['validation_rule_alias' => [...]]
}

try {
    $tWrapper->apply(); // validate and apply
    echo $yourObject->someAttribute; // output: 2
} catch(ValidationException $e) {
    print_r($e->getErrors()); // output: ['validation_rule_alias' => [...]]
}

Ready to use transactional containers

TArray

Wraps PHP array with transactional interface.

use Smoren\Containers\Transactional\Structs\TArray;
use Smoren\Containers\Transactional\Exceptions\ValidationException;

$ta = new TArray([1, 2, 3]);
print_r($ta->getWrapped()); // output: [1, 2, 3]

$ta->interact(function(array &$arr) {
    array_push($arr, 4);
    array_push($arr, 5);
    $arr[0] = 0;
});


try {
    print_r($ta->getWrapped()); // output: [1, 2, 3]
    $ta->apply();
    print_r($ta->getWrapped()); // output: [0, 2, 3, 4, 5]
} catch(ValidationException $e) {
    // if validation failed
}

TLinkedList

Classic implementation of linked list data structure wrapped with transactional interface.

Wraps LinkedList container.

use Smoren\Containers\Transactional\Structs\TLinkedList;
use Smoren\Containers\Transactional\Exceptions\ValidationException;
use Smoren\Containers\Structs\LinkedList;

$tll = new TLinkedList([1, 2, 3]);
print_r($tll->getWrapped()->toArray()); // output: [1, 2, 3]

$tll->interact(function(LinkedList $list) {
    $list->pushBack(4);
    $list->pushBack(5);
});

try {
    print_r($tll->getWrapped()->toArray()); // output: [1, 2, 3]
    $tll->apply();
    print_r($tll->getWrapped()->toArray()); // output: [1, 2, 3, 4, 5]
} catch(ValidationException $e) {
    // if validation failed
}

TMappedCollection

Map-like data structure with transactional interface.

Wraps MappedCollection container.

use Smoren\Containers\Transactional\Structs\TMappedCollection;
use Smoren\Containers\Transactional\Exceptions\ValidationException;
use Smoren\Containers\Structs\MappedCollection;

$tmc = new TMappedCollection([
    '0' => ['id' => 0],
]);

print_r($tmc->getWrapped()->toArray()); // output: ['0' => ['id' => 0]]

$tmc->interact(function(MappedCollection $collection) {
    $collection
        ->add('1', ['id' => 1])
        ->add('2', ['id' => 2])
        ->delete('2');
});

try {
    print_r($tmc->getWrapped()->toArray()); // output: ['0' => ['id' => 0]]
    $tmc->apply();
    print_r($tmc->getWrapped()->toArray()); // output: ['0' => ['id' => 0], ['1' => ['id' => 1]]]
} catch(ValidationException $e) {
    // if validation failed
}

TMappedLinkedList

LinkedList with mapping by id and with transactional interface.

Wraps MappedLinkedList container.

use Smoren\Containers\Transactional\Structs\TMappedLinkedList;
use Smoren\Containers\Transactional\Exceptions\ValidationException;
use Smoren\Containers\Structs\MappedLinkedList;

$tmll = new TMappedLinkedList(
    new MappedLinkedList([1 => 11])
);

print_r($tmll->getWrapped()->toArray()); // output: [1 => 11]

$tmll->interact(function(MappedLinkedList $list) {
    $list->pushBack(2, 22);
    $list->pushBack(3, 33);
});

try {
    print_r($tmll->getWrapped()->toArray()); // output: [1 => 11]
    $tmll->apply();
    print_r($tmll->getWrapped()->toArray()); // output: [1 => 11, 2 => 22, 3 => 33]
} catch(ValidationException $e) {
    // if validation failed
}

TSortedLinkedList

LinkedList with presort and transactional interface.

Wraps SortedLinkedList container.

use Smoren\Containers\Transactional\Structs\TSortedLinkedList;
use Smoren\Containers\Transactional\Exceptions\ValidationException;
use Smoren\Containers\Structs\SortedLinkedList;

/**
 * Class IntegerSortedLinkedList
 */
class IntegerSortedLinkedList extends SortedLinkedList
{
    /**
     * @inheritDoc
     */
    protected function getComparator(): callable
    {
        return function(int $lhs, int $rhs) {
            return $lhs > $rhs;
        };
    }
}

$tsll = new TSortedLinkedList(
    new IntegerSortedLinkedList([4, 1, 2])
);

print_r($tsll->getWrapped()->toArray()); // output: [1, 2, 4]

$tsll->interact(function(IntegerSortedLinkedList $list) {
    $list->insert(5);
    $list->insert(3);
});

try {
    print_r($tsll->getWrapped()->toArray()); // output: [1, 2, 4]
    $tsll->apply();
    print_r($tsll->getWrapped()->toArray()); // output: [1, 2, 3, 4, 5]
} catch(ValidationException $e) {
    // if validation failed
}

TSortedMappedLinkedList

LinkedList with presort, mapping and transactional interface.

Wraps SortedMappedLinkedList container.

use Smoren\Containers\Transactional\Structs\TSortedMappedLinkedList;
use Smoren\Containers\Transactional\Exceptions\ValidationException;
use Smoren\Containers\Structs\SortedMappedLinkedList;

$tsmll = new TSortedMappedLinkedList(
    new SortedMappedLinkedList([2 => -2, 1 => -1, 4 => -4])
);

print_r($tsmll->getWrapped()->toArray()); // output: [1 => -1, 2 => -2, 4 => -4]

$tsmll->interact(function(SortedMappedLinkedList $list) {
    $list->insert(3, 0);
});

try {
    print_r($tsmll->getWrapped()->toArray()); // output: [1 => -1, 2 => -2, 4 => -4]
    $tsmll->apply();
    print_r($tsmll->getWrapped()->toArray()); // output: [1 => -1, 2 => -2, 3 => 0, 4 => -4]
} catch(ValidationException $e) {
    // if validation failed
}