├── .github └── workflows │ └── phpunit.yml ├── .gitignore ├── .phpstorm.meta.php └── autocomplete.meta.php ├── README.md ├── benchmark ├── ChildModel.php ├── UserModel.php ├── bechmark-collections.php ├── bechmark.php └── maps │ ├── ChildModel │ └── dto.php │ └── UserModel │ └── dto.php ├── composer.json ├── composer.lock ├── docs └── migrate5to6.md ├── src ├── DataTransformer.php ├── DataTransformerInterface.php ├── MapsManager.php ├── Normalizer.php └── NormalizerInterface.php └── test ├── phpunit.xml └── unit ├── DataTransformerTest.php ├── MapsManagerTest.php ├── RefTest.php └── data ├── Container.php ├── UserModel.php ├── UserModel └── dto.php ├── dto.php └── withRefs.map.php /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: phpunit 2 | 3 | on: 4 | pull_request: {} 5 | release: {} 6 | push: 7 | branches: [ master ] 8 | 9 | jobs: 10 | tests: 11 | name: unit tests 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | php-versions: [ 8.1, 8.2 ] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: php-actions/composer@v6 21 | 22 | - name: phpunit tests ${{ matrix.php-versions }} 23 | uses: php-actions/phpunit@v3 24 | with: 25 | configuration: test/phpunit.xml 26 | php_extensions: pcov 27 | php_version: ${{ matrix.php-versions }} 28 | version: 9.5 29 | 30 | - name: coverage monitor 31 | uses: slavcodev/coverage-monitor-action@1.6.0 32 | with: 33 | github_token: ${{ secrets.GITHUB_TOKEN }} 34 | coverage_path: test/clover.xml 35 | comment_footer: false 36 | 37 | - name: Upload coverage to Codecov 38 | uses: codecov/codecov-action@v3 39 | with: 40 | token: ${{ secrets.CODECOV_TOKEN }} 41 | files: test/clover.xml 42 | name: github-ci 43 | verbose: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | test/clover.xml 3 | .phpunit.result.cache 4 | .idea -------------------------------------------------------------------------------- /.phpstorm.meta.php/autocomplete.meta.php: -------------------------------------------------------------------------------- 1 | "@", 7 | ])); 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-data-transformer2 2 | 3 | [![phpunit](https://github.com/alexpts/php-data-transformer2/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/alexpts/php-data-transformer2/actions/workflows/phpunit.yml) 4 | [![codecov](https://codecov.io/gh/alexpts/php-data-transformer2/branch/master/graph/badge.svg?token=14L6IJA5UE)](https://codecov.io/gh/alexpts/php-data-transformer2) 5 | 6 | Позволяет извлекать данные из объектов и создавать объекты из данных. Позволяет делать это по заранее опрелделенной схеме в обе стороны. Например извлечь данные из Model для записи в БД. Либо создать/заполнить Model данными из БД. 7 | 8 | 9 | ### Install 10 | 11 | `composer require alexpts/php-data-transformer2` 12 | 13 | Библиотека представляет собой более высокий уровень билбиотеки https://github.com/alexpts/php-hydrator. Расширяя ее 14 | возможности и упрощая работу за счет: 15 | 16 | - Декларативного описания правил преобразования 17 | - Рекурсивного преобразования вложенных моделей и коллекций моделей 18 | - Более лаконичного синтаксиса 19 | 20 | Базовые правила схем трансформации подробно описаны в проекте https://github.com/alexpts/php-hydrator. 21 | 22 | ### Data Transformer 23 | 24 | Класс DataTransformer является более высокоуровневым. Он позволяет работать с HydratorService и описывать схемы 25 | преобразования для каждого класса отдельно. 26 | 27 | Для одного класса может быть множество схем преобразования. Для преобразования модели для сохранения в БД 28 | требуется преобразовать ее в DTO сущность (массив php). При этом все значения типа \DateTime преобразовать в timestamp (integer тип). Если мы передаем эту же модель на клиент через REST API, то схема преобразования может быть иной. Все значения \DateTime нужно представить в виде строки в формате ISO8601. 29 | 30 | ```php 31 | use PTS\DataTransformer\DataTransformer; 32 | 33 | $dataTransformer = new DataTransformer; 34 | $dataTransformer->getMapsManager()->setMapDir(UserModel::class, __DIR__ . '/data'); 35 | 36 | $model = $dataTransformer->toModel(UserModel::class, [ 37 | 'id' => 1, 38 | 'creAt' => new DateTime, 39 | 'name' => 'Alex', 40 | 'active' => 1, 41 | ]); 42 | 43 | $dto = $dataTransformer->toDTO($model, 'dto'); 44 | $dtoForDb = $dataTransformer->toDTO($model, 'db'); 45 | ``` 46 | 47 | ### Вариации представлений 48 | 49 | Может потребоваться для разных сценариев извлекать данные по разным правиоам из модели. 50 | Либо может быть просто более компактное представлеиние этой же модели, без лишних деталей. Можно использовать несколько схем для 1 модели, например `short.dto`: 51 | 52 | ```php 53 | $shortFormatDto = $dataTransformer->toDTO($model, 'short.dto'); 54 | ``` 55 | 56 | Также можно исключить часть полей, без необъодимости определять новую схему/map для преобразования, указав при вызовы опцию `excludeFields` с массивом игнорируемых полей в схеме: 57 | 58 | ```php 59 | $shortFormatDto = $dataTransformer->toDTO($model, 'dto', [ 60 | 'excludeFields' => ['password'] 61 | ]); 62 | ``` 63 | 64 | ### Коллекция моделей 65 | 66 | Небольшой сахар, чтобы перевести коллекцию однотипных моделей в коллекцию DTO: 67 | 68 | ```php 69 | $mapName = 'dto'; 70 | $excludedFields = ['name']; 71 | $dtoCollection = $dataTransformer->toDtoCollection($models, $mapName); 72 | ``` 73 | 74 | ### Вложенные модели 75 | 76 | Если свойство модели представлено другой моделью или коллекцией моделей, то можно рекурсивно извлечь/заполнить модель. Для этого в схеме маппинга нужно использовать ключ `ref`. 77 | 78 | ```php 79 | // map file deepDto.php 80 | return [ 81 | 'id' => [], 82 | 'creAt' => [], 83 | 'name' => [], 84 | 'login' => [], 85 | 'active' => [ 86 | 'pipe-populate' => ['boolval'], 87 | 'pipe-extract' => ['boolval'], 88 | ], 89 | 'email' => [ 90 | 'pipe-populate' => [ // any callable 91 | 'strval', 92 | 'strtolower', 93 | ] 94 | ], 95 | 'refModel' => [ 96 | 'ref' => [ 97 | 'model' => UserModel::class, 98 | 'map' => 'dto' 99 | ] 100 | ], 101 | 'refModels' => [ 102 | 'ref' => [ 103 | 'model' => UserModel::class, 104 | 'map' => 'dto', 105 | 'collection' => true 106 | ] 107 | ], 108 | ]; 109 | 110 | // code file 111 | $model = $dataTransformer->toModel(UserModel::class, [ 112 | 'id' => 1, 113 | 'creAt' => new DateTime, 114 | 'name' => 'Alex', 115 | 'active' => 1, 116 | 'refModel' => [ 117 | 'id' => 2, 118 | 'name' => 'refModel', 119 | ] 120 | ], 'deepDto'); 121 | 122 | $model2 = $dataTransformer->toModel(UserModel::class, [ 123 | 'id' => 1, 124 | 'creAt' => new DateTime, 125 | 'name' => 'Alex', 126 | 'active' => 1, 127 | 'refModels' => [ // collection ref models 128 | [ 129 | 'id' => 2, 130 | 'name' => 'refModel', 131 | ], 132 | [ 133 | 'id' => 2, 134 | 'name' => 'refModel', 135 | ] 136 | ] 137 | ], 'deepDto'); 138 | ``` 139 | 140 | ### Логика в pipe обработчиках 141 | 142 | Обработчики pipe позволяют описывать callable методы и писать любую логику, которая будет применяться к значению. В pipe обработчиках можно кастить типы. Либо шифровать поля перед записью в БД. В случае необходимости, чтобы вся логика маппинга была в 1 месте, вы может прокинуть любые зависимости через замыкание в функцию pipe, достав их из контейнера `$this->getContainer()`. 143 | 144 | ```php 145 | getContainer()->get('encrypter'); 153 | 154 | return [ 155 | 'id' => [], 156 | 'creAt' => [], 157 | 'name' => [], 158 | 'password' => [ 159 | 'pipe-populate' => [ 160 | 'strtolower', 161 | function(string $openPassword) use($encrypter) { 162 | return $encrypter->encrypt($openPassword); 163 | }, 164 | ], 165 | 'pipe-extract' => [ 166 | function(string $ePassword) use($encrypter) { 167 | return $encrypter->decrypt($ePassword); 168 | }, 169 | 'strtolower' 170 | ], 171 | ] 172 | ]; 173 | ``` 174 | 175 | ### migration 176 | 177 | [update 5 to 6](https://github.com/alexpts/php-data-transformer2/blob/master/docs/migrate5to6.md) 178 | -------------------------------------------------------------------------------- /benchmark/ChildModel.php: -------------------------------------------------------------------------------- 1 | creAt = new DateTime; 19 | } 20 | 21 | public function __toString(): string 22 | { 23 | return (string)$this->id; 24 | } 25 | 26 | public function getEmail(): string 27 | { 28 | return $this->email; 29 | } 30 | 31 | public function setEmail(string $email): void 32 | { 33 | $this->email = $email; 34 | } 35 | 36 | /** @var string */ 37 | protected $email; 38 | 39 | public function getId() 40 | { 41 | return $this->id; 42 | } 43 | 44 | public function setId($id): void 45 | { 46 | $this->id = $id; 47 | } 48 | 49 | public function getName(): ?string 50 | { 51 | return $this->name; 52 | } 53 | 54 | public function setName(string $name): void 55 | { 56 | $this->name = $name; 57 | } 58 | 59 | public function getLogin(): ?string 60 | { 61 | return $this->login; 62 | } 63 | 64 | public function setLogin(string $login): void 65 | { 66 | $this->login = $login; 67 | } 68 | 69 | public function getCreAt(): DateTime 70 | { 71 | return $this->creAt; 72 | } 73 | 74 | public function setCreAt(DateTime $creAt): void 75 | { 76 | $this->creAt = $creAt; 77 | } 78 | 79 | public function isActive(): bool 80 | { 81 | return $this->active; 82 | } 83 | 84 | public function setActive(bool $active): void 85 | { 86 | $this->active = $active; 87 | } 88 | 89 | public function getCreAtTimestamp(): int 90 | { 91 | return $this->creAt->getTimestamp(); 92 | } 93 | 94 | public function getTitleName(string $title): string 95 | { 96 | return $title . ' ' . $this->name; 97 | } 98 | 99 | public function setTitleName(string $name, string $suffix): void 100 | { 101 | $this->name = $name . ' ' . $suffix; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /benchmark/UserModel.php: -------------------------------------------------------------------------------- 1 | creAt = new DateTime; 21 | } 22 | 23 | public function __toString(): string 24 | { 25 | return (string)$this->id; 26 | } 27 | 28 | public function getEmail(): string 29 | { 30 | return $this->email; 31 | } 32 | 33 | public function setEmail(string $email): void 34 | { 35 | $this->email = $email; 36 | } 37 | 38 | /** @var string */ 39 | protected $email; 40 | 41 | public function getId() 42 | { 43 | return $this->id; 44 | } 45 | 46 | public function setId($id): void 47 | { 48 | $this->id = $id; 49 | } 50 | 51 | public function getName(): ?string 52 | { 53 | return $this->name; 54 | } 55 | 56 | public function setName(string $name): void 57 | { 58 | $this->name = $name; 59 | } 60 | 61 | public function getLogin(): ?string 62 | { 63 | return $this->login; 64 | } 65 | 66 | public function setLogin(string $login): void 67 | { 68 | $this->login = $login; 69 | } 70 | 71 | public function getCreAt(): DateTime 72 | { 73 | return $this->creAt; 74 | } 75 | 76 | public function setCreAt(DateTime $creAt): void 77 | { 78 | $this->creAt = $creAt; 79 | } 80 | 81 | public function isActive(): bool 82 | { 83 | return $this->active; 84 | } 85 | 86 | public function setActive(bool $active): void 87 | { 88 | $this->active = $active; 89 | } 90 | 91 | public function getCreAtTimestamp(): int 92 | { 93 | return $this->creAt->getTimestamp(); 94 | } 95 | 96 | public function getTitleName(string $title): string 97 | { 98 | return $title . ' ' . $this->name; 99 | } 100 | 101 | public function setTitleName(string $name, string $suffix): void 102 | { 103 | $this->name = $name . ' ' . $suffix; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /benchmark/bechmark-collections.php: -------------------------------------------------------------------------------- 1 | getMapsManager()->setMapDir(UserModel::class, __DIR__ . '/maps/' . UserModel::class); 19 | $service->getMapsManager()->setMapDir(ChildModel::class, __DIR__ . '/maps/' . ChildModel::class); 20 | 21 | $collectionDto = []; 22 | while ($iterations--) { 23 | $collectionDto[] = [ 24 | 'id' => $faker->randomDigit, 25 | 'creAt' => $faker->unixTime(), 26 | 'name' => $faker->name(), 27 | 'login' => $faker->name(), 28 | 'active' => $faker->numberBetween(0, 2), 29 | 'email' => $faker->email, 30 | 'child' => [ 31 | 'id' => $faker->randomDigit, 32 | 'creAt' => time(), 33 | 'name' => $faker->unixTime(), 34 | 'login' => $faker->name, 35 | 'active' => $faker->boolean, 36 | 'email' => $faker->email, 37 | ] 38 | ]; 39 | } 40 | 41 | if ($blackfire) { 42 | $client = new Client; 43 | $probe = $client->createProbe(new Configuration); 44 | } 45 | $startTime = microtime(true); 46 | 47 | $models = $service->toModelsCollection(UserModel::class, $collectionDto); 48 | $collectionDto = $service->toDtoCollection($models); 49 | 50 | $diff = (microtime(true) - $startTime) * 1000; 51 | echo PHP_EOL . 'transformer: ' . sprintf('%2.3f ms', $diff); 52 | echo PHP_EOL . memory_get_peak_usage()/1024; 53 | 54 | if ($blackfire) { 55 | $client->endProbe($probe); 56 | } 57 | -------------------------------------------------------------------------------- /benchmark/bechmark.php: -------------------------------------------------------------------------------- 1 | getMapsManager()->setDefaultMapDir(__DIR__ . '/maps/'); 19 | 20 | $collectionDto = []; 21 | while ($iterations--) { 22 | $collectionDto[] = [ 23 | 'id' => $faker->randomDigit, 24 | 'creAt' => $faker->unixTime(), 25 | 'name' => $faker->name, 26 | 'login' => $faker->name, 27 | 'active' => $faker->numberBetween(0, 2), 28 | 'email' => $faker->email, 29 | 'child' => [ 30 | 'id' => $faker->randomDigit, 31 | 'creAt' => time(), 32 | 'name' => $faker->unixTime(), 33 | 'login' => $faker->name, 34 | 'active' => $faker->boolean, 35 | 'email' => $faker->email, 36 | ] 37 | ]; 38 | } 39 | 40 | if ($blackfire) { 41 | $client = new Client; 42 | $probe = $client->createProbe(new Configuration); 43 | } 44 | $startTime = microtime(true); 45 | 46 | foreach ($collectionDto as $dto) { 47 | $model = $service->toModel(UserModel::class, $dto); 48 | $dto = $service->toDTO($model); 49 | } 50 | 51 | $diff = (microtime(true) - $startTime) * 1000; 52 | echo sprintf('%2.3f ms', $diff); 53 | echo "\n" . memory_get_peak_usage()/1024; 54 | 55 | if ($blackfire) { 56 | $client->endProbe($probe); 57 | } 58 | -------------------------------------------------------------------------------- /benchmark/maps/ChildModel/dto.php: -------------------------------------------------------------------------------- 1 | [], 6 | 'creAt' => [], 7 | 'name' => [], 8 | 'login' => [], 9 | 'active' => [], 10 | 'email' => [], 11 | ]; 12 | -------------------------------------------------------------------------------- /benchmark/maps/UserModel/dto.php: -------------------------------------------------------------------------------- 1 | [], 6 | 'creAt' => [], 7 | 'name' => [ 8 | 'get' => 'getName', 9 | 'set' => 'setName' 10 | ], 11 | 'login' => [], 12 | 'active' => [ 13 | 'pipe' => ['boolval'] 14 | ], 15 | 'email' => [ 16 | 'pipe' => [ 17 | [ 18 | 'populate' => 'strtolower', 19 | 'extract' => 'strtoupper' 20 | ] 21 | ] 22 | ], 23 | 'child' => [ 24 | 'ref' => [ 25 | 'model' => 'ChildModel', 26 | 'map' => 'dto' 27 | ] 28 | ] 29 | ]; 30 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alexpts/php-data-transformer2", 3 | "description": "Convert model to dto, convert dto to model", 4 | "homepage": "https://github.com/alexpts/php-data-transformer2", 5 | "license": "MIT", 6 | "type": "library", 7 | "keywords": [ 8 | "model", 9 | "converter", 10 | "transform", 11 | "dto", 12 | "data-mapper", 13 | "hydrator", 14 | "serializer" 15 | ], 16 | "authors": [ 17 | { 18 | "name": "Alexpts", 19 | "email": "alexpts3@gmail.com" 20 | } 21 | ], 22 | "config": { 23 | "optimize-autoloader": true 24 | }, 25 | "minimum-stability": "stable", 26 | "require": { 27 | "php": ">=8.1", 28 | "psr/container": "^2.0", 29 | "alexpts/php-hydrator": "^5.0" 30 | }, 31 | "require-dev": { 32 | "fzaninotto/faker": "dev-master", 33 | "phpunit/phpunit": "^9.5" 34 | }, 35 | "suggest": { 36 | "blackfire/php-sdk": "^1.30" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "PTS\\DataTransformer\\": "src" 41 | } 42 | }, 43 | "scripts": { 44 | "test": "vendor/bin/phpunit --config=test/phpunit.xml" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "8a353f4b31964b9b26e0d4ee15823002", 8 | "packages": [ 9 | { 10 | "name": "alexpts/php-hydrator", 11 | "version": "5.0.2", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/alexpts/php-hydrator.git", 15 | "reference": "8f5acaf151315ea8c5cc4fdcb6f715b35c50ef08" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/alexpts/php-hydrator/zipball/8f5acaf151315ea8c5cc4fdcb6f715b35c50ef08", 20 | "reference": "8f5acaf151315ea8c5cc4fdcb6f715b35c50ef08", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=8.1" 25 | }, 26 | "require-dev": { 27 | "fzaninotto/faker": "dev-master", 28 | "phpunit/phpunit": "^9.5" 29 | }, 30 | "suggest": { 31 | "blackfire/php-sdk": "^1.30", 32 | "ext-blackfire": "*" 33 | }, 34 | "type": "library", 35 | "autoload": { 36 | "psr-4": { 37 | "PTS\\Hydrator\\": "src" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "Alexpts", 47 | "email": "alexpts3@gmail.com" 48 | } 49 | ], 50 | "description": "Convert model to dto, convert dto to model", 51 | "homepage": "https://github.com/alexpts/php-hydrator", 52 | "keywords": [ 53 | "converter", 54 | "data", 55 | "dto", 56 | "mapper", 57 | "model", 58 | "transform" 59 | ], 60 | "support": { 61 | "issues": "https://github.com/alexpts/php-hydrator/issues", 62 | "source": "https://github.com/alexpts/php-hydrator/tree/5.0.2" 63 | }, 64 | "time": "2023-01-05T11:02:18+00:00" 65 | }, 66 | { 67 | "name": "psr/container", 68 | "version": "2.0.2", 69 | "source": { 70 | "type": "git", 71 | "url": "https://github.com/php-fig/container.git", 72 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 73 | }, 74 | "dist": { 75 | "type": "zip", 76 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 77 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 78 | "shasum": "" 79 | }, 80 | "require": { 81 | "php": ">=7.4.0" 82 | }, 83 | "type": "library", 84 | "extra": { 85 | "branch-alias": { 86 | "dev-master": "2.0.x-dev" 87 | } 88 | }, 89 | "autoload": { 90 | "psr-4": { 91 | "Psr\\Container\\": "src/" 92 | } 93 | }, 94 | "notification-url": "https://packagist.org/downloads/", 95 | "license": [ 96 | "MIT" 97 | ], 98 | "authors": [ 99 | { 100 | "name": "PHP-FIG", 101 | "homepage": "https://www.php-fig.org/" 102 | } 103 | ], 104 | "description": "Common Container Interface (PHP FIG PSR-11)", 105 | "homepage": "https://github.com/php-fig/container", 106 | "keywords": [ 107 | "PSR-11", 108 | "container", 109 | "container-interface", 110 | "container-interop", 111 | "psr" 112 | ], 113 | "support": { 114 | "issues": "https://github.com/php-fig/container/issues", 115 | "source": "https://github.com/php-fig/container/tree/2.0.2" 116 | }, 117 | "time": "2021-11-05T16:47:00+00:00" 118 | } 119 | ], 120 | "packages-dev": [ 121 | { 122 | "name": "doctrine/instantiator", 123 | "version": "1.5.0", 124 | "source": { 125 | "type": "git", 126 | "url": "https://github.com/doctrine/instantiator.git", 127 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" 128 | }, 129 | "dist": { 130 | "type": "zip", 131 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", 132 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", 133 | "shasum": "" 134 | }, 135 | "require": { 136 | "php": "^7.1 || ^8.0" 137 | }, 138 | "require-dev": { 139 | "doctrine/coding-standard": "^9 || ^11", 140 | "ext-pdo": "*", 141 | "ext-phar": "*", 142 | "phpbench/phpbench": "^0.16 || ^1", 143 | "phpstan/phpstan": "^1.4", 144 | "phpstan/phpstan-phpunit": "^1", 145 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 146 | "vimeo/psalm": "^4.30 || ^5.4" 147 | }, 148 | "type": "library", 149 | "autoload": { 150 | "psr-4": { 151 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 152 | } 153 | }, 154 | "notification-url": "https://packagist.org/downloads/", 155 | "license": [ 156 | "MIT" 157 | ], 158 | "authors": [ 159 | { 160 | "name": "Marco Pivetta", 161 | "email": "ocramius@gmail.com", 162 | "homepage": "https://ocramius.github.io/" 163 | } 164 | ], 165 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 166 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 167 | "keywords": [ 168 | "constructor", 169 | "instantiate" 170 | ], 171 | "support": { 172 | "issues": "https://github.com/doctrine/instantiator/issues", 173 | "source": "https://github.com/doctrine/instantiator/tree/1.5.0" 174 | }, 175 | "funding": [ 176 | { 177 | "url": "https://www.doctrine-project.org/sponsorship.html", 178 | "type": "custom" 179 | }, 180 | { 181 | "url": "https://www.patreon.com/phpdoctrine", 182 | "type": "patreon" 183 | }, 184 | { 185 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 186 | "type": "tidelift" 187 | } 188 | ], 189 | "time": "2022-12-30T00:15:36+00:00" 190 | }, 191 | { 192 | "name": "fzaninotto/faker", 193 | "version": "dev-master", 194 | "source": { 195 | "type": "git", 196 | "url": "https://github.com/fzaninotto/Faker.git", 197 | "reference": "5ffe7db6c80f441f150fc88008d64e64af66634b" 198 | }, 199 | "dist": { 200 | "type": "zip", 201 | "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/5ffe7db6c80f441f150fc88008d64e64af66634b", 202 | "reference": "5ffe7db6c80f441f150fc88008d64e64af66634b", 203 | "shasum": "" 204 | }, 205 | "require": { 206 | "php": "^5.3.3 || ^7.0 || ^8.0" 207 | }, 208 | "require-dev": { 209 | "ext-intl": "*", 210 | "phpunit/phpunit": "^4.8.35 || ^5.7", 211 | "squizlabs/php_codesniffer": "^2.9.2" 212 | }, 213 | "default-branch": true, 214 | "type": "library", 215 | "extra": { 216 | "branch-alias": { 217 | "dev-master": "1.9-dev" 218 | } 219 | }, 220 | "autoload": { 221 | "psr-4": { 222 | "Faker\\": "src/Faker/" 223 | } 224 | }, 225 | "notification-url": "https://packagist.org/downloads/", 226 | "license": [ 227 | "MIT" 228 | ], 229 | "authors": [ 230 | { 231 | "name": "François Zaninotto" 232 | } 233 | ], 234 | "description": "Faker is a PHP library that generates fake data for you.", 235 | "keywords": [ 236 | "data", 237 | "faker", 238 | "fixtures" 239 | ], 240 | "support": { 241 | "issues": "https://github.com/fzaninotto/Faker/issues", 242 | "source": "https://github.com/fzaninotto/Faker/tree/master" 243 | }, 244 | "abandoned": true, 245 | "time": "2020-12-11T09:59:14+00:00" 246 | }, 247 | { 248 | "name": "myclabs/deep-copy", 249 | "version": "1.11.0", 250 | "source": { 251 | "type": "git", 252 | "url": "https://github.com/myclabs/DeepCopy.git", 253 | "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" 254 | }, 255 | "dist": { 256 | "type": "zip", 257 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", 258 | "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", 259 | "shasum": "" 260 | }, 261 | "require": { 262 | "php": "^7.1 || ^8.0" 263 | }, 264 | "conflict": { 265 | "doctrine/collections": "<1.6.8", 266 | "doctrine/common": "<2.13.3 || >=3,<3.2.2" 267 | }, 268 | "require-dev": { 269 | "doctrine/collections": "^1.6.8", 270 | "doctrine/common": "^2.13.3 || ^3.2.2", 271 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 272 | }, 273 | "type": "library", 274 | "autoload": { 275 | "files": [ 276 | "src/DeepCopy/deep_copy.php" 277 | ], 278 | "psr-4": { 279 | "DeepCopy\\": "src/DeepCopy/" 280 | } 281 | }, 282 | "notification-url": "https://packagist.org/downloads/", 283 | "license": [ 284 | "MIT" 285 | ], 286 | "description": "Create deep copies (clones) of your objects", 287 | "keywords": [ 288 | "clone", 289 | "copy", 290 | "duplicate", 291 | "object", 292 | "object graph" 293 | ], 294 | "support": { 295 | "issues": "https://github.com/myclabs/DeepCopy/issues", 296 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" 297 | }, 298 | "funding": [ 299 | { 300 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 301 | "type": "tidelift" 302 | } 303 | ], 304 | "time": "2022-03-03T13:19:32+00:00" 305 | }, 306 | { 307 | "name": "nikic/php-parser", 308 | "version": "v4.15.2", 309 | "source": { 310 | "type": "git", 311 | "url": "https://github.com/nikic/PHP-Parser.git", 312 | "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" 313 | }, 314 | "dist": { 315 | "type": "zip", 316 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", 317 | "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", 318 | "shasum": "" 319 | }, 320 | "require": { 321 | "ext-tokenizer": "*", 322 | "php": ">=7.0" 323 | }, 324 | "require-dev": { 325 | "ircmaxell/php-yacc": "^0.0.7", 326 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" 327 | }, 328 | "bin": [ 329 | "bin/php-parse" 330 | ], 331 | "type": "library", 332 | "extra": { 333 | "branch-alias": { 334 | "dev-master": "4.9-dev" 335 | } 336 | }, 337 | "autoload": { 338 | "psr-4": { 339 | "PhpParser\\": "lib/PhpParser" 340 | } 341 | }, 342 | "notification-url": "https://packagist.org/downloads/", 343 | "license": [ 344 | "BSD-3-Clause" 345 | ], 346 | "authors": [ 347 | { 348 | "name": "Nikita Popov" 349 | } 350 | ], 351 | "description": "A PHP parser written in PHP", 352 | "keywords": [ 353 | "parser", 354 | "php" 355 | ], 356 | "support": { 357 | "issues": "https://github.com/nikic/PHP-Parser/issues", 358 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" 359 | }, 360 | "time": "2022-11-12T15:38:23+00:00" 361 | }, 362 | { 363 | "name": "phar-io/manifest", 364 | "version": "2.0.3", 365 | "source": { 366 | "type": "git", 367 | "url": "https://github.com/phar-io/manifest.git", 368 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53" 369 | }, 370 | "dist": { 371 | "type": "zip", 372 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", 373 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53", 374 | "shasum": "" 375 | }, 376 | "require": { 377 | "ext-dom": "*", 378 | "ext-phar": "*", 379 | "ext-xmlwriter": "*", 380 | "phar-io/version": "^3.0.1", 381 | "php": "^7.2 || ^8.0" 382 | }, 383 | "type": "library", 384 | "extra": { 385 | "branch-alias": { 386 | "dev-master": "2.0.x-dev" 387 | } 388 | }, 389 | "autoload": { 390 | "classmap": [ 391 | "src/" 392 | ] 393 | }, 394 | "notification-url": "https://packagist.org/downloads/", 395 | "license": [ 396 | "BSD-3-Clause" 397 | ], 398 | "authors": [ 399 | { 400 | "name": "Arne Blankerts", 401 | "email": "arne@blankerts.de", 402 | "role": "Developer" 403 | }, 404 | { 405 | "name": "Sebastian Heuer", 406 | "email": "sebastian@phpeople.de", 407 | "role": "Developer" 408 | }, 409 | { 410 | "name": "Sebastian Bergmann", 411 | "email": "sebastian@phpunit.de", 412 | "role": "Developer" 413 | } 414 | ], 415 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 416 | "support": { 417 | "issues": "https://github.com/phar-io/manifest/issues", 418 | "source": "https://github.com/phar-io/manifest/tree/2.0.3" 419 | }, 420 | "time": "2021-07-20T11:28:43+00:00" 421 | }, 422 | { 423 | "name": "phar-io/version", 424 | "version": "3.2.1", 425 | "source": { 426 | "type": "git", 427 | "url": "https://github.com/phar-io/version.git", 428 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 429 | }, 430 | "dist": { 431 | "type": "zip", 432 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 433 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 434 | "shasum": "" 435 | }, 436 | "require": { 437 | "php": "^7.2 || ^8.0" 438 | }, 439 | "type": "library", 440 | "autoload": { 441 | "classmap": [ 442 | "src/" 443 | ] 444 | }, 445 | "notification-url": "https://packagist.org/downloads/", 446 | "license": [ 447 | "BSD-3-Clause" 448 | ], 449 | "authors": [ 450 | { 451 | "name": "Arne Blankerts", 452 | "email": "arne@blankerts.de", 453 | "role": "Developer" 454 | }, 455 | { 456 | "name": "Sebastian Heuer", 457 | "email": "sebastian@phpeople.de", 458 | "role": "Developer" 459 | }, 460 | { 461 | "name": "Sebastian Bergmann", 462 | "email": "sebastian@phpunit.de", 463 | "role": "Developer" 464 | } 465 | ], 466 | "description": "Library for handling version information and constraints", 467 | "support": { 468 | "issues": "https://github.com/phar-io/version/issues", 469 | "source": "https://github.com/phar-io/version/tree/3.2.1" 470 | }, 471 | "time": "2022-02-21T01:04:05+00:00" 472 | }, 473 | { 474 | "name": "phpunit/php-code-coverage", 475 | "version": "9.2.23", 476 | "source": { 477 | "type": "git", 478 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 479 | "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c" 480 | }, 481 | "dist": { 482 | "type": "zip", 483 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", 484 | "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", 485 | "shasum": "" 486 | }, 487 | "require": { 488 | "ext-dom": "*", 489 | "ext-libxml": "*", 490 | "ext-xmlwriter": "*", 491 | "nikic/php-parser": "^4.14", 492 | "php": ">=7.3", 493 | "phpunit/php-file-iterator": "^3.0.3", 494 | "phpunit/php-text-template": "^2.0.2", 495 | "sebastian/code-unit-reverse-lookup": "^2.0.2", 496 | "sebastian/complexity": "^2.0", 497 | "sebastian/environment": "^5.1.2", 498 | "sebastian/lines-of-code": "^1.0.3", 499 | "sebastian/version": "^3.0.1", 500 | "theseer/tokenizer": "^1.2.0" 501 | }, 502 | "require-dev": { 503 | "phpunit/phpunit": "^9.3" 504 | }, 505 | "suggest": { 506 | "ext-pcov": "*", 507 | "ext-xdebug": "*" 508 | }, 509 | "type": "library", 510 | "extra": { 511 | "branch-alias": { 512 | "dev-master": "9.2-dev" 513 | } 514 | }, 515 | "autoload": { 516 | "classmap": [ 517 | "src/" 518 | ] 519 | }, 520 | "notification-url": "https://packagist.org/downloads/", 521 | "license": [ 522 | "BSD-3-Clause" 523 | ], 524 | "authors": [ 525 | { 526 | "name": "Sebastian Bergmann", 527 | "email": "sebastian@phpunit.de", 528 | "role": "lead" 529 | } 530 | ], 531 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 532 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 533 | "keywords": [ 534 | "coverage", 535 | "testing", 536 | "xunit" 537 | ], 538 | "support": { 539 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 540 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23" 541 | }, 542 | "funding": [ 543 | { 544 | "url": "https://github.com/sebastianbergmann", 545 | "type": "github" 546 | } 547 | ], 548 | "time": "2022-12-28T12:41:10+00:00" 549 | }, 550 | { 551 | "name": "phpunit/php-file-iterator", 552 | "version": "3.0.6", 553 | "source": { 554 | "type": "git", 555 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 556 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 557 | }, 558 | "dist": { 559 | "type": "zip", 560 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 561 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 562 | "shasum": "" 563 | }, 564 | "require": { 565 | "php": ">=7.3" 566 | }, 567 | "require-dev": { 568 | "phpunit/phpunit": "^9.3" 569 | }, 570 | "type": "library", 571 | "extra": { 572 | "branch-alias": { 573 | "dev-master": "3.0-dev" 574 | } 575 | }, 576 | "autoload": { 577 | "classmap": [ 578 | "src/" 579 | ] 580 | }, 581 | "notification-url": "https://packagist.org/downloads/", 582 | "license": [ 583 | "BSD-3-Clause" 584 | ], 585 | "authors": [ 586 | { 587 | "name": "Sebastian Bergmann", 588 | "email": "sebastian@phpunit.de", 589 | "role": "lead" 590 | } 591 | ], 592 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 593 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 594 | "keywords": [ 595 | "filesystem", 596 | "iterator" 597 | ], 598 | "support": { 599 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 600 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 601 | }, 602 | "funding": [ 603 | { 604 | "url": "https://github.com/sebastianbergmann", 605 | "type": "github" 606 | } 607 | ], 608 | "time": "2021-12-02T12:48:52+00:00" 609 | }, 610 | { 611 | "name": "phpunit/php-invoker", 612 | "version": "3.1.1", 613 | "source": { 614 | "type": "git", 615 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 616 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 617 | }, 618 | "dist": { 619 | "type": "zip", 620 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 621 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 622 | "shasum": "" 623 | }, 624 | "require": { 625 | "php": ">=7.3" 626 | }, 627 | "require-dev": { 628 | "ext-pcntl": "*", 629 | "phpunit/phpunit": "^9.3" 630 | }, 631 | "suggest": { 632 | "ext-pcntl": "*" 633 | }, 634 | "type": "library", 635 | "extra": { 636 | "branch-alias": { 637 | "dev-master": "3.1-dev" 638 | } 639 | }, 640 | "autoload": { 641 | "classmap": [ 642 | "src/" 643 | ] 644 | }, 645 | "notification-url": "https://packagist.org/downloads/", 646 | "license": [ 647 | "BSD-3-Clause" 648 | ], 649 | "authors": [ 650 | { 651 | "name": "Sebastian Bergmann", 652 | "email": "sebastian@phpunit.de", 653 | "role": "lead" 654 | } 655 | ], 656 | "description": "Invoke callables with a timeout", 657 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 658 | "keywords": [ 659 | "process" 660 | ], 661 | "support": { 662 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 663 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 664 | }, 665 | "funding": [ 666 | { 667 | "url": "https://github.com/sebastianbergmann", 668 | "type": "github" 669 | } 670 | ], 671 | "time": "2020-09-28T05:58:55+00:00" 672 | }, 673 | { 674 | "name": "phpunit/php-text-template", 675 | "version": "2.0.4", 676 | "source": { 677 | "type": "git", 678 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 679 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 680 | }, 681 | "dist": { 682 | "type": "zip", 683 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 684 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 685 | "shasum": "" 686 | }, 687 | "require": { 688 | "php": ">=7.3" 689 | }, 690 | "require-dev": { 691 | "phpunit/phpunit": "^9.3" 692 | }, 693 | "type": "library", 694 | "extra": { 695 | "branch-alias": { 696 | "dev-master": "2.0-dev" 697 | } 698 | }, 699 | "autoload": { 700 | "classmap": [ 701 | "src/" 702 | ] 703 | }, 704 | "notification-url": "https://packagist.org/downloads/", 705 | "license": [ 706 | "BSD-3-Clause" 707 | ], 708 | "authors": [ 709 | { 710 | "name": "Sebastian Bergmann", 711 | "email": "sebastian@phpunit.de", 712 | "role": "lead" 713 | } 714 | ], 715 | "description": "Simple template engine.", 716 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 717 | "keywords": [ 718 | "template" 719 | ], 720 | "support": { 721 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 722 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 723 | }, 724 | "funding": [ 725 | { 726 | "url": "https://github.com/sebastianbergmann", 727 | "type": "github" 728 | } 729 | ], 730 | "time": "2020-10-26T05:33:50+00:00" 731 | }, 732 | { 733 | "name": "phpunit/php-timer", 734 | "version": "5.0.3", 735 | "source": { 736 | "type": "git", 737 | "url": "https://github.com/sebastianbergmann/php-timer.git", 738 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 739 | }, 740 | "dist": { 741 | "type": "zip", 742 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 743 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 744 | "shasum": "" 745 | }, 746 | "require": { 747 | "php": ">=7.3" 748 | }, 749 | "require-dev": { 750 | "phpunit/phpunit": "^9.3" 751 | }, 752 | "type": "library", 753 | "extra": { 754 | "branch-alias": { 755 | "dev-master": "5.0-dev" 756 | } 757 | }, 758 | "autoload": { 759 | "classmap": [ 760 | "src/" 761 | ] 762 | }, 763 | "notification-url": "https://packagist.org/downloads/", 764 | "license": [ 765 | "BSD-3-Clause" 766 | ], 767 | "authors": [ 768 | { 769 | "name": "Sebastian Bergmann", 770 | "email": "sebastian@phpunit.de", 771 | "role": "lead" 772 | } 773 | ], 774 | "description": "Utility class for timing", 775 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 776 | "keywords": [ 777 | "timer" 778 | ], 779 | "support": { 780 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 781 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 782 | }, 783 | "funding": [ 784 | { 785 | "url": "https://github.com/sebastianbergmann", 786 | "type": "github" 787 | } 788 | ], 789 | "time": "2020-10-26T13:16:10+00:00" 790 | }, 791 | { 792 | "name": "phpunit/phpunit", 793 | "version": "9.5.27", 794 | "source": { 795 | "type": "git", 796 | "url": "https://github.com/sebastianbergmann/phpunit.git", 797 | "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38" 798 | }, 799 | "dist": { 800 | "type": "zip", 801 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38", 802 | "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38", 803 | "shasum": "" 804 | }, 805 | "require": { 806 | "doctrine/instantiator": "^1.3.1", 807 | "ext-dom": "*", 808 | "ext-json": "*", 809 | "ext-libxml": "*", 810 | "ext-mbstring": "*", 811 | "ext-xml": "*", 812 | "ext-xmlwriter": "*", 813 | "myclabs/deep-copy": "^1.10.1", 814 | "phar-io/manifest": "^2.0.3", 815 | "phar-io/version": "^3.0.2", 816 | "php": ">=7.3", 817 | "phpunit/php-code-coverage": "^9.2.13", 818 | "phpunit/php-file-iterator": "^3.0.5", 819 | "phpunit/php-invoker": "^3.1.1", 820 | "phpunit/php-text-template": "^2.0.3", 821 | "phpunit/php-timer": "^5.0.2", 822 | "sebastian/cli-parser": "^1.0.1", 823 | "sebastian/code-unit": "^1.0.6", 824 | "sebastian/comparator": "^4.0.8", 825 | "sebastian/diff": "^4.0.3", 826 | "sebastian/environment": "^5.1.3", 827 | "sebastian/exporter": "^4.0.5", 828 | "sebastian/global-state": "^5.0.1", 829 | "sebastian/object-enumerator": "^4.0.3", 830 | "sebastian/resource-operations": "^3.0.3", 831 | "sebastian/type": "^3.2", 832 | "sebastian/version": "^3.0.2" 833 | }, 834 | "suggest": { 835 | "ext-soap": "*", 836 | "ext-xdebug": "*" 837 | }, 838 | "bin": [ 839 | "phpunit" 840 | ], 841 | "type": "library", 842 | "extra": { 843 | "branch-alias": { 844 | "dev-master": "9.5-dev" 845 | } 846 | }, 847 | "autoload": { 848 | "files": [ 849 | "src/Framework/Assert/Functions.php" 850 | ], 851 | "classmap": [ 852 | "src/" 853 | ] 854 | }, 855 | "notification-url": "https://packagist.org/downloads/", 856 | "license": [ 857 | "BSD-3-Clause" 858 | ], 859 | "authors": [ 860 | { 861 | "name": "Sebastian Bergmann", 862 | "email": "sebastian@phpunit.de", 863 | "role": "lead" 864 | } 865 | ], 866 | "description": "The PHP Unit Testing framework.", 867 | "homepage": "https://phpunit.de/", 868 | "keywords": [ 869 | "phpunit", 870 | "testing", 871 | "xunit" 872 | ], 873 | "support": { 874 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 875 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27" 876 | }, 877 | "funding": [ 878 | { 879 | "url": "https://phpunit.de/sponsors.html", 880 | "type": "custom" 881 | }, 882 | { 883 | "url": "https://github.com/sebastianbergmann", 884 | "type": "github" 885 | }, 886 | { 887 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 888 | "type": "tidelift" 889 | } 890 | ], 891 | "time": "2022-12-09T07:31:23+00:00" 892 | }, 893 | { 894 | "name": "sebastian/cli-parser", 895 | "version": "1.0.1", 896 | "source": { 897 | "type": "git", 898 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 899 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" 900 | }, 901 | "dist": { 902 | "type": "zip", 903 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", 904 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", 905 | "shasum": "" 906 | }, 907 | "require": { 908 | "php": ">=7.3" 909 | }, 910 | "require-dev": { 911 | "phpunit/phpunit": "^9.3" 912 | }, 913 | "type": "library", 914 | "extra": { 915 | "branch-alias": { 916 | "dev-master": "1.0-dev" 917 | } 918 | }, 919 | "autoload": { 920 | "classmap": [ 921 | "src/" 922 | ] 923 | }, 924 | "notification-url": "https://packagist.org/downloads/", 925 | "license": [ 926 | "BSD-3-Clause" 927 | ], 928 | "authors": [ 929 | { 930 | "name": "Sebastian Bergmann", 931 | "email": "sebastian@phpunit.de", 932 | "role": "lead" 933 | } 934 | ], 935 | "description": "Library for parsing CLI options", 936 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 937 | "support": { 938 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 939 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" 940 | }, 941 | "funding": [ 942 | { 943 | "url": "https://github.com/sebastianbergmann", 944 | "type": "github" 945 | } 946 | ], 947 | "time": "2020-09-28T06:08:49+00:00" 948 | }, 949 | { 950 | "name": "sebastian/code-unit", 951 | "version": "1.0.8", 952 | "source": { 953 | "type": "git", 954 | "url": "https://github.com/sebastianbergmann/code-unit.git", 955 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 956 | }, 957 | "dist": { 958 | "type": "zip", 959 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 960 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 961 | "shasum": "" 962 | }, 963 | "require": { 964 | "php": ">=7.3" 965 | }, 966 | "require-dev": { 967 | "phpunit/phpunit": "^9.3" 968 | }, 969 | "type": "library", 970 | "extra": { 971 | "branch-alias": { 972 | "dev-master": "1.0-dev" 973 | } 974 | }, 975 | "autoload": { 976 | "classmap": [ 977 | "src/" 978 | ] 979 | }, 980 | "notification-url": "https://packagist.org/downloads/", 981 | "license": [ 982 | "BSD-3-Clause" 983 | ], 984 | "authors": [ 985 | { 986 | "name": "Sebastian Bergmann", 987 | "email": "sebastian@phpunit.de", 988 | "role": "lead" 989 | } 990 | ], 991 | "description": "Collection of value objects that represent the PHP code units", 992 | "homepage": "https://github.com/sebastianbergmann/code-unit", 993 | "support": { 994 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 995 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 996 | }, 997 | "funding": [ 998 | { 999 | "url": "https://github.com/sebastianbergmann", 1000 | "type": "github" 1001 | } 1002 | ], 1003 | "time": "2020-10-26T13:08:54+00:00" 1004 | }, 1005 | { 1006 | "name": "sebastian/code-unit-reverse-lookup", 1007 | "version": "2.0.3", 1008 | "source": { 1009 | "type": "git", 1010 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1011 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 1012 | }, 1013 | "dist": { 1014 | "type": "zip", 1015 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 1016 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 1017 | "shasum": "" 1018 | }, 1019 | "require": { 1020 | "php": ">=7.3" 1021 | }, 1022 | "require-dev": { 1023 | "phpunit/phpunit": "^9.3" 1024 | }, 1025 | "type": "library", 1026 | "extra": { 1027 | "branch-alias": { 1028 | "dev-master": "2.0-dev" 1029 | } 1030 | }, 1031 | "autoload": { 1032 | "classmap": [ 1033 | "src/" 1034 | ] 1035 | }, 1036 | "notification-url": "https://packagist.org/downloads/", 1037 | "license": [ 1038 | "BSD-3-Clause" 1039 | ], 1040 | "authors": [ 1041 | { 1042 | "name": "Sebastian Bergmann", 1043 | "email": "sebastian@phpunit.de" 1044 | } 1045 | ], 1046 | "description": "Looks up which function or method a line of code belongs to", 1047 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1048 | "support": { 1049 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 1050 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 1051 | }, 1052 | "funding": [ 1053 | { 1054 | "url": "https://github.com/sebastianbergmann", 1055 | "type": "github" 1056 | } 1057 | ], 1058 | "time": "2020-09-28T05:30:19+00:00" 1059 | }, 1060 | { 1061 | "name": "sebastian/comparator", 1062 | "version": "4.0.8", 1063 | "source": { 1064 | "type": "git", 1065 | "url": "https://github.com/sebastianbergmann/comparator.git", 1066 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a" 1067 | }, 1068 | "dist": { 1069 | "type": "zip", 1070 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", 1071 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a", 1072 | "shasum": "" 1073 | }, 1074 | "require": { 1075 | "php": ">=7.3", 1076 | "sebastian/diff": "^4.0", 1077 | "sebastian/exporter": "^4.0" 1078 | }, 1079 | "require-dev": { 1080 | "phpunit/phpunit": "^9.3" 1081 | }, 1082 | "type": "library", 1083 | "extra": { 1084 | "branch-alias": { 1085 | "dev-master": "4.0-dev" 1086 | } 1087 | }, 1088 | "autoload": { 1089 | "classmap": [ 1090 | "src/" 1091 | ] 1092 | }, 1093 | "notification-url": "https://packagist.org/downloads/", 1094 | "license": [ 1095 | "BSD-3-Clause" 1096 | ], 1097 | "authors": [ 1098 | { 1099 | "name": "Sebastian Bergmann", 1100 | "email": "sebastian@phpunit.de" 1101 | }, 1102 | { 1103 | "name": "Jeff Welch", 1104 | "email": "whatthejeff@gmail.com" 1105 | }, 1106 | { 1107 | "name": "Volker Dusch", 1108 | "email": "github@wallbash.com" 1109 | }, 1110 | { 1111 | "name": "Bernhard Schussek", 1112 | "email": "bschussek@2bepublished.at" 1113 | } 1114 | ], 1115 | "description": "Provides the functionality to compare PHP values for equality", 1116 | "homepage": "https://github.com/sebastianbergmann/comparator", 1117 | "keywords": [ 1118 | "comparator", 1119 | "compare", 1120 | "equality" 1121 | ], 1122 | "support": { 1123 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 1124 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" 1125 | }, 1126 | "funding": [ 1127 | { 1128 | "url": "https://github.com/sebastianbergmann", 1129 | "type": "github" 1130 | } 1131 | ], 1132 | "time": "2022-09-14T12:41:17+00:00" 1133 | }, 1134 | { 1135 | "name": "sebastian/complexity", 1136 | "version": "2.0.2", 1137 | "source": { 1138 | "type": "git", 1139 | "url": "https://github.com/sebastianbergmann/complexity.git", 1140 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" 1141 | }, 1142 | "dist": { 1143 | "type": "zip", 1144 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", 1145 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", 1146 | "shasum": "" 1147 | }, 1148 | "require": { 1149 | "nikic/php-parser": "^4.7", 1150 | "php": ">=7.3" 1151 | }, 1152 | "require-dev": { 1153 | "phpunit/phpunit": "^9.3" 1154 | }, 1155 | "type": "library", 1156 | "extra": { 1157 | "branch-alias": { 1158 | "dev-master": "2.0-dev" 1159 | } 1160 | }, 1161 | "autoload": { 1162 | "classmap": [ 1163 | "src/" 1164 | ] 1165 | }, 1166 | "notification-url": "https://packagist.org/downloads/", 1167 | "license": [ 1168 | "BSD-3-Clause" 1169 | ], 1170 | "authors": [ 1171 | { 1172 | "name": "Sebastian Bergmann", 1173 | "email": "sebastian@phpunit.de", 1174 | "role": "lead" 1175 | } 1176 | ], 1177 | "description": "Library for calculating the complexity of PHP code units", 1178 | "homepage": "https://github.com/sebastianbergmann/complexity", 1179 | "support": { 1180 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 1181 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" 1182 | }, 1183 | "funding": [ 1184 | { 1185 | "url": "https://github.com/sebastianbergmann", 1186 | "type": "github" 1187 | } 1188 | ], 1189 | "time": "2020-10-26T15:52:27+00:00" 1190 | }, 1191 | { 1192 | "name": "sebastian/diff", 1193 | "version": "4.0.4", 1194 | "source": { 1195 | "type": "git", 1196 | "url": "https://github.com/sebastianbergmann/diff.git", 1197 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" 1198 | }, 1199 | "dist": { 1200 | "type": "zip", 1201 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", 1202 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", 1203 | "shasum": "" 1204 | }, 1205 | "require": { 1206 | "php": ">=7.3" 1207 | }, 1208 | "require-dev": { 1209 | "phpunit/phpunit": "^9.3", 1210 | "symfony/process": "^4.2 || ^5" 1211 | }, 1212 | "type": "library", 1213 | "extra": { 1214 | "branch-alias": { 1215 | "dev-master": "4.0-dev" 1216 | } 1217 | }, 1218 | "autoload": { 1219 | "classmap": [ 1220 | "src/" 1221 | ] 1222 | }, 1223 | "notification-url": "https://packagist.org/downloads/", 1224 | "license": [ 1225 | "BSD-3-Clause" 1226 | ], 1227 | "authors": [ 1228 | { 1229 | "name": "Sebastian Bergmann", 1230 | "email": "sebastian@phpunit.de" 1231 | }, 1232 | { 1233 | "name": "Kore Nordmann", 1234 | "email": "mail@kore-nordmann.de" 1235 | } 1236 | ], 1237 | "description": "Diff implementation", 1238 | "homepage": "https://github.com/sebastianbergmann/diff", 1239 | "keywords": [ 1240 | "diff", 1241 | "udiff", 1242 | "unidiff", 1243 | "unified diff" 1244 | ], 1245 | "support": { 1246 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1247 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" 1248 | }, 1249 | "funding": [ 1250 | { 1251 | "url": "https://github.com/sebastianbergmann", 1252 | "type": "github" 1253 | } 1254 | ], 1255 | "time": "2020-10-26T13:10:38+00:00" 1256 | }, 1257 | { 1258 | "name": "sebastian/environment", 1259 | "version": "5.1.4", 1260 | "source": { 1261 | "type": "git", 1262 | "url": "https://github.com/sebastianbergmann/environment.git", 1263 | "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" 1264 | }, 1265 | "dist": { 1266 | "type": "zip", 1267 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", 1268 | "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", 1269 | "shasum": "" 1270 | }, 1271 | "require": { 1272 | "php": ">=7.3" 1273 | }, 1274 | "require-dev": { 1275 | "phpunit/phpunit": "^9.3" 1276 | }, 1277 | "suggest": { 1278 | "ext-posix": "*" 1279 | }, 1280 | "type": "library", 1281 | "extra": { 1282 | "branch-alias": { 1283 | "dev-master": "5.1-dev" 1284 | } 1285 | }, 1286 | "autoload": { 1287 | "classmap": [ 1288 | "src/" 1289 | ] 1290 | }, 1291 | "notification-url": "https://packagist.org/downloads/", 1292 | "license": [ 1293 | "BSD-3-Clause" 1294 | ], 1295 | "authors": [ 1296 | { 1297 | "name": "Sebastian Bergmann", 1298 | "email": "sebastian@phpunit.de" 1299 | } 1300 | ], 1301 | "description": "Provides functionality to handle HHVM/PHP environments", 1302 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1303 | "keywords": [ 1304 | "Xdebug", 1305 | "environment", 1306 | "hhvm" 1307 | ], 1308 | "support": { 1309 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1310 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" 1311 | }, 1312 | "funding": [ 1313 | { 1314 | "url": "https://github.com/sebastianbergmann", 1315 | "type": "github" 1316 | } 1317 | ], 1318 | "time": "2022-04-03T09:37:03+00:00" 1319 | }, 1320 | { 1321 | "name": "sebastian/exporter", 1322 | "version": "4.0.5", 1323 | "source": { 1324 | "type": "git", 1325 | "url": "https://github.com/sebastianbergmann/exporter.git", 1326 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" 1327 | }, 1328 | "dist": { 1329 | "type": "zip", 1330 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 1331 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 1332 | "shasum": "" 1333 | }, 1334 | "require": { 1335 | "php": ">=7.3", 1336 | "sebastian/recursion-context": "^4.0" 1337 | }, 1338 | "require-dev": { 1339 | "ext-mbstring": "*", 1340 | "phpunit/phpunit": "^9.3" 1341 | }, 1342 | "type": "library", 1343 | "extra": { 1344 | "branch-alias": { 1345 | "dev-master": "4.0-dev" 1346 | } 1347 | }, 1348 | "autoload": { 1349 | "classmap": [ 1350 | "src/" 1351 | ] 1352 | }, 1353 | "notification-url": "https://packagist.org/downloads/", 1354 | "license": [ 1355 | "BSD-3-Clause" 1356 | ], 1357 | "authors": [ 1358 | { 1359 | "name": "Sebastian Bergmann", 1360 | "email": "sebastian@phpunit.de" 1361 | }, 1362 | { 1363 | "name": "Jeff Welch", 1364 | "email": "whatthejeff@gmail.com" 1365 | }, 1366 | { 1367 | "name": "Volker Dusch", 1368 | "email": "github@wallbash.com" 1369 | }, 1370 | { 1371 | "name": "Adam Harvey", 1372 | "email": "aharvey@php.net" 1373 | }, 1374 | { 1375 | "name": "Bernhard Schussek", 1376 | "email": "bschussek@gmail.com" 1377 | } 1378 | ], 1379 | "description": "Provides the functionality to export PHP variables for visualization", 1380 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1381 | "keywords": [ 1382 | "export", 1383 | "exporter" 1384 | ], 1385 | "support": { 1386 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1387 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" 1388 | }, 1389 | "funding": [ 1390 | { 1391 | "url": "https://github.com/sebastianbergmann", 1392 | "type": "github" 1393 | } 1394 | ], 1395 | "time": "2022-09-14T06:03:37+00:00" 1396 | }, 1397 | { 1398 | "name": "sebastian/global-state", 1399 | "version": "5.0.5", 1400 | "source": { 1401 | "type": "git", 1402 | "url": "https://github.com/sebastianbergmann/global-state.git", 1403 | "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" 1404 | }, 1405 | "dist": { 1406 | "type": "zip", 1407 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", 1408 | "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", 1409 | "shasum": "" 1410 | }, 1411 | "require": { 1412 | "php": ">=7.3", 1413 | "sebastian/object-reflector": "^2.0", 1414 | "sebastian/recursion-context": "^4.0" 1415 | }, 1416 | "require-dev": { 1417 | "ext-dom": "*", 1418 | "phpunit/phpunit": "^9.3" 1419 | }, 1420 | "suggest": { 1421 | "ext-uopz": "*" 1422 | }, 1423 | "type": "library", 1424 | "extra": { 1425 | "branch-alias": { 1426 | "dev-master": "5.0-dev" 1427 | } 1428 | }, 1429 | "autoload": { 1430 | "classmap": [ 1431 | "src/" 1432 | ] 1433 | }, 1434 | "notification-url": "https://packagist.org/downloads/", 1435 | "license": [ 1436 | "BSD-3-Clause" 1437 | ], 1438 | "authors": [ 1439 | { 1440 | "name": "Sebastian Bergmann", 1441 | "email": "sebastian@phpunit.de" 1442 | } 1443 | ], 1444 | "description": "Snapshotting of global state", 1445 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1446 | "keywords": [ 1447 | "global state" 1448 | ], 1449 | "support": { 1450 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1451 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" 1452 | }, 1453 | "funding": [ 1454 | { 1455 | "url": "https://github.com/sebastianbergmann", 1456 | "type": "github" 1457 | } 1458 | ], 1459 | "time": "2022-02-14T08:28:10+00:00" 1460 | }, 1461 | { 1462 | "name": "sebastian/lines-of-code", 1463 | "version": "1.0.3", 1464 | "source": { 1465 | "type": "git", 1466 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1467 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" 1468 | }, 1469 | "dist": { 1470 | "type": "zip", 1471 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", 1472 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", 1473 | "shasum": "" 1474 | }, 1475 | "require": { 1476 | "nikic/php-parser": "^4.6", 1477 | "php": ">=7.3" 1478 | }, 1479 | "require-dev": { 1480 | "phpunit/phpunit": "^9.3" 1481 | }, 1482 | "type": "library", 1483 | "extra": { 1484 | "branch-alias": { 1485 | "dev-master": "1.0-dev" 1486 | } 1487 | }, 1488 | "autoload": { 1489 | "classmap": [ 1490 | "src/" 1491 | ] 1492 | }, 1493 | "notification-url": "https://packagist.org/downloads/", 1494 | "license": [ 1495 | "BSD-3-Clause" 1496 | ], 1497 | "authors": [ 1498 | { 1499 | "name": "Sebastian Bergmann", 1500 | "email": "sebastian@phpunit.de", 1501 | "role": "lead" 1502 | } 1503 | ], 1504 | "description": "Library for counting the lines of code in PHP source code", 1505 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1506 | "support": { 1507 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1508 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" 1509 | }, 1510 | "funding": [ 1511 | { 1512 | "url": "https://github.com/sebastianbergmann", 1513 | "type": "github" 1514 | } 1515 | ], 1516 | "time": "2020-11-28T06:42:11+00:00" 1517 | }, 1518 | { 1519 | "name": "sebastian/object-enumerator", 1520 | "version": "4.0.4", 1521 | "source": { 1522 | "type": "git", 1523 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1524 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 1525 | }, 1526 | "dist": { 1527 | "type": "zip", 1528 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 1529 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 1530 | "shasum": "" 1531 | }, 1532 | "require": { 1533 | "php": ">=7.3", 1534 | "sebastian/object-reflector": "^2.0", 1535 | "sebastian/recursion-context": "^4.0" 1536 | }, 1537 | "require-dev": { 1538 | "phpunit/phpunit": "^9.3" 1539 | }, 1540 | "type": "library", 1541 | "extra": { 1542 | "branch-alias": { 1543 | "dev-master": "4.0-dev" 1544 | } 1545 | }, 1546 | "autoload": { 1547 | "classmap": [ 1548 | "src/" 1549 | ] 1550 | }, 1551 | "notification-url": "https://packagist.org/downloads/", 1552 | "license": [ 1553 | "BSD-3-Clause" 1554 | ], 1555 | "authors": [ 1556 | { 1557 | "name": "Sebastian Bergmann", 1558 | "email": "sebastian@phpunit.de" 1559 | } 1560 | ], 1561 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1562 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1563 | "support": { 1564 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1565 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 1566 | }, 1567 | "funding": [ 1568 | { 1569 | "url": "https://github.com/sebastianbergmann", 1570 | "type": "github" 1571 | } 1572 | ], 1573 | "time": "2020-10-26T13:12:34+00:00" 1574 | }, 1575 | { 1576 | "name": "sebastian/object-reflector", 1577 | "version": "2.0.4", 1578 | "source": { 1579 | "type": "git", 1580 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1581 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 1582 | }, 1583 | "dist": { 1584 | "type": "zip", 1585 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1586 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1587 | "shasum": "" 1588 | }, 1589 | "require": { 1590 | "php": ">=7.3" 1591 | }, 1592 | "require-dev": { 1593 | "phpunit/phpunit": "^9.3" 1594 | }, 1595 | "type": "library", 1596 | "extra": { 1597 | "branch-alias": { 1598 | "dev-master": "2.0-dev" 1599 | } 1600 | }, 1601 | "autoload": { 1602 | "classmap": [ 1603 | "src/" 1604 | ] 1605 | }, 1606 | "notification-url": "https://packagist.org/downloads/", 1607 | "license": [ 1608 | "BSD-3-Clause" 1609 | ], 1610 | "authors": [ 1611 | { 1612 | "name": "Sebastian Bergmann", 1613 | "email": "sebastian@phpunit.de" 1614 | } 1615 | ], 1616 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1617 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1618 | "support": { 1619 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 1620 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 1621 | }, 1622 | "funding": [ 1623 | { 1624 | "url": "https://github.com/sebastianbergmann", 1625 | "type": "github" 1626 | } 1627 | ], 1628 | "time": "2020-10-26T13:14:26+00:00" 1629 | }, 1630 | { 1631 | "name": "sebastian/recursion-context", 1632 | "version": "4.0.4", 1633 | "source": { 1634 | "type": "git", 1635 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1636 | "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" 1637 | }, 1638 | "dist": { 1639 | "type": "zip", 1640 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", 1641 | "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", 1642 | "shasum": "" 1643 | }, 1644 | "require": { 1645 | "php": ">=7.3" 1646 | }, 1647 | "require-dev": { 1648 | "phpunit/phpunit": "^9.3" 1649 | }, 1650 | "type": "library", 1651 | "extra": { 1652 | "branch-alias": { 1653 | "dev-master": "4.0-dev" 1654 | } 1655 | }, 1656 | "autoload": { 1657 | "classmap": [ 1658 | "src/" 1659 | ] 1660 | }, 1661 | "notification-url": "https://packagist.org/downloads/", 1662 | "license": [ 1663 | "BSD-3-Clause" 1664 | ], 1665 | "authors": [ 1666 | { 1667 | "name": "Sebastian Bergmann", 1668 | "email": "sebastian@phpunit.de" 1669 | }, 1670 | { 1671 | "name": "Jeff Welch", 1672 | "email": "whatthejeff@gmail.com" 1673 | }, 1674 | { 1675 | "name": "Adam Harvey", 1676 | "email": "aharvey@php.net" 1677 | } 1678 | ], 1679 | "description": "Provides functionality to recursively process PHP variables", 1680 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1681 | "support": { 1682 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 1683 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" 1684 | }, 1685 | "funding": [ 1686 | { 1687 | "url": "https://github.com/sebastianbergmann", 1688 | "type": "github" 1689 | } 1690 | ], 1691 | "time": "2020-10-26T13:17:30+00:00" 1692 | }, 1693 | { 1694 | "name": "sebastian/resource-operations", 1695 | "version": "3.0.3", 1696 | "source": { 1697 | "type": "git", 1698 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1699 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" 1700 | }, 1701 | "dist": { 1702 | "type": "zip", 1703 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 1704 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 1705 | "shasum": "" 1706 | }, 1707 | "require": { 1708 | "php": ">=7.3" 1709 | }, 1710 | "require-dev": { 1711 | "phpunit/phpunit": "^9.0" 1712 | }, 1713 | "type": "library", 1714 | "extra": { 1715 | "branch-alias": { 1716 | "dev-master": "3.0-dev" 1717 | } 1718 | }, 1719 | "autoload": { 1720 | "classmap": [ 1721 | "src/" 1722 | ] 1723 | }, 1724 | "notification-url": "https://packagist.org/downloads/", 1725 | "license": [ 1726 | "BSD-3-Clause" 1727 | ], 1728 | "authors": [ 1729 | { 1730 | "name": "Sebastian Bergmann", 1731 | "email": "sebastian@phpunit.de" 1732 | } 1733 | ], 1734 | "description": "Provides a list of PHP built-in functions that operate on resources", 1735 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1736 | "support": { 1737 | "issues": "https://github.com/sebastianbergmann/resource-operations/issues", 1738 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" 1739 | }, 1740 | "funding": [ 1741 | { 1742 | "url": "https://github.com/sebastianbergmann", 1743 | "type": "github" 1744 | } 1745 | ], 1746 | "time": "2020-09-28T06:45:17+00:00" 1747 | }, 1748 | { 1749 | "name": "sebastian/type", 1750 | "version": "3.2.0", 1751 | "source": { 1752 | "type": "git", 1753 | "url": "https://github.com/sebastianbergmann/type.git", 1754 | "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" 1755 | }, 1756 | "dist": { 1757 | "type": "zip", 1758 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", 1759 | "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", 1760 | "shasum": "" 1761 | }, 1762 | "require": { 1763 | "php": ">=7.3" 1764 | }, 1765 | "require-dev": { 1766 | "phpunit/phpunit": "^9.5" 1767 | }, 1768 | "type": "library", 1769 | "extra": { 1770 | "branch-alias": { 1771 | "dev-master": "3.2-dev" 1772 | } 1773 | }, 1774 | "autoload": { 1775 | "classmap": [ 1776 | "src/" 1777 | ] 1778 | }, 1779 | "notification-url": "https://packagist.org/downloads/", 1780 | "license": [ 1781 | "BSD-3-Clause" 1782 | ], 1783 | "authors": [ 1784 | { 1785 | "name": "Sebastian Bergmann", 1786 | "email": "sebastian@phpunit.de", 1787 | "role": "lead" 1788 | } 1789 | ], 1790 | "description": "Collection of value objects that represent the types of the PHP type system", 1791 | "homepage": "https://github.com/sebastianbergmann/type", 1792 | "support": { 1793 | "issues": "https://github.com/sebastianbergmann/type/issues", 1794 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" 1795 | }, 1796 | "funding": [ 1797 | { 1798 | "url": "https://github.com/sebastianbergmann", 1799 | "type": "github" 1800 | } 1801 | ], 1802 | "time": "2022-09-12T14:47:03+00:00" 1803 | }, 1804 | { 1805 | "name": "sebastian/version", 1806 | "version": "3.0.2", 1807 | "source": { 1808 | "type": "git", 1809 | "url": "https://github.com/sebastianbergmann/version.git", 1810 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 1811 | }, 1812 | "dist": { 1813 | "type": "zip", 1814 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 1815 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 1816 | "shasum": "" 1817 | }, 1818 | "require": { 1819 | "php": ">=7.3" 1820 | }, 1821 | "type": "library", 1822 | "extra": { 1823 | "branch-alias": { 1824 | "dev-master": "3.0-dev" 1825 | } 1826 | }, 1827 | "autoload": { 1828 | "classmap": [ 1829 | "src/" 1830 | ] 1831 | }, 1832 | "notification-url": "https://packagist.org/downloads/", 1833 | "license": [ 1834 | "BSD-3-Clause" 1835 | ], 1836 | "authors": [ 1837 | { 1838 | "name": "Sebastian Bergmann", 1839 | "email": "sebastian@phpunit.de", 1840 | "role": "lead" 1841 | } 1842 | ], 1843 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1844 | "homepage": "https://github.com/sebastianbergmann/version", 1845 | "support": { 1846 | "issues": "https://github.com/sebastianbergmann/version/issues", 1847 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 1848 | }, 1849 | "funding": [ 1850 | { 1851 | "url": "https://github.com/sebastianbergmann", 1852 | "type": "github" 1853 | } 1854 | ], 1855 | "time": "2020-09-28T06:39:44+00:00" 1856 | }, 1857 | { 1858 | "name": "theseer/tokenizer", 1859 | "version": "1.2.1", 1860 | "source": { 1861 | "type": "git", 1862 | "url": "https://github.com/theseer/tokenizer.git", 1863 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" 1864 | }, 1865 | "dist": { 1866 | "type": "zip", 1867 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", 1868 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", 1869 | "shasum": "" 1870 | }, 1871 | "require": { 1872 | "ext-dom": "*", 1873 | "ext-tokenizer": "*", 1874 | "ext-xmlwriter": "*", 1875 | "php": "^7.2 || ^8.0" 1876 | }, 1877 | "type": "library", 1878 | "autoload": { 1879 | "classmap": [ 1880 | "src/" 1881 | ] 1882 | }, 1883 | "notification-url": "https://packagist.org/downloads/", 1884 | "license": [ 1885 | "BSD-3-Clause" 1886 | ], 1887 | "authors": [ 1888 | { 1889 | "name": "Arne Blankerts", 1890 | "email": "arne@blankerts.de", 1891 | "role": "Developer" 1892 | } 1893 | ], 1894 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1895 | "support": { 1896 | "issues": "https://github.com/theseer/tokenizer/issues", 1897 | "source": "https://github.com/theseer/tokenizer/tree/1.2.1" 1898 | }, 1899 | "funding": [ 1900 | { 1901 | "url": "https://github.com/theseer", 1902 | "type": "github" 1903 | } 1904 | ], 1905 | "time": "2021-07-28T10:34:58+00:00" 1906 | } 1907 | ], 1908 | "aliases": [], 1909 | "minimum-stability": "stable", 1910 | "stability-flags": { 1911 | "fzaninotto/faker": 20 1912 | }, 1913 | "prefer-stable": false, 1914 | "prefer-lowest": false, 1915 | "platform": { 1916 | "php": ">=8.1" 1917 | }, 1918 | "platform-dev": [], 1919 | "plugin-api-version": "2.3.0" 1920 | } 1921 | -------------------------------------------------------------------------------- /docs/migrate5to6.md: -------------------------------------------------------------------------------- 1 | # Migrate 5 to 6 2 | 3 | Change pipe format in map: 4 | ```php 5 | // 5 6 | $mapOld = [ 7 | 'active' => [ 8 | 'pipe' => [ 9 | [ 10 | 'populate' => 'boolval', 11 | 'extract' => 'boolval', 12 | ] 13 | ] 14 | ], 15 | 'email' => [ 16 | 'pipe' => [ 17 | 'strtolower' 18 | ] 19 | ], 20 | ]; 21 | 22 | // 6 23 | $mapNew = [ 24 | 'active' => [ 25 | 'pipe-populate' => [ 26 | 'boolval', 27 | ], 28 | 'pipe-extract' => [ 29 | 'boolval', 30 | ] 31 | ], 32 | 'email' => [ 33 | 'pipe-populate' => ['strtolower'], 34 | 'pipe-extract' => ['strtolower'], 35 | ], 36 | ]; 37 | 38 | ``` -------------------------------------------------------------------------------- /src/DataTransformer.php: -------------------------------------------------------------------------------- 1 | extractor = $extractor ?? new Extractor; 23 | $this->hydrator = $hydrator ?? new Hydrator; 24 | $this->mapsManager = $mapsManager ?? new MapsManager; 25 | } 26 | 27 | public function getMapsManager(): MapsManager 28 | { 29 | return $this->mapsManager; 30 | } 31 | 32 | public function toModel(string $class, array $dto, string $mapName = 'dto'): object 33 | { 34 | $map = $this->mapsManager->getMap($class, $mapName); 35 | $dto = $map['refs'] ? $this->resolveRefPopulate($dto, $map['refs']) : $dto; 36 | $dto = $map['pipe-populate'] ? $this->pipes($dto, $map['pipe-populate']) : $dto; 37 | return $this->hydrator->hydrate($dto, $class, $map['rules']); 38 | } 39 | 40 | public function toModelsCollection(string $model, iterable $dtoCollection, string $mapType = 'dto'): array 41 | { 42 | $models = []; 43 | foreach ($dtoCollection as $key => $dto) { 44 | $dto = $this->toModel($model, $dto, $mapType); 45 | $models[$key] = $dto; 46 | } 47 | 48 | return $models; 49 | } 50 | 51 | public function fillModel(object $model, array $dto, string $mapName = 'dto'): object 52 | { 53 | $map = $this->mapsManager->getMap($model::class, $mapName); 54 | $dto = $map['refs'] ? $this->resolveRefPopulate($dto, $map['refs']) : $dto; 55 | $dto = $map['pipe-populate'] ? $this->pipes($dto, $map['pipe-populate']) : $dto; 56 | $this->hydrator->hydrateModel($dto, $model, $map['rules']); 57 | 58 | return $model; 59 | } 60 | 61 | public function toDtoCollection(iterable $models, string $mapName = 'dto', array $options = []): array 62 | { 63 | $collection = []; 64 | foreach ($models as $key => $model) { 65 | $dto = $this->toDTO($model, $mapName, $options); 66 | $collection[$key] = $dto; 67 | } 68 | 69 | return $collection; 70 | } 71 | 72 | public function toDTO(object $model, string $mapName = 'dto', array $options = []): array 73 | { 74 | $map = $this->mapsManager->getMap($model::class, $mapName); 75 | $excludeRules = $options['excludeFields'] ?? []; 76 | 77 | foreach ($excludeRules as $name) { 78 | unset($map['pipe'][$name], $map['rules'][$name], $map['refs'][$name]); 79 | } 80 | 81 | $dto = $this->extractor->extract($model, $map['rules']); 82 | $dto = $map['pipe-extract'] ? $this->pipes($dto, $map['pipe-extract']) : $dto; 83 | return $map['refs'] ? $this->resolveRefExtract($dto, $map['refs']) : $dto; 84 | } 85 | 86 | protected function resolveRefExtract(array $dto, array $refsRules): array 87 | { 88 | foreach ($refsRules as $name => $rule) { 89 | $value = $dto[$name] ?? null; 90 | if ($value !== null) { 91 | $method = ($rule['collection'] ?? false) ? 'toDtoCollection' : 'toDTO'; 92 | $dto[$name] = $this->{$method}($value, $rule['map']); 93 | } 94 | } 95 | 96 | return $dto; 97 | } 98 | 99 | protected function resolveRefPopulate(array $dto, array $refsRules): array 100 | { 101 | foreach ($refsRules as $name => $rule) { 102 | $value = $dto[$name] ?? null; 103 | if ($value !== null) { 104 | $dto[$name] = ($rule['collection'] ?? false) 105 | ? $this->toModelsCollection($rule['model'], $value, $rule['map']) 106 | : $this->toModel($rule['model'], $value, $rule['map']); 107 | } 108 | } 109 | 110 | return $dto; 111 | } 112 | 113 | /** 114 | * @param array $dto 115 | * @param callable[][] $pipes 116 | * 117 | * @return array - modified dto 118 | */ 119 | protected function pipes(array $dto, array $pipes): array 120 | { 121 | $fieldsPipes = array_intersect_key($pipes, $dto); 122 | foreach ($fieldsPipes as $name => $filters) { 123 | $value = $dto[$name] ?? null; 124 | foreach ($filters as $filter) { 125 | $value = $filter($value); 126 | } 127 | 128 | $dto[$name] = $value; 129 | } 130 | 131 | return $dto; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/DataTransformerInterface.php: -------------------------------------------------------------------------------- 1 | normalizer = $normalizer ?? new Normalizer; 20 | $this->setDefaultMapDir($dir); 21 | } 22 | 23 | public function setContainer(ContainerInterface $container): static 24 | { 25 | $this->container = $container; 26 | return $this; 27 | } 28 | 29 | public function getContainer(): ?ContainerInterface 30 | { 31 | return $this->container; 32 | } 33 | 34 | public function setDefaultMapDir(string $dir): void 35 | { 36 | $this->defaultMapsDirs = $dir; 37 | } 38 | 39 | public function setMapDir(string $entityName, string $dir): void 40 | { 41 | $this->mapsDirs[$entityName] = $dir; 42 | } 43 | 44 | public function getMap(string $entityName, string $mapName = 'dto'): array 45 | { 46 | $map = $this->cache[$entityName][$mapName] ?? null; 47 | if ($map === null) { 48 | $dir = $this->getMapDir($entityName); 49 | $rules = $this->includeMap($dir . DIRECTORY_SEPARATOR . $mapName . '.php'); 50 | $this->setMap($rules, $entityName, $mapName); 51 | } 52 | 53 | return $this->cache[$entityName][$mapName]; 54 | } 55 | 56 | protected function includeMap(string $file): array 57 | { 58 | return require $file; 59 | } 60 | 61 | public function getMapDir(string $entityName): string 62 | { 63 | $dir = $this->mapsDirs[$entityName] ?? null; 64 | 65 | if (!$dir) { 66 | $parts = explode('\\', $entityName); 67 | $class = array_pop($parts); 68 | $dir = $this->defaultMapsDirs . DIRECTORY_SEPARATOR . $class; 69 | } 70 | 71 | return $dir; 72 | } 73 | 74 | public function setMap(array $rules, string $entityName, $mapName = 'dto'): void 75 | { 76 | $this->cache[$entityName][$mapName] = $this->normalizer->normalize($rules); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Normalizer.php: -------------------------------------------------------------------------------- 1 | [], 13 | 'pipe-extract' => [], 14 | 'rules' => $rules, 15 | 'refs' => [], 16 | ]; 17 | 18 | foreach ($map['rules'] as $name => &$rule) { 19 | $rule['prop'] ??= $name; 20 | $map['refs'][$name] = $rule['ref'] ?? null; 21 | $map['pipe-populate'][$name] = $rule['pipe-populate'] ?? null; 22 | $map['pipe-extract'][$name] = $rule['pipe-extract'] ?? null; 23 | } 24 | 25 | $map['refs'] = array_filter($map['refs']); 26 | $map['pipe-populate'] = array_filter($map['pipe-populate']); 27 | $map['pipe-extract'] = array_filter($map['pipe-extract']); 28 | 29 | return $map; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/NormalizerInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | ../src/ 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ./unit 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/unit/DataTransformerTest.php: -------------------------------------------------------------------------------- 1 | dataTransformer = new DataTransformer; 20 | $this->dataTransformer->getMapsManager()->setMapDir(UserModel::class, __DIR__ . '/data'); 21 | 22 | $this->faker = Factory::create(); 23 | } 24 | 25 | /** 26 | * @return UserModel 27 | * @throws Exception 28 | */ 29 | protected function createUser(): UserModel 30 | { 31 | $user = new UserModel; 32 | $user->setId(random_int(1, 9999)); 33 | $user->setActive($this->faker->randomElement([true, false])); 34 | $user->setEmail(strtoupper($this->faker->email)); 35 | $user->setLogin($this->faker->name); 36 | $user->setName($this->faker->name); 37 | 38 | return $user; 39 | } 40 | 41 | public function testConstructor(): void 42 | { 43 | static::assertInstanceOf(DataTransformer::class, $this->dataTransformer); 44 | } 45 | 46 | public function testGetMapsManager(): void 47 | { 48 | $mapsManager = $this->dataTransformer->getMapsManager(); 49 | static::assertInstanceOf(MapsManager::class, $mapsManager); 50 | } 51 | 52 | /** 53 | * @throws Exception 54 | */ 55 | public function testToModel(): void 56 | { 57 | $model = $this->dataTransformer->toModel(UserModel::class, [ 58 | 'id' => 1, 59 | 'creAt' => new DateTime, 60 | 'name' => 'Alex', 61 | 'active' => 1, 62 | ]); 63 | 64 | static::assertInstanceOf(UserModel::class, $model); 65 | static::assertEquals(true, $model->isActive()); 66 | static::assertEquals(1, $model->getId()); 67 | static::assertEquals('Alex', $model->getName()); 68 | } 69 | 70 | /** 71 | * @throws Exception 72 | */ 73 | public function testFillModel(): void 74 | { 75 | $model = new UserModel; 76 | $model = $this->dataTransformer->fillModel($model, [ 77 | 'id' => 1, 78 | 'creAt' => new DateTime, 79 | 'name' => 'Alex', 80 | 'active' => 1, 81 | ]); 82 | 83 | static::assertInstanceOf(UserModel::class, $model); 84 | static::assertEquals(true, $model->isActive()); 85 | static::assertEquals(1, $model->getId()); 86 | static::assertEquals('Alex', $model->getName()); 87 | } 88 | 89 | /** 90 | * @throws Exception 91 | */ 92 | public function testToDTO(): void 93 | { 94 | $model = $this->createUser(); 95 | $dto = $this->dataTransformer->toDTO($model); 96 | static::assertEquals([ 97 | 'id' => $model->getId(), 98 | 'creAt' => $model->getCreAt(), 99 | 'name' => $model->getName(), 100 | 'login' => $model->getLogin(), 101 | 'active' => $model->isActive(), 102 | 'email' => strtolower($model->getEmail()), 103 | ], $dto); 104 | } 105 | 106 | public function testToDTOWithExcludeFields(): void 107 | { 108 | $model = new UserModel; 109 | $model->setId(1); 110 | $model->setActive(false); 111 | 112 | $dto = $this->dataTransformer->toDTO($model, 'dto', [ 113 | 'excludeFields' => ['email', 'login'], 114 | ]); 115 | static::assertEquals([ 116 | 'id' => 1, 117 | 'creAt' => $model->getCreAt(), 118 | 'name' => null, 119 | 'active' => false, 120 | ], $dto); 121 | } 122 | 123 | /** 124 | * @throws Exception 125 | */ 126 | public function testToDtoCollection(): void 127 | { 128 | $model1 = $this->createUser(); 129 | $model2 = $this->createUser(); 130 | $models = [$model1, $model2]; 131 | 132 | $dtoCollection = $this->dataTransformer->toDtoCollection($models); 133 | static::assertCount(2, $dtoCollection); 134 | 135 | static::assertSame([ 136 | 'id' => $model1->getId(), 137 | 'creAt' => $model1->getCreAt(), 138 | 'name' => $model1->getName(), 139 | 'login' => $model1->getLogin(), 140 | 'active' => $model1->isActive(), 141 | 'email' => strtolower($model1->getEmail()), 142 | ], $dtoCollection[0]); 143 | 144 | static::assertSame([ 145 | 'id' => $model2->getId(), 146 | 'creAt' => $model2->getCreAt(), 147 | 'name' => $model2->getName(), 148 | 'login' => $model2->getLogin(), 149 | 'active' => $model2->isActive(), 150 | 'email' => strtolower($model2->getEmail()), 151 | ], $dtoCollection[1]); 152 | } 153 | 154 | /** 155 | * @throws Exception 156 | */ 157 | public function testToModelsCollection(): void 158 | { 159 | $dtoCollection = [ 160 | [ 161 | 'id' => 1, 162 | 'creAt' => new DateTime, 163 | 'name' => 'Alex', 164 | 'active' => true, 165 | ], 166 | [ 167 | 'id' => 2, 168 | 'creAt' => new DateTime, 169 | 'name' => 'Bob', 170 | 'active' => false, 171 | ], 172 | ]; 173 | 174 | /** @var UserModel[] $models */ 175 | $models = $this->dataTransformer->toModelsCollection(UserModel::class, $dtoCollection); 176 | static::assertCount(2, $models); 177 | 178 | static::assertInstanceOf(UserModel::class, $models[0]); 179 | static::assertEquals(1, $models[0]->getId()); 180 | static::assertEquals('Alex', $models[0]->getName()); 181 | static::assertEquals(true, $models[0]->isActive()); 182 | 183 | static::assertInstanceOf(UserModel::class, $models[1]); 184 | static::assertEquals(2, $models[1]->getId()); 185 | static::assertEquals('Bob', $models[1]->getName()); 186 | static::assertEquals(false, $models[1]->isActive()); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /test/unit/MapsManagerTest.php: -------------------------------------------------------------------------------- 1 | manager = new MapsManager; 17 | } 18 | 19 | public function testSetMapDir(): void 20 | { 21 | $this->manager->setMapDir('model.user', __DIR__ . '/data'); 22 | $result = $this->manager->getMap('model.user'); 23 | static::assertNotNull($result); 24 | } 25 | 26 | public function testGetMap(): void 27 | { 28 | $this->manager->setMapDir('model.user', __DIR__ . '/data'); 29 | $map = $this->manager->getMap('model.user'); 30 | static::assertCount(4, $map); 31 | static::assertCount(6, $map['rules']); 32 | static::assertCount(2, $map['pipe-populate']); 33 | static::assertCount(2, $map['pipe-extract']); 34 | static::assertCount(0, $map['refs']); 35 | } 36 | 37 | public function testGetMapWithCache(): void 38 | { 39 | $this->manager->setMapDir('model.user', __DIR__ . '/data'); 40 | $map = $this->manager->getMap('model.user'); 41 | $map2 = $this->manager->getMap('model.user'); 42 | static::assertCount(4, $map2); 43 | static::assertCount(6, $map2['rules']); 44 | static::assertCount(2, $map2['pipe-populate']); 45 | static::assertCount(2, $map2['pipe-extract']); 46 | static::assertCount(0, $map2['refs']); 47 | static::assertSame($map, $map2); 48 | } 49 | 50 | public function testGetMapFromDefaultDir(): void 51 | { 52 | $this->manager->setDefaultMapDir(__DIR__ . '/data'); 53 | $map = $this->manager->getMap('Namespace\UserModel'); 54 | static::assertCount(4, $map); 55 | static::assertCount(6, $map['rules']); 56 | static::assertCount(2, $map['pipe-populate']); 57 | static::assertCount(2, $map['pipe-extract']); 58 | static::assertCount(0, $map['refs']); 59 | } 60 | 61 | public function testContainer(): void 62 | { 63 | $container = new Container; 64 | $this->manager->setContainer($container); 65 | $value = $this->manager->getContainer()->get('any'); 66 | static::assertSame(1, $value); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/unit/RefTest.php: -------------------------------------------------------------------------------- 1 | setMapDir(UserModel::class, __DIR__ . '/data'); 28 | 29 | $this->dataTransformer = new DataTransformer($extractor, $hydrator, $mapsManager); 30 | 31 | $this->faker = Factory::create(); 32 | } 33 | 34 | /** 35 | * @return UserModel 36 | * @throws Exception 37 | */ 38 | protected function createUser(): UserModel 39 | { 40 | $user = new UserModel; 41 | $user->setId(random_int(1, 9999)); 42 | $user->setActive($this->faker->randomElement([true, false])); 43 | $user->setEmail($this->faker->email); 44 | $user->setLogin($this->faker->name); 45 | $user->setName($this->faker->name); 46 | 47 | return $user; 48 | } 49 | 50 | /** 51 | * @throws Exception 52 | */ 53 | public function testFillModelRefModel(): void 54 | { 55 | $model = new UserModel; 56 | $this->dataTransformer->fillModel($model, [ 57 | 'id' => 1, 58 | 'name' => 'Alex', 59 | 'refModel' => [ 60 | 'id' => 2, 61 | 'creAt' => new DateTime, 62 | 'name' => 'Alex2', 63 | 'active' => true, 64 | ] 65 | ], 'withRefs.map'); 66 | 67 | static::assertInstanceOf(UserModel::class, $model); 68 | static::assertInstanceOf(UserModel::class, $model->refModel); 69 | static::assertEquals(2, $model->refModel->getId()); 70 | } 71 | 72 | /** 73 | * @throws Exception 74 | */ 75 | public function testFillModelRefModelWithExtraFields(): void 76 | { 77 | $model = new UserModel; 78 | $this->dataTransformer->fillModel($model, [ 79 | 'id' => 1, 80 | 'name' => 'Alex', 81 | 'extraFieldWithoutDeclarateTransform' => 3, 82 | 'refModel' => [ 83 | 'id' => 2, 84 | 'creAt' => new DateTime, 85 | 'name' => 'Alex2', 86 | 'active' => true, 87 | ] 88 | ], 'withRefs.map'); 89 | 90 | static::assertInstanceOf(UserModel::class, $model); 91 | static::assertInstanceOf(UserModel::class, $model->refModel); 92 | static::assertEquals(2, $model->refModel->getId()); 93 | } 94 | 95 | /** 96 | * @throws Exception 97 | */ 98 | public function testToModelRefModel(): void 99 | { 100 | /** @var UserModel $model */ 101 | $model = $this->dataTransformer->toModel(UserModel::class, [ 102 | 'id' => 1, 103 | 'name' => 'Alex', 104 | 'refModel' => [ 105 | 'id' => 2, 106 | 'creAt' => new DateTime, 107 | 'name' => 'Alex2', 108 | 'active' => true, 109 | ] 110 | ], 'withRefs.map'); 111 | 112 | static::assertInstanceOf(UserModel::class, $model); 113 | static::assertInstanceOf(UserModel::class, $model->refModel); 114 | static::assertEquals(2, $model->refModel->getId()); 115 | } 116 | 117 | public function testToModelRefModels(): void 118 | { 119 | /** @var UserModel $model */ 120 | $model = $this->dataTransformer->toModel(UserModel::class, [ 121 | 'id' => 1, 122 | 'name' => 'Alex', 123 | 'refModels' => [ 124 | [ 125 | 'id' => 2, 126 | 'name' => 'Alex2', 127 | ], 128 | [ 129 | 'id' => 3, 130 | 'name' => 'Alex3', 131 | ] 132 | ] 133 | ], 'withRefs.map'); 134 | 135 | static::assertCount(2, $model->refModels); 136 | static::assertInstanceOf(UserModel::class, $model->refModels[0]); 137 | static::assertInstanceOf(UserModel::class, $model->refModels[1]); 138 | static::assertEquals(2, $model->refModels[0]->getId()); 139 | static::assertEquals(3, $model->refModels[1]->getId()); 140 | } 141 | 142 | /** 143 | * @throws Exception 144 | */ 145 | public function testToDtoRefModel(): void 146 | { 147 | $model = $this->createUser(); 148 | $model2= $this->createUser(); 149 | 150 | $model->refModel = $model2; 151 | 152 | $dto = $this->dataTransformer->toDTO($model, 'withRefs.map', ['refModels']); 153 | static::assertEquals($dto['refModel'], [ 154 | 'id' => $model2->getId(), 155 | 'creAt' => $model2->getCreAt(), 156 | 'name' => $model2->getName(), 157 | 'login' => $model2->getLogin(), 158 | 'active' => $model2->isActive(), 159 | 'email' => $model2->getEmail(), 160 | ]); 161 | } 162 | 163 | /** 164 | * @throws Exception 165 | */ 166 | public function testToDtoRefModels(): void 167 | { 168 | $model = $this->createUser(); 169 | $model2= $this->createUser(); 170 | $model3= $this->createUser(); 171 | 172 | $model->refModels = [$model2, $model3]; 173 | 174 | $dto = $this->dataTransformer->toDTO($model, 'withRefs.map', ['refModel']); 175 | static::assertCount(2, $dto['refModels']); 176 | static::assertEquals($dto['refModels'], [ 177 | [ 178 | 'id' => $model2->getId(), 179 | 'creAt' => $model2->getCreAt(), 180 | 'name' => $model2->getName(), 181 | 'login' => $model2->getLogin(), 182 | 'active' => $model2->isActive(), 183 | 'email' => $model2->getEmail(), 184 | ], 185 | [ 186 | 'id' => $model3->getId(), 187 | 'creAt' => $model3->getCreAt(), 188 | 'name' => $model3->getName(), 189 | 'login' => $model3->getLogin(), 190 | 'active' => $model3->isActive(), 191 | 'email' => $model3->getEmail(), 192 | ] 193 | ]); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /test/unit/data/Container.php: -------------------------------------------------------------------------------- 1 | creAt = new \DateTime; 24 | } 25 | 26 | public function __toString(): string 27 | { 28 | return (string)$this->id; 29 | } 30 | 31 | public function getEmail(): string 32 | { 33 | return $this->email; 34 | } 35 | 36 | public function setEmail(string $email): void 37 | { 38 | $this->email = $email; 39 | } 40 | 41 | /** @var string */ 42 | protected $email; 43 | 44 | public function getId() 45 | { 46 | return $this->id; 47 | } 48 | 49 | public function setId($id): void 50 | { 51 | $this->id = $id; 52 | } 53 | 54 | public function getName(): ?string 55 | { 56 | return $this->name; 57 | } 58 | 59 | public function setName(string $name): void 60 | { 61 | $this->name = $name; 62 | } 63 | 64 | public function getLogin(): ?string 65 | { 66 | return $this->login; 67 | } 68 | 69 | public function setLogin(string $login): void 70 | { 71 | $this->login = $login; 72 | } 73 | 74 | public function getCreAt(): \DateTime 75 | { 76 | return $this->creAt; 77 | } 78 | 79 | public function setCreAt(\DateTime $creAt): void 80 | { 81 | $this->creAt = $creAt; 82 | } 83 | 84 | public function isActive(): bool 85 | { 86 | return $this->active; 87 | } 88 | 89 | public function setActive(bool $active): void 90 | { 91 | $this->active = (bool)$active; 92 | } 93 | 94 | public function getCreAtTimestamp(): int 95 | { 96 | return $this->creAt->getTimestamp(); 97 | } 98 | 99 | public function getTitleName(string $title): string 100 | { 101 | return $title . ' ' . $this->name; 102 | } 103 | 104 | public function setTitleName(string $name, string $suffix): void 105 | { 106 | $this->name = $name . ' ' . $suffix; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /test/unit/data/UserModel/dto.php: -------------------------------------------------------------------------------- 1 | [], 5 | 'creAt' => [], 6 | 'name' => [], 7 | 'login' => [], 8 | 'active' => [ 9 | // 'pipe' => [ 10 | // [ 11 | // 'populate' => 'boolval', 12 | // 'extract' => 'boolval', 13 | // ], 14 | // ], 15 | 'pipe-populate' => [ 16 | 'boolval' 17 | ], 18 | 'pipe-extract' => [ 19 | 'boolval' 20 | ] 21 | ], 22 | 'email' => [ 23 | // 'pipe' => [ 24 | // 'strtolower', 25 | // ], 26 | 'pipe-populate' => [ 27 | 'strtolower' 28 | ], 29 | 'pipe-extract' => [ 30 | 'strtolower' 31 | ] 32 | ], 33 | ]; -------------------------------------------------------------------------------- /test/unit/data/dto.php: -------------------------------------------------------------------------------- 1 | [], 10 | 'creAt' => [], 11 | 'name' => [], 12 | 'login' => [], 13 | 'active' => [ 14 | 'pipe-populate' => ['boolval'], 15 | 'pipe-extract' => ['boolval'], 16 | ], 17 | 'email' => [ 18 | 'pipe-populate' => ['strtolower'], 19 | 'pipe-extract' => ['strtolower'], 20 | ], 21 | ]; -------------------------------------------------------------------------------- /test/unit/data/withRefs.map.php: -------------------------------------------------------------------------------- 1 | [], 7 | 'creAt' => [], 8 | 'name' => [], 9 | 'login' => [], 10 | 'active' => [ 11 | 'pipe-populate' => ['boolval'], 12 | 'pipe-extract' => ['boolval'], 13 | ], 14 | 'email' => [], 15 | 'refModel' => [ 16 | 'ref' => [ 17 | 'model' => UserModel::class, 18 | 'map' => 'dto' 19 | ] 20 | ], 21 | 'refModels' => [ 22 | 'ref' => [ 23 | 'model' => UserModel::class, 24 | 'map' => 'dto', 25 | 'collection' => true 26 | ] 27 | ], 28 | ]; --------------------------------------------------------------------------------