PHP Classes

Schematic PHP Data Mapper: Process and convert nested arrays and objects

Recommend this page to a friend!
  Info   Documentation   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Ratings Unique User Downloads Download Rankings
Not yet rated by the usersTotal: 39 All time: 10,910 This week: 89Up
Version License PHP version Categories
schemator-php 1.0MIT/X Consortium ...7.4Libraries, Data types, PHP 7
Description 

Author

This package can process and convert nested arrays and objects.

It can take as parameters an array or an object and an array that defines the schema.

The package can perform the data mapping conversion according to the schema definitions and returns an array with the mapped values.

Picture of Smoren  Freelight
  Performance   Level  
Name: Smoren Freelight <contact>
Classes: 38 packages by
Country: Russian Federation Russian Federation
Age: 35
All time rank: 280978 in Russian Federation Russian Federation
Week rank: 164 Up10 in Russian Federation Russian Federation Up
Innovation award
Innovation award
Nominee: 16x

Documentation

Schematic data mapper

Packagist PHP Version Support Scrutinizer Code Quality Coverage Status Build and test License: MIT

Schemator logo

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

How to install to your project

composer require smoren/schemator

Usage

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
        )

)
*/

Setting errors level

use Smoren\Schemator\Factories\SchematorFactory;
use Smoren\Schemator\Structs\ErrorsLevelMask;
use Smoren\Schemator\Exceptions\SchematorException;

$input = [
    'some_key' => null,
];
$schema = [
    'my_value' => ['some_key', ['date', 'Y-m-d']],
];

$schemator = SchematorFactory::createBuilder()
    ->withErrorsLevelMask(
        ErrorsLevelMask::nothing()
            ->add([SchematorException::FILTER_ERROR, SchematorException::CANNOT_GET_VALUE])
    )
    ->get();

try {
    $schemator->convert($input, $schema);
} catch(SchematorException $e) {
    echo $e->getMessage(); // filter error: 'date'
}

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', function (string $candidate) {
        return 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 smart filter and replace

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

$schemator = SchematorFactory::create();
$input = [
    'numbers' => [-1, 10, 5, 22, -10, 0, 35, 7, 8, 9, 0],
];

$output = $schemator->convert($input, [
    'positive' => [
        'numbers',
        ['filter', [['>', 0]]],
        ['sort'],
    ],
    'negative' => [
        'numbers',
        ['filter', [['<', 0]]],
        ['sort'],
    ],
    'complicated' => [
        'numbers',
        ['filter', [['>=', 8], ['<', 0]]],
        ['filter', [['<', 22]]],
        ['sort'],
    ],
]);

print_r($output);
/*
Array
(
    [positive] => Array
        (
            [0] => 5
            [1] => 7
            [2] => 8
            [3] => 9
            [4] => 10
            [5] => 22
            [6] => 35
        )

    [negative] => Array
        (
            [0] => -10
            [1] => -1
        )

    [complicated] => Array
        (
            [0] => -10
            [1] => -1
            [2] => 8
            [3] => 9
            [4] => 10
        )

)
*/

$output = $schemator->convert($input, [
    'number_types' => ['numbers', [
        'replace',
        [
            ['=0', '=', 0],
            ['>9', '>', 9],
            ['<0', '<', 0],
            ['1-8', 'between', 1, 8],
        ]
    ]]
]);

print_r($output);
/*
Array
(
    [number_types] => Array
        (
            [0] => <0
            [1] => >9
            [2] => 1-8
            [3] => >9
            [4] => <0
            [5] => =0
            [6] => >9
            [7] => 1-8
            [8] => 1-8
            [9] => 9
            [10] => =0
        )

)
*/

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
)
*/

Mass usage

use Smoren\Schemator\Factories\SchematorFactory;

$massSchemator = SchematorFactory::createMass();

$cities = [
    [
        'id' => 100,
        'name' => 'London',
        'country' => [
            'id' => 10,
            'name' => 'UK',
        ],
        'streets' => [
            [
                'id' => 1001,
                'name' => 'The Mall',
            ],
            [
                'id' => 1002,
                'name' => 'Carnaby Street',
            ],
        ],
    ],
    [
        'id' => 101,
        'name' => 'Oxford',
        'country' => [
            'id' => 10,
            'name' => 'UK',
        ],
        'streets' => [
            [
                'id' => 1003,
                'name' => 'Turl Street',
            ],
            [
                'id' => 1004,
                'name' => 'Holywell Street',
            ],
        ],
    ],
];

$schema = [
    'city_id' => 'id',
    'city_name' => 'name',
    'city_street_names' => 'streets.name',
    'country_id' => 'country.id',
    'country_name' => 'country.name',
];

