Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Schemator to Architectural section #1262

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Smoren
Copy link
Contributor

@Smoren Smoren commented Mar 3, 2024

Schematic data mapper · Packagist PHP Version Support Coverage Status CI License: MIT

Schemator is a tool for converting nested data structures (any composition of associative arrays, non-associative arrays and objects) according to the given conversion schema.

Examples

Simple usage

use Smoren\Schemator\Factories\SchematorFactory;

$input = [
    'id' => 100,
    'name' => 'Oxford',
    'country' => [
        'id' => 10,
        'name' => 'UK',
        'neighbours' => ['Ireland', 'Sweden', 'France'],
        'capitals' => [
            'lnd' => 'London',
            'edb' => 'Edinburgh',
        ],
    ],
    'streets' => [
        [
            'id' => 1000,
            'name' => 'Woodstock Rd',
            'houses' => [1, 5, 9],
        ],
        [
            'id' => 1002,
            'name' => 'Banbury Rd',
            'houses' => [22, 35, 49],
        ],
        [
            'id' => 1003,
            'name' => 'Beamont St',
            'houses' => [11, 12, 15],
        ],
    ],
    'lnd_path' => 'country.capitals.lnd',
];

$schema = [
    'city_id' => 'id',
    'city_name' => 'name',
    'city_street_names' => 'streets.*.name',
    'country_id' => 'country.id',
    'country_name' => 'country.name',
    'country_neighbours' => 'country.neighbours',
    'country_neighbour' => 'country.neighbours',
    'country_first_capital' => 'country.capitals.lnd',
    'country_second_capital' => 'country.capitals.edb',
    'country_data.country_id' => 'country.id',
    'country_data.country_name' => 'country.name',
];

$schemator = SchematorFactory::create();
$output = $schemator->convert($input, $schema);

print_r($output);
/* Array
(
    [city_id] => 100
    [city_name] => Oxford
    [city_street_names] => Array
        (
            [0] => Woodstock Rd
            [1] => Banbury Rd
            [2] => Beamont St
        )

    [country_id] => 10
    [country_name] => UK
    [country_neighbours] => Array
        (
            [0] => Ireland
            [1] => Sweden
            [2] => France
        )

    [country_neighbour] => Array
        (
            [0] => Ireland
            [1] => Sweden
            [2] => France
        )

    [country_first_capital] => London
    [country_second_capital] => Edinburgh
    [country_data] => Array
        (
            [country_id] => 10
            [country_name] => UK
        )

)
*/

Using base filters

use Smoren\Schemator\Factories\SchematorFactory;
use Smoren\Schemator\Filters\BaseFiltersStorage;

$input = [
    'id' => 100,
    'name' => 'Oxford',
    'country' => [
        'id' => 10,
        'name' => 'UK',
        'neighbours' => ['Ireland', 'Sweden', 'France'],
        'capitals' => [
            'lnd' => 'London',
            'edb' => 'Edinburgh',
        ],
    ],
    'streets' => [
        [
            'id' => 1000,
            'name' => 'Woodstock Rd',
            'houses' => [1, 5, 9],
        ],
        [
            'id' => 1002,
            'name' => 'Banbury Rd',
            'houses' => [22, 35, 49],
        ],
        [
            'id' => 1003,
            'name' => 'Beamont St',
            'houses' => [11, 12, 15],
        ],
    ],
    'lnd_path' => 'country.capitals.lnd',
];

$schema = [
    'city_street_names.all' => ['streets.*.name', ['implode', ', ']],
    'city_street_names.sorted' => ['streets.*.name', ['sort'], ['implode', ', ']],
    'city_street_names.filtered' => ['streets.*.name', ['filter', fn (string $candidate) => strpos($candidate, 'Ban') !== false]],
    'lnd' => ['lnd_path', ['path']],
    'city_street_houses' => ['streets.*.houses', ['flatten']],
];

$schemator = SchematorFactory::create();
$output = $schemator->convert($input, $schema);

print_r($output);
/*
Array
(
    [city_street_names] => Array
        (
            [all] => Woodstock Rd, Banbury Rd, Beamont St
            [sorted] => Banbury Rd, Beamont St, Woodstock Rd
            [filtered] => Array
                (
                    [0] => Banbury Rd
                )

        )

    [lnd] => London
    [city_street_houses] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 9
            [3] => 22
            [4] => 35
            [5] => 49
            [6] => 11
            [7] => 12
            [8] => 15
        )

)
*/

Using custom filters

use Smoren\Schemator\Factories\SchematorFactory;
use Smoren\Schemator\Interfaces\FilterContextInterface;

$schemator = SchematorFactory::createBuilder()
    ->withFilters([
        'startsWith' => function (FilterContextInterface $context, string $start) {
            return array_filter($context->getSource(), function (string $candidate) use ($start) {
                return strpos($candidate, $start) === 0;
            });
        },
    ])
    ->get();

$input = [
    'streets' => ['Woodstock Rd', 'Banbury Rd', 'Beamont St'],
];

$schema = [
    'street_names' => ['streets', ['startsWith', 'T'], ['implode', ', ']],
];

$output = $schemator->convert($input, $schema);

print_r($output);
/*
Array
(
    [street_names] => Woodstock Rd, Beamont St
)
*/

@alexkart
Copy link
Collaborator

alexkart commented Mar 3, 2024

It doesn't seem to be widely used yet.

@Smoren
Copy link
Contributor Author

Smoren commented Mar 5, 2024

Thank you @alexkart for your comment. I agree that the repository is not widely popular at the moment, but I hope that its usefulness will be a more important factor in deciding whether to add it to the list.

@dereuromark
Copy link
Collaborator

Looks to me like this is a bit more powerful version of https://github.com/jolicode/automapper
In general, I am a big fan of the idea of having a schema to map from incoming data (e.g. API call) to nested (DTO) objects.

I was working on sth even more powerful that auto-defines itself based on the data structure of the example array, creating the schema on its own (with only few customizations necessary), generating the necessary PHP classes and having it all up and ready < 1min: https://github.com/dereuromark/cakephp-dto
Still framework specific, but it could be made more generic, if people are interested in the idea and helping out.

That said, I think having at least one useful datamapper on its own listed here sounds like a good idea.
Do we have already some listed?

@zjd85611234
Copy link

哈喽

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants