setherator/variables

The Setherator Variable management library. Manages and processes variable values with some additional magic.

1.0.3 2020-04-23 12:06 UTC

This package is auto-updated.

Last update: 2024-03-23 21:31:55 UTC


README

Latest Version on Packagist Software License Build Status Code Quality Code Coverage Mutation testing badge Total Downloads

Email

The Setherator Variable management library. Manages and processes variable values with some additional magic.

Install

Via Composer

$ composer require setherator/variables

Usage

A compilation of several use cases of Variables and it's helpers.

use Setherator\Variables\Variables;
use function Setherator\Variables\all;
use function Setherator\Variables\context;
use function Setherator\Variables\factory;
use function Setherator\Variables\logic;
use function Setherator\Variables\passthrough;
use function Setherator\Variables\ref;

$variables = new Variables();
$variables->setContext(['Prefix: ']);

$globalLogicState  = true;
$providedVariables = [
    'scalar'              => 'foo',
    // will execute closure and catch value
    'closure'             => fn() => 'closure Foo ' . random_int(1, 10),
    // Will be fetched at code load
    'ref'                 => ref('scalar', 'Not found'),
    // Will be only fetched when 'ref_on_get' is fetched
    'ref_on_get'          => fn() => ref('scalar'),
    // will return number increasing every time its fetched and 'Number: ' will be passed as argument to
    'factory'             => factory(
        function ($prefix) {
            static $i = 0;

            return $prefix . $i++;
        },
        function () {
            static $i = 0;

            return 'Number ' . $i++ . ': ';
        },
    ),
    // Will inject context values as arguments from Variables::getContext();
    'context'             => context(fn(string $prefix) => $prefix . random_int(1, 10)),
    'factory_context'     => factory(context(fn(string $prefix) => $prefix . random_int(1, 10))),
    'all'                 => all(
        fn() => 'First',
        fn() => 'Second',
        'Third'
    ),
    'logic'               => logic(
        fn() => 1,
        fn() => 'Condition: true',
        fn() => 'Condition: false',
    ),
    'logic_strict'        => logic(
        fn() => 1,
        fn() => 'Condition: true',
        fn() => 'Condition: false',
        true
    ),
    'logic_factory'       => factory(
        logic(
            function () use (&$globalLogicState) {
                return $globalLogicState;
            },
            function () use (&$globalLogicState) {
                $globalLogicState = !$globalLogicState;

                return 'Factory Condition: true';
            },
            function () use (&$globalLogicState) {
                $globalLogicState = !$globalLogicState;

                return 'Factory Condition: false';
            },
        )
    ),
    'passthrough'         => passthrough(
        Closure::fromCallable('strtoupper'),
        fn() => 'Passthrough: ' . ref('logic_factory'),
    ),
    'passthrough_factory' => factory(
        passthrough(
            Closure::fromCallable('strtoupper'),
            fn() => 'Passthrough Factory: ' . ref('logic_factory'),
        )
    ),
    'first' => first(
        0,
        'value'
    ),
];


$variables->add($providedVariables);


echo $variables->get('scalar') . PHP_EOL;
echo $variables->get('closure') . PHP_EOL;
echo $variables->get('closure') . PHP_EOL;
echo $variables->get('ref') . PHP_EOL;
echo $variables->get('ref_on_get') . PHP_EOL;
echo $variables->get('factory') . PHP_EOL;
echo $variables->get('factory') . PHP_EOL;
echo $variables->get('context') . PHP_EOL;
echo $variables->get('context') . PHP_EOL;
echo $variables->get('factory_context') . PHP_EOL;
echo $variables->get('factory_context') . PHP_EOL;
echo json_encode($variables->get('all')) . PHP_EOL;
echo $variables->get('logic') . PHP_EOL;
echo $variables->get('logic_strict') . PHP_EOL;
echo $variables->get('logic_factory') . PHP_EOL;
echo $variables->get('logic_factory') . PHP_EOL;
echo $variables->get('logic_factory') . PHP_EOL;
echo $variables->get('passthrough') . PHP_EOL;
echo $variables->get('passthrough') . PHP_EOL;
echo $variables->get('passthrough_factory') . PHP_EOL;
echo $variables->get('passthrough_factory') . PHP_EOL;
echo $variables->get('passthrough_factory') . PHP_EOL;
echo $variables->get('first') . PHP_EOL . PHP_EOL;

// Print all computed values
echo json_encode($variables->all(), JSON_PRETTY_PRINT) . PHP_EOL;

// Print all non computed values (Closures do not json encode)
echo json_encode($variables->all(false), JSON_PRETTY_PRINT) . PHP_EOL;

Will result in:


foo
closure Foo 4
closure Foo 4
Not found
foo
Number 0: 0
Number 1: 1
Prefix: 6
Prefix: 6
Prefix: 10
Prefix: 1
["First","Second","Third"]
Condition: true
Condition: false
Factory Condition: true
Factory Condition: false
Factory Condition: true
PASSTHROUGH: FACTORY CONDITION: FALSE
PASSTHROUGH: FACTORY CONDITION: FALSE
PASSTHROUGH FACTORY: FACTORY CONDITION: TRUE
PASSTHROUGH FACTORY: FACTORY CONDITION: FALSE
PASSTHROUGH FACTORY: FACTORY CONDITION: TRUE
value

