Skip to content

Commit 6c4bbd7

Browse files
committed
feat: add Transformer contract and enhance composite processors
- Added `Transformer` contract in `src/Contract/Transformer.php`: - Defines the core interface for all transformers, ensuring consistency across implementations. - Updated `ChainTransformer`: - Enhanced chaining mechanism for sequential processing of transformations. - Improved error handling and data validation during transformation chain execution. - Improved `ConditionalTransformer`: - Added conditional checks to apply transformations based on configurable criteria. - Enhanced logic for validating conditions before executing transformations. - Modified main `Transformer` class in `src/Transformer.php`: - Integrated `Transformer` contract to standardize transformation behavior. - Streamlined method signatures and added additional validation for consistent data processing.
1 parent 327dac2 commit 6c4bbd7

File tree

4 files changed

+222
-0
lines changed

4 files changed

+222
-0
lines changed

src/Contract/Transformer.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Contract\Transformer;
6+
7+
use KaririCode\Transformer\Result\TransformationResult;
8+
9+
interface Transformer
10+
{
11+
public function transform(mixed $object): TransformationResult;
12+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\Composite;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
10+
class ChainTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
11+
{
12+
/** @var array<AbstractTransformerProcessor> */
13+
private array $transformers = [];
14+
15+
private bool $stopOnError = true;
16+
17+
public function configure(array $options): void
18+
{
19+
if (isset($options['transformers']) && is_array($options['transformers'])) {
20+
foreach ($options['transformers'] as $transformer) {
21+
if ($transformer instanceof AbstractTransformerProcessor) {
22+
$this->transformers[] = $transformer;
23+
}
24+
}
25+
}
26+
27+
$this->stopOnError = $options['stopOnError'] ?? $this->stopOnError;
28+
}
29+
30+
public function process(mixed $input): mixed
31+
{
32+
$result = $input;
33+
34+
foreach ($this->transformers as $transformer) {
35+
try {
36+
$result = $transformer->process($result);
37+
38+
if (!$transformer->isValid() && $this->stopOnError) {
39+
$this->setInvalid($transformer->getErrorKey());
40+
break;
41+
}
42+
} catch (\Exception $e) {
43+
if ($this->stopOnError) {
44+
$this->setInvalid('transformationError');
45+
break;
46+
}
47+
}
48+
}
49+
50+
return $result;
51+
}
52+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\Composite;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
10+
class ConditionalTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
11+
{
12+
private ?AbstractTransformerProcessor $transformer = null;
13+
private ?callable $condition = null;
14+
private mixed $defaultValue = null;
15+
private bool $useDefaultOnError = true;
16+
17+
public function configure(array $options): void
18+
{
19+
if (!isset($options['transformer']) || !$options['transformer'] instanceof AbstractTransformerProcessor) {
20+
throw new \InvalidArgumentException('A valid transformer must be provided');
21+
}
22+
23+
if (!isset($options['condition']) || !is_callable($options['condition'])) {
24+
throw new \InvalidArgumentException('A valid condition callback must be provided');
25+
}
26+
27+
$this->transformer = $options['transformer'];
28+
$this->condition = $options['condition'];
29+
$this->defaultValue = $options['defaultValue'] ?? $this->defaultValue;
30+
$this->useDefaultOnError = $options['useDefaultOnError'] ?? $this->useDefaultOnError;
31+
}
32+
33+
public function process(mixed $input): mixed
34+
{
35+
if (!$this->shouldTransform($input)) {
36+
return $this->defaultValue ?? $input;
37+
}
38+
39+
try {
40+
$result = $this->transformer->process($input);
41+
42+
if (!$this->transformer->isValid() && $this->useDefaultOnError) {
43+
$this->setInvalid($this->transformer->getErrorKey());
44+
return $this->defaultValue ?? $input;
45+
}
46+
47+
return $result;
48+
} catch (\Exception $e) {
49+
$this->setInvalid('transformationError');
50+
return $this->defaultValue ?? $input;
51+
}
52+
}
53+
54+
private function shouldTransform(mixed $input): bool
55+
{
56+
try {
57+
return call_user_func($this->condition, $input);
58+
} catch (\Exception $e) {
59+
return false;
60+
}
61+
}
62+
}

src/Transformer.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer;
6+
7+
use KaririCode\Contract\Processor\ProcessorRegistry;
8+
use KaririCode\Contract\Transformer\Transformer as TransformerContract;
9+
use KaririCode\ProcessorPipeline\Handler\ProcessorAttributeHandler;
10+
use KaririCode\ProcessorPipeline\ProcessorBuilder;
11+
use KaririCode\PropertyInspector\AttributeAnalyzer;
12+
use KaririCode\PropertyInspector\Utility\PropertyInspector;
13+
use KaririCode\Transformer\Attribute\Transform;
14+
use KaririCode\Transformer\Result\TransformationResult;
15+
16+
final class Transformer implements TransformerContract
17+
{
18+
private const IDENTIFIER = 'transformer';
19+
20+
private readonly ProcessorBuilder $builder;
21+
22+
public function __construct(
23+
private readonly ProcessorRegistry $registry
24+
) {
25+
$this->builder = new ProcessorBuilder($this->registry);
26+
}
27+
28+
public function transform(mixed $object): TransformationResult
29+
{
30+
$handler = new ProcessorAttributeHandler(
31+
self::IDENTIFIER,
32+
$this->builder
33+
);
34+
35+
$propertyInspector = new PropertyInspector(
36+
new AttributeAnalyzer(Transform::class)
37+
);
38+
39+
/** @var ProcessorAttributeHandler */
40+
$handler = $propertyInspector->inspect($object, $handler);
41+
$handler->applyChanges($object);
42+
43+
return new TransformationResult(
44+
$handler->getProcessingResults()
45+
);
46+
}
47+
}
48+
49+
namespace KaririCode\Transformer\Processor\Composite;
50+
51+
use KaririCode\Contract\Processor\ConfigurableProcessor;
52+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
53+
54+
class ChainTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
55+
{
56+
/** @var array<AbstractTransformerProcessor> */
57+
private array $transformers = [];
58+
59+
private bool $stopOnError = true;
60+
61+
public function configure(array $options): void
62+
{
63+
if (isset($options['transformers']) && is_array($options['transformers'])) {
64+
foreach ($options['transformers'] as $transformer) {
65+
if ($transformer instanceof AbstractTransformerProcessor) {
66+
$this->transformers[] = $transformer;
67+
}
68+
}
69+
}
70+
71+
$this->stopOnError = $options['stopOnError'] ?? $this->stopOnError;
72+
}
73+
74+
public function process(mixed $input): mixed
75+
{
76+
$result = $input;
77+
78+
foreach ($this->transformers as $transformer) {
79+
try {
80+
$result = $transformer->process($result);
81+
82+
if (!$transformer->isValid() && $this->stopOnError) {
83+
$this->setInvalid($transformer->getErrorKey());
84+
break;
85+
}
86+
} catch (\Exception $e) {
87+
if ($this->stopOnError) {
88+
$this->setInvalid('transformationError');
89+
break;
90+
}
91+
}
92+
}
93+
94+
return $result;
95+
}
96+
}

0 commit comments

Comments
 (0)