$gen = $massSchemator->generate($cities, $schema);

$result = [];
foreach($gen as $item) {
    $result[] = $item;
}

print_r($result);
/*
Array
(
    [0] => Array
        (
            [city_id] => 100
            [city_name] => London
            [city_street_names] => Array
                (
                    [0] => The Mall
                    [1] => Carnaby Street
                )

            [country_id] => 10
            [country_name] => UK
        )
    [1] => Array
        (
            [city_id] => 101
            [city_name] => Oxford
            [city_street_names] => Array
                (
                    [0] => Turl Street
                    [1] => Holywell Street
                )

            [country_id] => 10
            [country_name] => UK
        )
)
*/

Filters

const

Sets the value from const param.

Schema:

["value" => [["const", "My const value"]]]

Result:

["value" => "My const value"]

sum

Returns the sum of given array.

Given:

["numbers" => [1, 2, 3, 4, 5]]

Schema:

["value" => ["numbers", ["sum"]]]

Result:

["value" => 15]

average

Returns the average of given array.

Given:

["numbers" => [1, 2, 3, 4, 5]]

Schema:

["value" => ["numbers", ["average"]]]

Result:

["value" => 3]

date

Returns formatted date from the Unix timestamp given value.

Params:

  1. Date format * required * data type ? string * example: `d.m.Y H:i:s` * more about formats
  2. Time zone offset from GMT * optional * data type ? integer * default ? 0

Given:

["some_date" => 1651481881]

Schema:

["value" => ["some_date", ["date", "d.m.Y H:i:s", 3]]]

Result:

["value" => "02.05.2022 11:58:01"]

implode

Returns string of imploded items of given array with separator from args list.

params:

  1. Separator * required * data type ? string * example: `; `

Given:

["numbers" => [1, 2, 3, 4, 5]]

Schema:

["value" => ["numbers", ["implode", "; "]]]

Result:

["value" => "1; 2; 3; 4; 5"]

explode

Returns array of exploded strings from given string with separator from args list

params:

  1. Separator * required * data type ? string * example: `; `

Given:

["numbers" => "1; 2; 3; 4; 5"]

Schema:

["value" => ["numbers", ["explode", "; "]]]

Result:

["value" => ["1", "2", "3", "4", "5"]]

flatten

Returns flat array contains all the dead end leaves of tree array.

Given:

[
   "numbers" => [
      [
         [1, 2, 3],
         [4, 5, 6]
      ],
      [7, 8, 9]
   ],
]

Schema:

["value" => ["numbers", ["flatten"]]]

Result:

["value" => [1, 2, 3, 4, 5, 6, 7, 8, 9]]

sort

Sorts and returns given array.

Given:

["numbers" => [3, 5, 4, 1, 2]]

Schema:

["value" => ["numbers", ["sort"]]]

Result:

["value" => [1, 2, 3, 4, 5]]

rsort

Sorts reversely and returns given array.

Given:

["numbers" => [3, 5, 4, 1, 2]]

Schema:

["value" => ["numbers", ["sort"]]]

Result:

["value" => [5, 4, 3, 2, 1]]

filter

Returns array contains elements from given array, that match the predicates from params list.

Rules:

  • Every predicate has such format `["predicate name", ...parans]`.
  • Predicates in one filter apply according the "OR" logic.
  • To apply "AND" logic use chain of filters.
  • Available predicates: * `["=", 10]` means `value = 10` * `[">", 10]` means `value > 10` * `[">=", 10]` means `value >= 10` * `["<", 10]` means `value < 10` * `["<=", 10]` means `value <= 10` * `["in", [1, 2]]` means `value = 1 OR value = 2` * `["not in", [1, 2]]` means `value != 1 AND value != 2` * `["between", 1, 5]` means `1 <= value <= 5` * `["between strict", 1, 5]` means `1 < value < 5`

Given:

["numbers" => [-5, -3, -1, 1, 3, 5]]

Schema:

[
   "value" => [
      "numbers",
      [
         "filter",
         [[">", 1], ["<", -1]] // value > 1 OR value < -1
      ],
   ],
]

Result:

["value" => [-5, -3, 3, 5]]

replace

Returns array of elements from given array with replaces by rules from params list.

