Skip to content

Commit 6b9f080

Browse files
authored
Merge pull request #7 from KaririCode-Framework/develop
refactor(AttributeHandler): update handleAttribute to use fallback va…
2 parents 30c6e85 + e6a0db9 commit 6b9f080

File tree

5 files changed

+172
-44
lines changed

5 files changed

+172
-44
lines changed

composer.lock

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/AttributeAnalyzer.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ private function analyzeProperty(object $object, \ReflectionProperty $property):
4444
$property->setAccessible(true);
4545
$propertyValue = $property->getValue($object);
4646

47+
$attributeInstances = array_map(
48+
static fn (\ReflectionAttribute $attr): object => $attr->newInstance(),
49+
$attributes
50+
);
51+
4752
return [
4853
'value' => $propertyValue,
49-
'attributes' => array_map(
50-
static fn (\ReflectionAttribute $attr): object => $attr->newInstance(),
51-
$attributes
52-
),
54+
'attributes' => $attributeInstances,
5355
];
5456
}
5557
}

src/AttributeHandler.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
namespace KaririCode\PropertyInspector;
66

7-
use KaririCode\Contract\Processor\ProcessableAttribute;
7+
use KaririCode\Contract\Processor\Attribute\CustomizableMessageAttribute;
8+
use KaririCode\Contract\Processor\Attribute\ProcessableAttribute;
89
use KaririCode\Contract\Processor\ProcessorBuilder;
910
use KaririCode\ProcessorPipeline\Exception\ProcessingException;
1011
use KaririCode\PropertyInspector\Contract\PropertyAttributeHandler;
@@ -14,6 +15,7 @@
1415
class AttributeHandler implements PropertyAttributeHandler, PropertyChangeApplier
1516
{
1617
private array $processedValues = [];
18+
private array $processingErrors = [];
1719

1820
public function __construct(
1921
private readonly string $processorType,
@@ -27,28 +29,37 @@ public function handleAttribute(string $propertyName, object $attribute, mixed $
2729
return null;
2830
}
2931

32+
$processors = $attribute->getProcessors();
33+
34+
if ($attribute instanceof CustomizableMessageAttribute) {
35+
foreach ($processors as $processorName => &$processorConfig) {
36+
$customMessage = $attribute->getMessage($processorName);
37+
if (null !== $customMessage) {
38+
$processorConfig['customMessage'] = $customMessage;
39+
}
40+
}
41+
unset($processorConfig); // Break the reference after use
42+
}
43+
44+
$pipeline = $this->builder->buildPipeline($this->processorType, $processors);
45+
3046
try {
31-
$pipeline = $this->builder->buildPipeline($this->processorType, $attribute->getProcessors());
3247
$processedValue = $pipeline->process($value);
33-
$this->processedValues[$propertyName][] = $processedValue;
48+
$this->processedValues[$propertyName] = $processedValue;
3449

3550
return $processedValue;
3651
} catch (ProcessingException $e) {
37-
$fallbackValue = $attribute->getFallbackValue() ?? $value;
38-
$this->processedValues[$propertyName][] = $fallbackValue;
52+
$this->processingErrors[$propertyName][] = $e->getMessage();
3953

40-
return $fallbackValue;
54+
return $value; // Return original value in case of processing error
4155
}
4256
}
4357

4458
public function applyChanges(object $entity): void
4559
{
46-
foreach ($this->processedValues as $propertyName => $values) {
47-
if (!empty($values)) {
48-
$finalValue = end($values);
49-
$accessor = new PropertyAccessor($entity, $propertyName);
50-
$accessor->setValue($finalValue);
51-
}
60+
foreach ($this->processedValues as $propertyName => $value) {
61+
$accessor = new PropertyAccessor($entity, $propertyName);
62+
$accessor->setValue($value);
5263
}
5364
$this->processedValues = []; // Clear the processed values after applying
5465
}
@@ -57,4 +68,9 @@ public function getProcessedValues(): array
5768
{
5869
return $this->processedValues;
5970
}
71+
72+
public function getProcessingErrors(): array
73+
{
74+
return $this->processingErrors;
75+
}
6076
}

tests/AttributeHandlerTest.php

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,25 @@
44

55
namespace KaririCode\PropertyInspector\Tests;
66

7+
use KaririCode\Contract\Processor\Attribute\CustomizableMessageAttribute;
8+
use KaririCode\Contract\Processor\Attribute\ProcessableAttribute;
79
use KaririCode\Contract\Processor\Pipeline;
8-
use KaririCode\Contract\Processor\ProcessableAttribute;
910
use KaririCode\Contract\Processor\ProcessorBuilder;
1011
use KaririCode\ProcessorPipeline\Exception\ProcessingException;
1112
use KaririCode\PropertyInspector\AttributeHandler;
13+
use PHPUnit\Framework\MockObject\MockObject;
1214
use PHPUnit\Framework\TestCase;
1315

16+
interface CombinedAttribute extends
17+
ProcessableAttribute,
18+
CustomizableMessageAttribute
19+
{
20+
}
21+
1422
final class AttributeHandlerTest extends TestCase
1523
{
1624
private AttributeHandler $attributeHandler;
17-
private ProcessorBuilder $processorBuilder;
25+
private ProcessorBuilder|MockObject $processorBuilder;
1826

1927
protected function setUp(): void
2028
{
@@ -45,7 +53,7 @@ public function testHandleAttributeProcessesValue(): void
4553
$this->assertSame('processedValue', $result);
4654
}
4755

48-
public function testHandleAttributeReturnsFallbackOnException(): void
56+
public function testHandleAttributeReturnsOriginalValueOnException(): void
4957
{
5058
$mockAttribute = $this->createMock(ProcessableAttribute::class);
5159
$mockPipeline = $this->createMock(Pipeline::class);
@@ -62,17 +70,17 @@ public function testHandleAttributeReturnsFallbackOnException(): void
6270
->method('getProcessors')
6371
->willReturn(['processor1']);
6472

65-
$mockAttribute->expects($this->once())
66-
->method('getFallbackValue')
67-
->willReturn('fallbackValue');
68-
6973
$result = $this->attributeHandler->handleAttribute('testProperty', $mockAttribute, 'initialValue');
70-
$this->assertSame('fallbackValue', $result);
74+
$this->assertSame('initialValue', $result);
75+
76+
$errors = $this->attributeHandler->getProcessingErrors();
77+
$this->assertArrayHasKey('testProperty', $errors);
78+
$this->assertContains('Test exception', $errors['testProperty']);
7179
}
7280

7381
public function testHandleAttributeReturnsNullWhenAttributeNotProcessable(): void
7482
{
75-
$nonProcessableAttribute = new \stdClass(); // Simulate a non-ProcessableAttribute object
83+
$nonProcessableAttribute = new \stdClass();
7684
$result = $this->attributeHandler->handleAttribute('testProperty', $nonProcessableAttribute, 'initialValue');
7785
$this->assertNull($result);
7886
}
@@ -127,6 +135,62 @@ public function testGetProcessedValuesReturnsProcessedData(): void
127135
$processedValues = $this->attributeHandler->getProcessedValues();
128136

129137
$this->assertArrayHasKey('testProperty', $processedValues);
130-
$this->assertSame(['processedValue'], $processedValues['testProperty']);
138+
$this->assertSame('processedValue', $processedValues['testProperty']);
139+
}
140+
141+
public function testHandleAttributeWithCustomizableMessageAttribute(): void
142+
{
143+
// Create a mock of the combined interface
144+
$mockAttribute = $this->createMock(CombinedAttribute::class);
145+
146+
$mockAttribute->method('getProcessors')
147+
->willReturn(['processor1' => ['option' => 'value']]);
148+
149+
$mockAttribute->expects($this->once())
150+
->method('getMessage')
151+
->with('processor1')
152+
->willReturn('Custom message');
153+
154+
$mockPipeline = $this->createMock(Pipeline::class);
155+
$mockPipeline->method('process')->willReturn('processedValue');
156+
157+
$this->processorBuilder->expects($this->once())
158+
->method('buildPipeline')
159+
->with('testProcessor', ['processor1' => ['option' => 'value', 'customMessage' => 'Custom message']])
160+
->willReturn($mockPipeline);
161+
162+
$result = $this->attributeHandler->handleAttribute('testProperty', $mockAttribute, 'initialValue');
163+
$this->assertSame('processedValue', $result);
164+
165+
// Since getProcessors is mocked, we need to simulate the processors array
166+
$processors = ['processor1' => ['option' => 'value', 'customMessage' => 'Custom message']];
167+
168+
$this->assertArrayHasKey('processor1', $processors);
169+
$this->assertArrayHasKey('customMessage', $processors['processor1']);
170+
$this->assertEquals('Custom message', $processors['processor1']['customMessage']);
171+
}
172+
173+
public function testGetProcessingErrors(): void
174+
{
175+
$mockAttribute = $this->createMock(ProcessableAttribute::class);
176+
$mockPipeline = $this->createMock(Pipeline::class);
177+
178+
$mockPipeline->expects($this->once())
179+
->method('process')
180+
->willThrowException(new ProcessingException('Test error'));
181+
182+
$this->processorBuilder->expects($this->once())
183+
->method('buildPipeline')
184+
->willReturn($mockPipeline);
185+
186+
$mockAttribute->expects($this->once())
187+
->method('getProcessors')
188+
->willReturn(['processor1']);
189+
190+
$this->attributeHandler->handleAttribute('testProperty', $mockAttribute, 'initialValue');
191+
$errors = $this->attributeHandler->getProcessingErrors();
192+
193+
$this->assertArrayHasKey('testProperty', $errors);
194+
$this->assertContains('Test error', $errors['testProperty']);
131195
}
132196
}

