diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 33954cd..8ab7d55 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,31 +1,17 @@ filter: - paths: - - 'src/*' -checks: - php: - uppercase_constants: true - simplify_boolean_return: true - return_doc_comments: true - properties_in_camelcaps: true - phpunit_assertions: true - parameters_in_camelcaps: true - parameter_doc_comments: true - -coding_style: - php: { } - -tools: - external_code_coverage: false + paths: ['src/*'] build: environment: php: version: 8.0 - tests: override: - - - command: 'vendor/bin/phpunit --configuration ./test/phpunit.xml --coverage-clover=test/clover.xml' + - php-scrutinizer-run --enable-security-analysis + - command: 'XDEBUG_MODE=coverage ./vendor/bin/phpunit --config test/phpunit.xml --coverage-clover=test/clover.xml' coverage: file: 'test/clover.xml' format: 'clover' + +tools: + external_code_coverage: false \ No newline at end of file diff --git a/README.md b/README.md index 3819fb0..a870e6d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ представить в виде строки в формате ISO8601. ```php +use PTS\DataTransformer\DataTransformer; + $dataTransformer = new DataTransformer; $dataTransformer->getMapsManager()->setMapDir(UserModel::class, __DIR__ . '/data'); @@ -45,7 +47,7 @@ $dto = $dataTransformer->toDTO($model, 'dto'); $dtoForDb = $dataTransformer->toDTO($model, 'db'); ``` -А еще у нас может быть просто более компактное представлеиние этой же модели, без лишних деталей. +А еще может быть просто более компактное представлеиние этой же модели, без лишних деталей. ```php $shortFormatDto = $dataTransformer->toDTO($model, 'short.dto'); @@ -59,7 +61,7 @@ $shortFormatDto = $dataTransformer->toDTO($model, 'short.dto'); $mapName = 'dto'; $excludedFields = ['name']; $dtoCollection = $dataTransformer->toDtoCollection($models, $mapName, [ - 'excludeFields' => $excludedFields + 'excludeFields' => $excludedFields ]); ``` @@ -76,15 +78,14 @@ return [ 'name' => [], 'login' => [], 'active' => [ - 'pipe' => ['boolval'] + 'pipe-populate' => ['boolval'], + 'pipe-extract' => ['boolval'], ], 'email' => [ - 'pipe' => [ - [ - 'populate' => 'strtolower', // any callable - 'extract' => 'strtoupper' - ] - ] + 'pipe-populate' => [ // any callable + 'strval', + 'strtolower', + ] ], 'refModel' => [ 'ref' => [ @@ -134,8 +135,8 @@ $model2 = $dataTransformer->toModel(UserModel::class, [ ### Логика в pipe обработчиках Обработчики pipe позволяют описывать callable методы и писать любую логику, которая будет применяться к значению. В pipe -фильтрах можно кастить типы например. Либо шифровать поля перед записью в БД. В случае необходимости, чтобы вся логика -маппинга была в 1 месте, вы может прокинуть любые зависимости через замыкание в функцию pipe, доставл ее из контейнера. +фильтрах можно кастить типы. Либо шифровать поля перед записью в БД. В случае необходимости, чтобы вся логика +маппинга была в 1 месте, вы может прокинуть любые зависимости через замыкание в функцию pipe, достав ее из контейнера. ```php [], 'name' => [], 'password' => [ - 'pipe' => [ - [ - 'extract' => function(string $openPassword) use($encrypter) { - return $encrypter->encrypt($openPassword, false); - }, - 'populate' => static function(string $ePassword) use($encrypter) { - return $encrypter->decrypt($ePassword, false); - }, - ] - ] + 'pipe-populate' => [ + 'strtolower', + function(string $openPassword) use($encrypter) { + return $encrypter->encrypt($openPassword); + }, + ], + 'pipe-extract' => [ + function(string $ePassword) use($encrypter) { + return $encrypter->decrypt($ePassword); + }, + 'strtolower' ], +]; + + +### migrates + +[update 5 to 6](https://github.com/alexpts/php-data-transformer2/blob/master/docs/migrate5to6.md) -]; \ No newline at end of file diff --git a/docs/migrate5to6.md b/docs/migrate5to6.md new file mode 100644 index 0000000..f9e59af --- /dev/null +++ b/docs/migrate5to6.md @@ -0,0 +1,40 @@ +# Migrate 5 to 6 + +Change pipe format in map: +```php +// 5 +$mapOld = [ + 'active' => [ + 'pipe' => [ + [ + 'populate' => 'boolval', + 'extract' => 'boolval', + ] + ] + ], + 'email' => [ + 'pipe-populate' => ['strtolower'], + 'pipe-extract' => ['strtolower'], + 'pipe' => [ + 'strtolower' + ] + ], +]; + +// 6 +$mapNew = [ + 'active' => [ + 'pipe-populate' => [ + 'boolval', + ], + 'pipe-extract' => [ + 'boolval', + ] + ], + 'email' => [ + 'pipe-populate' => ['strtolower'], + 'pipe-extract' => ['strtolower'], + ], +]; + +``` \ No newline at end of file diff --git a/src/DataTransformer.php b/src/DataTransformer.php index 87f9315..b515ef2 100644 --- a/src/DataTransformer.php +++ b/src/DataTransformer.php @@ -6,14 +6,9 @@ use PTS\Hydrator\ExtractorInterface; use PTS\Hydrator\Hydrator; use PTS\Hydrator\HydratorInterface; -use function get_class; -use function is_callable; class DataTransformer implements DataTransformerInterface { - protected const FILTER_TYPE_POPULATE = 'populate'; - protected const FILTER_TYPE_EXTRACT = 'extract'; - protected ExtractorInterface $extractor; protected HydratorInterface $hydrator; protected MapsManager $mapsManager; @@ -37,19 +32,16 @@ public function toModel(string $class, array $dto, string $mapName = 'dto'): obj { $map = $this->mapsManager->getMap($class, $mapName); $dto = $map['refs'] ? $this->resolveRefPopulate($dto, $map['refs']) : $dto; - $dto = $map['pipe'] ? $this->applyPipes($dto, $map['pipe']) : $dto; + $dto = $map['pipe-populate'] ? $this->pipes($dto, $map['pipe-populate']) : $dto; return $this->hydrator->hydrate($dto, $class, $map['rules']); } public function toModelsCollection(string $model, iterable $dtoCollection, string $mapType = 'dto'): array { - $map = $this->mapsManager->getMap($model, $mapType); - $models = []; - foreach ($dtoCollection as $dto) { - $dto = $map['refs'] ? $this->resolveRefPopulate($dto, $map['refs']) : $dto; - $dto = $map['pipe'] ? $this->applyPipes($dto, $map['pipe']) : $dto; - $models[] = $this->hydrator->hydrate($dto, $model, $map['rules']); + foreach ($dtoCollection as $key => $dto) { + $dto = $this->toModel($model, $dto, $mapType); + $models[$key] = $dto; } return $models; @@ -59,7 +51,7 @@ public function fillModel(object $model, array $dto, string $mapName = 'dto'): o { $map = $this->mapsManager->getMap($model::class, $mapName); $dto = $map['refs'] ? $this->resolveRefPopulate($dto, $map['refs']) : $dto; - $dto = $map['pipe'] ? $this->applyPipes($dto, $map['pipe']) : $dto; + $dto = $map['pipe-populate'] ? $this->pipes($dto, $map['pipe-populate']) : $dto; $this->hydrator->hydrateModel($dto, $model, $map['rules']); return $model; @@ -86,7 +78,7 @@ public function toDTO(object $model, string $mapName = 'dto', array $options = [ } $dto = $this->extractor->extract($model, $map['rules']); - $dto = $map['pipe'] ? $this->applyPipes($dto, $map['pipe'], self::FILTER_TYPE_EXTRACT) : $dto; + $dto = $map['pipe-extract'] ? $this->pipes($dto, $map['pipe-extract']) : $dto; return $map['refs'] ? $this->resolveRefExtract($dto, $map['refs']) : $dto; } @@ -124,28 +116,18 @@ protected function resolveRefPopulate(array $dto, array $refsRules): array return $dto; } - protected function applyPipes(array $dto, array $pipes, string $type = self::FILTER_TYPE_POPULATE): array + protected function pipes(array $dto, array $pipes): array { $fieldsPipes = array_intersect_key($pipes, $dto); foreach ($fieldsPipes as $name => $filters) { $value = $dto[$name] ?? null; - $dto[$name] = $this->applyFilters($value, $filters, $type); - } - - return $dto; - } - - protected function applyFilters($value, array $filters, string $type): mixed - { - foreach ($filters as $filter) { - if (is_callable($filter)) { + foreach ($filters as $filter) { $value = $filter($value); - continue; } - $value = ($filter[$type] ?? false) ? $filter[$type]($value) : $value; + $dto[$name] = $value; } - return $value; + return $dto; } } diff --git a/src/Normalizer.php b/src/Normalizer.php index 6ad4a31..81e500a 100644 --- a/src/Normalizer.php +++ b/src/Normalizer.php @@ -9,7 +9,8 @@ class Normalizer implements NormalizerInterface public function normalize(array $rules): array { $map = [ - 'pipe' => [], + 'pipe-populate' => [], + 'pipe-extract' => [], 'rules' => $rules, 'refs' => [], ]; @@ -17,11 +18,13 @@ public function normalize(array $rules): array foreach ($map['rules'] as $name => &$rule) { $rule['prop'] ??= $name; $map['refs'][$name] = $rule['ref'] ?? null; - $map['pipe'][$name] = $rule['pipe'] ?? null; + $map['pipe-populate'][$name] = $rule['pipe-populate'] ?? null; + $map['pipe-extract'][$name] = $rule['pipe-extract'] ?? null; } $map['refs'] = array_filter($map['refs']); - $map['pipe'] = array_filter($map['pipe']); + $map['pipe-populate'] = array_filter($map['pipe-populate']); + $map['pipe-extract'] = array_filter($map['pipe-extract']); return $map; } diff --git a/test/unit/MapsManagerTest.php b/test/unit/MapsManagerTest.php index 0a9025d..29afed3 100644 --- a/test/unit/MapsManagerTest.php +++ b/test/unit/MapsManagerTest.php @@ -27,9 +27,10 @@ public function testGetMap(): void { $this->manager->setMapDir('model.user', __DIR__ . '/data'); $map = $this->manager->getMap('model.user'); - static::assertCount(3, $map); + static::assertCount(4, $map); static::assertCount(6, $map['rules']); - static::assertCount(2, $map['pipe']); + static::assertCount(2, $map['pipe-populate']); + static::assertCount(2, $map['pipe-extract']); static::assertCount(0, $map['refs']); } @@ -38,9 +39,10 @@ public function testGetMapWithCache(): void $this->manager->setMapDir('model.user', __DIR__ . '/data'); $map = $this->manager->getMap('model.user'); $map2 = $this->manager->getMap('model.user'); - static::assertCount(3, $map2); + static::assertCount(4, $map2); static::assertCount(6, $map2['rules']); - static::assertCount(2, $map2['pipe']); + static::assertCount(2, $map2['pipe-populate']); + static::assertCount(2, $map2['pipe-extract']); static::assertCount(0, $map2['refs']); static::assertSame($map, $map2); } @@ -49,9 +51,10 @@ public function testGetMapFromDefaultDir(): void { $this->manager->setDefaultMapDir(__DIR__ . '/data'); $map = $this->manager->getMap('Namespace\UserModel'); - static::assertCount(3, $map); + static::assertCount(4, $map); static::assertCount(6, $map['rules']); - static::assertCount(2, $map['pipe']); + static::assertCount(2, $map['pipe-populate']); + static::assertCount(2, $map['pipe-extract']); static::assertCount(0, $map['refs']); } diff --git a/test/unit/data/UserModel/dto.php b/test/unit/data/UserModel/dto.php index 04a26d9..ef1af11 100644 --- a/test/unit/data/UserModel/dto.php +++ b/test/unit/data/UserModel/dto.php @@ -6,15 +6,27 @@ 'name' => [], 'login' => [], 'active' => [ - 'pipe' => [ - [ - 'populate' => 'boolval', - 'extract' => 'boolval', - ] +// 'pipe' => [ +// [ +// 'populate' => 'boolval', +// 'extract' => 'boolval', +// ], +// ], + 'pipe-populate' => [ + 'boolval' + ], + 'pipe-extract' => [ + 'boolval' ] ], 'email' => [ - 'pipe' => [ +// 'pipe' => [ +// 'strtolower', +// ], + 'pipe-populate' => [ + 'strtolower' + ], + 'pipe-extract' => [ 'strtolower' ] ], diff --git a/test/unit/data/dto.php b/test/unit/data/dto.php index 16d79bd..dbb75d1 100644 --- a/test/unit/data/dto.php +++ b/test/unit/data/dto.php @@ -11,16 +11,11 @@ 'name' => [], 'login' => [], 'active' => [ - 'pipe' => [ - [ - 'populate' => 'boolval', - 'extract' => 'boolval', - ] - ] + 'pipe-populate' => ['boolval'], + 'pipe-extract' => ['boolval'], ], 'email' => [ - 'pipe' => [ - 'strtolower' - ] + 'pipe-populate' => ['strtolower'], + 'pipe-extract' => ['strtolower'], ], ]; \ No newline at end of file diff --git a/test/unit/data/withRefs.map.php b/test/unit/data/withRefs.map.php index 047bdde..2570115 100644 --- a/test/unit/data/withRefs.map.php +++ b/test/unit/data/withRefs.map.php @@ -8,7 +8,8 @@ 'name' => [], 'login' => [], 'active' => [ - 'pipe' => ['boolval'] + 'pipe-populate' => ['boolval'], + 'pipe-extract' => ['boolval'], ], 'email' => [], 'refModel' => [