Rules:

  • Every rule has such format `["value to replace", "rule name", ...params]`.
  • Rules in one filter apply according the "OR" logic.
  • To apply "AND" logic use chain of filters.
  • Available rules: * `["=", 10]` means `value = 10` * `[">", 10]` means `value > 10` * `[">=", 10]` means `value >= 10` * `["<", 10]` means `value < 10` * `["<=", 10]` means `value <= 10` * `["in", [1, 2]]` means `value = 1 ??? value = 2` * `["not in", [1, 2]]` means `value != 1 ? value != 2` * `["between", 1, 5]` means `1 <= value <= 5` * `["between strict", 1, 5]` means `1 < value < 5` * `["else"]` ? no rules matched for value _(If rule `else` did not use, by default such values are replaced with `null`)_

Given:

["numbers" => [-5, -3, -1, 1, 3, 5]]

Schema:

[
   "value" => [
      "numbers",
      [
         "replace",
         [
            ["positive", ">", 0],
            ["negative", "<", 0],
            ["zero", "else"]
         ],
      ],
   ],
]

Result:

["value" => ["negative", "negative", "negative", "zero", "positive", "positive", "positive"]]

Chain of filters

Given:

["numbers" => [-5, -3, -1, 1, 3, 5]]

Schema:

[
   "value" => [
      "numbers",
      [
         "filter",
         [[">", 1], ["<", -1]] // (value > 1 OR value < -1)
      ],
      // AND
      [
         "filter",
         [[">=", -3]] // value >= -3
      ],
   ],
]

Result:

["value" => [-3, 3, 5]]

Unit testing

composer install
composer test-init
composer test

Standards

Schemator conforms to the following standards:

License

Schemator is licensed under the MIT License.


  Files folder image Files (28)  
File Role Description
Files folder image.github (1 directory)
Files folder imagedocs (1 directory)
Files folder imagesrc (7 directories)
Files folder imagetests (3 files, 2 directories)
Accessible without login Plain text file .travis.yml Data Auxiliary data
Accessible without login Plain text file codeception.yml Data Auxiliary data
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files (28)  /  .github  
File Role Description
Files folder imageworkflows (1 file)

  Files folder image Files (28)  /  .github  /  workflows  
File Role Description
  Accessible without login Plain text file test_master.yml Data Auxiliary data

  Files folder image Files (28)  /  docs  
File Role Description
Files folder imageimages (1 file)

  Files folder image Files (28)  /  docs  /  images  
File Role Description
  Accessible without login Image file schemator-logo.png Data Auxiliary data

  Files folder image Files (28)  /  src  
File Role Description
Files folder imageComponents (2 files)
Files folder imageExceptions (1 file)
Files folder imageFactories (2 files)
Files folder imageFilters (1 file)
Files folder imageInterfaces (5 files)
Files folder imageStructs (2 files)
Files folder imageUtil (2 files)

  Files folder image Files (28)  /  src  /  Components  
File Role Description
  Plain text file MassSchemator.php Class Class source
  Plain text file Schemator.php Class Class source

  Files folder image Files (28)  /  src  /  Exceptions  
File Role Description
  Plain text file SchematorException.php Class Class source

  Files folder image Files (28)  /  src  /  Factories  
File Role Description
  Plain text file SchematorBuilder.php Class Class source
  Plain text file SchematorFactory.php Class Class source

  Files folder image Files (28)  /  src  /  Filters  
File Role Description
  Plain text file BaseFiltersStorage.php Class Class source

  Files folder image Files (28)  /  src  /  Interfaces  
File Role Description
  Plain text file FilterContextInterface.php Class Class source
  Plain text file FiltersStorageInterface.php Class Class source
  Plain text file MassSchematorInterface.php Class Class source
  Plain text file SchematorBuilderInterface.php Class Class source
  Plain text file SchematorInterface.php Class Class source

  Files folder image Files (28)  /  src  /  Structs  
File Role Description
  Plain text file ErrorsLevelMask.php Class Class source
  Plain text file FilterContext.php Class Class source

  Files folder image Files (28)  /  src  /  Util  
File Role Description
  Plain text file ArrayHelper.php Class Class source
  Plain text file RuleHelper.php Class Class source

  Files folder image Files (28)  /  tests  
File Role Description
Files folder imageunit (2 files)
Files folder image_support (1 file)
  Accessible without login Plain text file coding_standard.xml Data Auxiliary data
  Accessible without login Plain text file unit.suite.yml Data Auxiliary data
  Accessible without login Plain text file _bootstrap.php Aux. Auxiliary script

  Files folder image Files (28)  /  tests  /  unit  
File Role Description
  Plain text file MassSchematorTest.php Class Class source
  Plain text file SchematorTest.php Class Class source

  Files folder image Files (28)  /  tests  /  _support  
File Role Description
  Plain text file UnitTester.php Class Class source

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads Download Rankings  
 100%
Total:39
This week:0
All time:10,910
This week:89Up