{
    "scalar": "foo",
    "closure": "closure Foo 4",
    "ref": "Not found",
    "ref_on_get": "foo",
    "factory": "Number 2: 2",
    "context": "Prefix: 6",
    "factory_context": "Prefix: 8",
    "all": [
        "First",
        "Second",
        "Third"
    ],
    "logic": "Condition: true",
    "logic_strict": "Condition: false",
    "logic_factory": "Factory Condition: false",
    "passthrough": "PASSTHROUGH: FACTORY CONDITION: FALSE",
    "passthrough_factory": "PASSTHROUGH FACTORY: FACTORY CONDITION: TRUE",
    "first": "value"
}

{
    "scalar": "foo",
    "closure": "closure Foo 4",
    "ref": "Not found",
    "ref_on_get": "foo",
    "factory": {},
    "context": "Prefix: 6",
    "factory_context": {},
    "all": [
        "First",
        "Second",
        "Third"
    ],
    "logic": "Condition: true",
    "logic_strict": "Condition: false",
    "logic_factory": {},
    "passthrough": "PASSTHROUGH: FACTORY CONDITION: FALSE",
    "passthrough_factory": {},.
    "first": {}
}

Helpers

A variable value can be any scalar, array, object type but also closure which will be executed and cached. To prevent caching value should implement NonCacheableClosure interface for e.g. factory helper function.

Reference

A function to fetch variable value from Variables instance. If not found $default = null will be returned. If raw value before evaluation required use $raw = true.

function ref(string $name, $default = null, bool $raw = false);
function reference(string $name, $default = null, bool $raw = false);

To fetch value at variable get time use these functions.

function refFn(string $name, $default = null, bool $raw = false);
function referenceFn(string $name, $default = null, bool $raw = false);

Enviroment variable

A function to fetch environment variable. If not found $default = null will be returned.

function env(string $name, $default = null): string;

Context

A function to wrap your closure and inject context from Variables::getContext();

function context(Closure $closure, ...$args): Closure;Cacheable

Will return your closure wrapped with context variables + extra $args as arguments. $args will be evaluated using Variables::parseValue() function. It will behave as normal Variable value.

[
    'context_aware_variable' => context(
        function (Setherator $setherator, string $input) {
            // ... Your logic
            
            return 'Your typed input: ' . $input;
        },
        ask('Input')
    ),
]

Attention: Context returned closure does not accept any arguments.

Factory

A function to prevent your closue value from getting cached. Your closure will be called everytime value is accessed. $args will be passed as arguments to closure function. $args will be evaluated using Variables::parseValue() function. It will behave as normal Variable value.

function factory(Closure $closure, ...$args): NonCacheableClosure;

Will return a value which implements NonCacheableClosure interface and prevents it from caching and behave as your normal closure.

[
    'factory_value' => factory(
        function (string $input) {
            // ... Your logic
            
            return 'Your typed input: ' . $input;
        },
        ask('Input')
    ),
]

All

A function to evaluate all values passed to arguments and return result as array.

function all(...$args): array

Will return an array of all $args evaluated.

[
    'all' => all(
        ask('Please provide project name'),
        ask('Please provide folder name')
    )
]

Tip: To evaluate all values at variable get time use function: allFn(/* ... */).

Logic

A function to evaluate condition and decide which value to use. $condtion, $true, $false are evaluated using Variables::parseValue() function.

function logic($condition, $true, $false, bool $strict = false): Closure;

Will return a closure which will decide which $true or $false to return based on $condition

[
    'logic_based_value' => logic(
        fn() => askChoice('Please select app env', ['dev', 'prod']) !== 'dev',
        'Environement is production',
        fn() => 'Enviroment is dev and time is: ' . time()
    )
]

Attention: Logic returned closure does not accept any arguments.

Passthrough

A function which will pass all evaluted values as argumnents to closure.

function passthrough(Closure $closure, ...$args): Closure;

Will return a closure which will pass $args evaluated as arguments to Closure.

[
    'passthough_value' => passthrough(
        function (string $projectName, string $projectFolderName) {
            return 'Project "' . $projectName . '" at "' . $projectFolderName . '"';
        }
        ask('Please provide project name'),
        ask('Please provide project folder name')
    )
]

Attention: Passthrough returned closure does not accept any arguments.

First

A function which return a first truthfull value from arguments. $args will be evaluated using Variables::parseValue() function.

function first(...$args);

Tip: To evaluate at variable get time use function: firstFn(/* ... */).

Value Parsers

You can implement your own value parsers to be parsed when accessing variables value.

class JsonEncodeValue
{
    private $value;
    
    public function __construct($value)
    {
        $this->value = $value;
    }
    
    public function getValue()
    {
        return $this->value;
    }
}

class JsonEncodeValueParser implements ValueParserInterface
{
    public function supports($value): bool
    {
        return $value instanceof JsonEncodeValue;
    }

    public function parseValue($value, Variables $variables)
    {
        return json_encode($value->getValue());
    }
}

$variables = new Variables();
$variables->addValueParser(new JsonEncodeValueParser());

$variables->set('json', new JsonEncodeValue(['foo' => 'bar']);
$variables->get('json') // => {"foo":"bar"}

Testing

Run test cases

$ composer test

Run test cases with coverage (HTML format)

$ composer test-coverage

Run PHP style checker

$ composer cs-check

Run PHP style fixer

$ composer cs-fix

Run all continuous integration tests

$ composer ci-run

Contributing

Please see CONTRIBUTING and CONDUCT for details.

License

Please see License File for more information.