tests/Utility/PropertyInspectorTest.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,57 @@ public function testInspectWithAnalyzerException(): void
6868

6969
$this->analyzer->expects($this->once())
7070
->method('analyzeObject')
71-
->willThrowException(new PropertyInspectionException('Test exception'));
71+
->willThrowException(new \ReflectionException('Test exception'));
7272

7373
$this->expectException(PropertyInspectionException::class);
74-
$this->expectExceptionMessage('An error occurred during object analysis: Test exception');
74+
$this->expectExceptionMessage('Failed to analyze object: Test exception');
7575

7676
$this->inspector->inspect($object, $mockHandler);
7777
}
78+
79+
public function testInspectWithHandlerReturningNull(): void
80+
{
81+
$object = new \stdClass();
82+
$mockHandler = $this->createMock(PropertyAttributeHandler::class);
83+
84+
$this->analyzer->expects($this->once())
85+
->method('analyzeObject')
86+
->willReturn([
87+
'property1' => [
88+
'value' => 'value1',
89+
'attributes' => [new \stdClass()],
90+
],
91+
]);
92+
93+
$mockHandler->expects($this->once())
94+
->method('handleAttribute')
95+
->willReturn(null);
96+
97+
$result = $this->inspector->inspect($object, $mockHandler);
98+
99+
$this->assertEmpty($result);
100+
}
101+
102+
public function testInspectWithMultipleAttributes(): void
103+
{
104+
$object = new \stdClass();
105+
$mockHandler = $this->createMock(PropertyAttributeHandler::class);
106+
107+
$this->analyzer->expects($this->once())
108+
->method('analyzeObject')
109+
->willReturn([
110+
'property1' => [
111+
'value' => 'value1',
112+
'attributes' => [new \stdClass(), new \stdClass()],
113+
],
114+
]);
115+
116+
$mockHandler->expects($this->exactly(2))
117+
->method('handleAttribute')
118+
->willReturn('handled result');
119+
120+
$result = $this->inspector->inspect($object, $mockHandler);
121+
122+
$this->assertEquals(['property1' => ['handled result', 'handled result']], $result);
123+
}
78124
}

0 commit comments

Comments
 (0)