ylsideas/forecaster

a library for manipulating and casting associative arrays in PHP

v1.2.0 2018-10-27 16:48 UTC

This package is auto-updated.

Last update: 2024-03-28 05:24:03 UTC


README

Forecaster is a library for manipulating and casting associative arrays in PHP.

While the project makes use of a class and helpers found in Laravel it can be used in non-Laravel projects as it only depends upon the Tighten Co's Collect package and not the Laravel Support package meaning it's compatible with any framework or stand-alone project.

Installation

Forecaster is compatible and tested with PHP 7.1 and greater.

This package should be installed through composer using the following command:

composer require ylsideas/forecaster

Usage

You can use Forecaster to process arrays with casting and array placement. For example all the following basic types are included, int, integer, float, double, real, string, boolean and bool. You can also ignore the data type argument so no casting is done but the key will still be included.

$result = forecast([
    'a-string-int' => '10',
    'a-string-float' => '1.5',
    'an-int' => 10,
    'another-int' => 1,
    'do-not-touch' => '11'
])
    ->cast('a-string-int', 'anInt', 'int')
    ->cast('a-string-float', 'aFloat', 'float')
    ->cast('an-int', 'aString', 'string')
    ->cast('another-int', 'aBoolean', 'bool')
    ->cast('do-not-touch', 'doNotTouch')
    ->get();

// $results to

[
    'anInt' => 10,
    'aFloat' => 1.5,
    'aString' => '10',
    'aBoolean' => true,
    'doNotTouch' => '11',
]   

Forecaster can also handle more complex array structures using dot notation.

$result = forecast([
    'onions' => [
        'have' => [
            'layers' => true,
        ]
    ]
])
    ->cast('onions.have.layers', 'ogres.do.to')
    ->get();
    
// results to

[
    'orgres' => [
        'do' => [
            'to' => true,
        ]
    ]
]               

A nice piece of functionality is that it can cast all the values of an array using the castAll method. There is even the option to do this using wild cards.

$result = forecast([
    'anArrayOfStrings' => [
        '10', '100', '1000'
    ],
    'anArrayOfArrays' => [
        ['value' => '20'],
        ['value' => '200'],
        ['value' => '2000'],
    ]
])
    ->castAll('anArrayOfStrings', 'an-array-of-ints')
    ->castAll('anArrayOfArrays.*.value', 'an-array-of-all-values')
    ->get();
    
// results to

[
    'an-array-of-ints' => [
        10, 100, 1000
    ],
    'an-array-of-all-values' => [
        20, 200, 2000
    ],
]               

You need not use just arrays, you may also use an object or a mix of objects and arrays with the same dot notation.

$object = new stdClass();
$object->objField = [
    'arrField' => '10',
];

$result = forecast($object)
    ->cast('objField.arrField', 'my_field', 'int')
    ->get();
    
// results to

[
    'my_field' => 10,
]               

Manipulating sub arrays is also relatively easy using the castItems method

$result = forecast([
    'an-array' => [
        ['attr' => '10'],
        ['attr' => '100'],
        ['attr' => '1000'],
    ]
])
    ->castItems('an-array', 'anArray', function (Forecaster $forecaster) {
        $forecaster->cast('attr', 'Attribute', 'int');
    })
    ->get();
    
// results to

[
    'anArray' => [
        ['Attribute' => 10],
        ['Attribute' => 100],
        ['Attribute' => 1000],
    ]
]    

Add your own fixed transformers

You can apply your own transformers to the Forecaster class statically making them available to all instances created.

Forecaster::transformer('csv', function ($value) {
    return str_getcsv($value);
});

$results = forecast([
    'test' => '1, 2, 3',
])
    ->cast('test', 'output', 'csv')
    ->get();
    
// results to

[
    'output' => ['1', '2', '3']
]

Use functions for casting on the fly

$results = forecast([
    'test' => '1, 2, 3',
])
    ->cast('test', 'output', function ($value) {
        return str_getcsv($value);
    })
    ->get();
    
// results to

[
    'output' => ['1', '2', '3']
]

Use classes for more complex casting

You can define transformers if you need to perform more complex logic that you wish to reuse.

public class CsvTransformer implements CastingTransformer
{
    public function cast(string $in, string $out, array $item, array $processed)
    {
        return str_getcsv($item[$in]);
    }
}

Which can then be applied when using forecast.

$results = forecast([
    'test' => '1, 2, 3',
])
    ->cast('test', 'output', new CsvTransformer())
    ->get();
    
// results to

[
    'output' => ['1', '2', '3']
]

Conditional transformations

Sometimes you might want to only perform some casting based on certain conditions. Forecaster provides a function for this that will only execute when the condition is truthy (e.g. == true).

$processed = Forecaster::make([
    'test' => '10',
])
    ->when(true, function (Forecaster $caster) {
        $caster->cast('test', 'output', 'int');
    })
    ->get();
    
// results to

[
    'output' => 10, 
]    

You may also use a function to resolve the conditional.

$processed = Forecaster::make([
    'test' => '10',
])
    ->when(
        function ($item) {
            return $item['test'] > 1;
        }, 
        function (Forecaster $caster) {
            $caster->cast('test', 'output', 'int');
        }
    )
    ->get();
    
// results to

[
    'output' => 10, 
]    

Cast Into objects

If you're rather turn the result into an object of your choice you can provide a class string to the get method.

$results = forecast([
    'test' => '10',
])
    ->cast('test', 'output')
    ->get(SomeClass::class);

You can also provide the string object as a parameter which will instruct the forecaster instance to cast the array into a stdClass object.

$object = forecast([
    'test' => '10',
])
    ->cast('test', 'output')
    ->get('object');

There is also the option to resolve this using a function.

$results = forecast([
    'test' => '10',
])
    ->cast('test', 'output')
    ->get(function ($processed) {
        return new SomeClass($processed['output']);
    });

Using it with Laravel/Tighten Collections

If you have an array of items you'd like to cast that's already in a Laravel/Tighten Collection class a macro is available allowing you to do it seamlessly.

$collection = collect([
    ['test' => '123.456'],
    ['test' => '789.101112']
])
    ->forecast(function (Forecaster $forecast) {
        $forecast->cast('test', 'output', 'float');
    })
    ->toArray();
    
// results to

[
    ['output' => 123.456],
    ['output' => 789.101112],
]

This macro also lets you specify the outcome of the forecast if you want to transform each of them into a particular class or an stdObject.

$collection = collect([
    ['test' => '123.456'],
    ['test' => '789.101112']
])
    ->forecast(
        function (Forecaster $forecast) {
            $forecast->cast('test', 'output', 'float');
        }, 
        'object'
    );

FAQ

Why no datetime converter?

Currently we feel this should be implemented by the user and not apart of the library due to how some developers only use datetime while others would use additional packages like Carbon or Chronos. We're open to ideas for this as it makes sense. We just don't want to put forward something that requires a breaking change early on.

Testing

Testing for this package is done using PHPUnit. You can run this from the composer dependencies. Running vendor/bin/phpunit will execute phpunit.xml.dist but you may copy it to phpunit.xml if you wish to change it for your own testing but please do not commit your version of phpunit.xml as part of any PR.

Contributing

If you wish to contribute to this project, please read the included contribution guide

License

This project is covered by the MIT license and can be read about the included license.md.