Skip to content

Commit 84566f7

Browse files
committed
perf(AttributeHandler): optimize performance and memory usage
- Reduce method complexity and function calls - Implement efficient processor caching - Remove unnecessary abstraction layers - Optimize memory allocation and reuse
1 parent 16f1ccd commit 84566f7

11 files changed

+1573
-205
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"phpstan/phpstan": "^1.10",
4646
"phpunit/phpunit": "^11.0",
4747
"squizlabs/php_codesniffer": "^3.9",
48-
"enlightn/security-checker": "^2.0"
48+
"enlightn/security-checker": "^2.0",
49+
"kariricode/validator": "^1.0"
4950
},
5051
"support": {
5152
"issues": "https://github.com/KaririCode-Framework/kariricode-property-inspector/issues",

composer.lock

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

src/AttributeAnalyzer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
use KaririCode\PropertyInspector\Contract\AttributeAnalyzer as AttributeAnalyzerContract;
88
use KaririCode\PropertyInspector\Exception\PropertyInspectionException;
99

10-
final class AttributeAnalyzer implements AttributeAnalyzerContract
10+
final readonly class AttributeAnalyzer implements AttributeAnalyzerContract
1111
{
12-
public function __construct(private readonly string $attributeClass)
12+
public function __construct(private string $attributeClass)
1313
{
1414
}
1515

src/AttributeHandler.php

Lines changed: 49 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use KaririCode\Contract\Processor\Attribute\CustomizableMessageAttribute;
88
use KaririCode\Contract\Processor\Attribute\ProcessableAttribute;
99
use KaririCode\Contract\Processor\ProcessorBuilder;
10+
use KaririCode\Contract\Processor\ProcessorValidator as ProcessorProcessorContract;
11+
use KaririCode\PropertyInspector\Contract\ProcessorConfigBuilder as ProcessorConfigBuilderContract;
1012
use KaririCode\PropertyInspector\Contract\PropertyAttributeHandler;
1113
use KaririCode\PropertyInspector\Contract\PropertyChangeApplier;
1214
use KaririCode\PropertyInspector\Processor\ProcessorConfigBuilder;
@@ -18,12 +20,13 @@ class AttributeHandler implements PropertyAttributeHandler, PropertyChangeApplie
1820
private array $processedPropertyValues = [];
1921
private array $processingResultErrors = [];
2022
private array $processingResultMessages = [];
23+
private array $processorCache = [];
2124

2225
public function __construct(
2326
private readonly string $processorType,
2427
private readonly ProcessorBuilder $builder,
25-
private readonly ProcessorValidator $validator = new ProcessorValidator(),
26-
private readonly ProcessorConfigBuilder $configBuilder = new ProcessorConfigBuilder()
28+
private readonly ProcessorProcessorContract $validator = new ProcessorValidator(),
29+
private readonly ProcessorConfigBuilderContract $configBuilder = new ProcessorConfigBuilder()
2730
) {
2831
}
2932

@@ -33,101 +36,79 @@ public function handleAttribute(string $propertyName, object $attribute, mixed $
3336
return null;
3437
}
3538

36-
$processorsConfig = $this->configBuilder->build($attribute);
37-
$messages = $this->extractCustomMessages($attribute, $processorsConfig);
38-
3939
try {
40-
$processedValue = $this->processValue($value, $processorsConfig);
41-
$errors = $this->validateProcessors($processorsConfig, $messages);
42-
43-
$this->storeProcessedPropertyValue($propertyName, $processedValue, $messages);
44-
45-
if (!empty($errors)) {
46-
$this->storeProcessingResultErrors($propertyName, $errors);
47-
}
48-
49-
return $processedValue;
40+
return $this->processAttribute($propertyName, $attribute, $value);
5041
} catch (\Exception $e) {
51-
$this->storeProcessingResultError($propertyName, $e->getMessage());
42+
$this->processingResultErrors[$propertyName][] = $e->getMessage();
5243

5344
return $value;
5445
}
5546
}
5647

57-
private function validateProcessors(array $processorsConfig, array $messages): array
58-
{
59-
$errors = [];
60-
foreach ($processorsConfig as $processorName => $config) {
61-
$processor = $this->builder->build($this->processorType, $processorName, $config);
62-
$validationError = $this->validator->validate(
63-
$processor,
64-
$processorName,
65-
$messages
66-
);
67-
68-
if ($this->shouldAddValidationError($validationError, $errors, $processorName)) {
69-
$errors[$processorName] = $validationError;
70-
}
71-
}
72-
73-
return $errors;
74-
}
75-
76-
private function shouldAddValidationError(?array $validationError, array $errors, string $processorName): bool
77-
{
78-
return null !== $validationError && !isset($errors[$processorName]);
79-
}
80-
81-
private function storeProcessingResultErrors(string $propertyName, array $errors): void
82-
{
83-
$this->processingResultErrors[$propertyName] = $errors;
84-
}
85-
86-
private function extractCustomMessages(ProcessableAttribute $attribute, array &$processorsConfig): array
48+
private function processAttribute(string $propertyName, ProcessableAttribute $attribute, mixed $value): mixed
8749
{
50+
$config = $this->configBuilder->build($attribute);
8851
$messages = [];
52+
8953
if ($attribute instanceof CustomizableMessageAttribute) {
90-
foreach ($processorsConfig as $processorName => &$config) {
91-
$customMessage = $attribute->getMessage($processorName);
92-
if (null !== $customMessage) {
93-
$config['customMessage'] = $customMessage;
94-
$messages[$processorName] = $customMessage;
54+
foreach ($config as $processorName => &$processorConfig) {
55+
if ($message = $attribute->getMessage($processorName)) {
56+
$processorConfig['customMessage'] = $message;
57+
$messages[$processorName] = $message;
9558
}
9659
}
9760
}
9861

99-
return $messages;
100-
}
101-
102-
private function processValue(mixed $value, array $processorsConfig): mixed
103-
{
104-
$pipeline = $this->builder->buildPipeline(
105-
$this->processorType,
106-
$processorsConfig
107-
);
62+
$processedValue = $this->processValue($value, $config);
10863

109-
return $pipeline->process($value);
110-
}
64+
if ($errors = $this->validateProcessors($config, $messages)) {
65+
$this->processingResultErrors[$propertyName] = $errors;
66+
}
11167

112-
private function storeProcessedPropertyValue(string $propertyName, mixed $processedValue, array $messages): void
113-
{
11468
$this->processedPropertyValues[$propertyName] = [
11569
'value' => $processedValue,
11670
'messages' => $messages,
11771
];
72+
11873
$this->processingResultMessages[$propertyName] = $messages;
74+
75+
return $processedValue;
76+
}
77+
78+
private function validateProcessors(array $processorsConfig, array $messages): array
79+
{
80+
$errors = [];
81+
foreach ($processorsConfig as $processorName => $config) {
82+
// Simplify cache key to processor name
83+
if (!isset($this->processorCache[$processorName])) {
84+
$this->processorCache[$processorName] = $this->builder->build(
85+
$this->processorType,
86+
$processorName,
87+
$config
88+
);
89+
}
90+
91+
$processor = $this->processorCache[$processorName];
92+
93+
if ($error = $this->validator->validate($processor, $processorName, $messages)) {
94+
$errors[$processorName] = $error;
95+
}
96+
}
97+
98+
return $errors;
11999
}
120100

121-
private function storeProcessingResultError(string $propertyName, string $errorMessage): void
101+
private function processValue(mixed $value, array $config): mixed
122102
{
123-
$this->processingResultErrors[$propertyName][] = $errorMessage;
103+
return $this->builder
104+
->buildPipeline($this->processorType, $config)
105+
->process($value);
124106
}
125107

126108
public function applyChanges(object $entity): void
127109
{
128110
foreach ($this->processedPropertyValues as $propertyName => $data) {
129-
$accessor = new PropertyAccessor($entity, $propertyName);
130-
$accessor->setValue($data['value']);
111+
(new PropertyAccessor($entity, $propertyName))->setValue($data['value']);
131112
}
132113
}
133114

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\PropertyInspector\Contract;
6+
7+
use KaririCode\Contract\Processor\Attribute\ProcessableAttribute;
8+
9+
interface ProcessorConfigBuilder
10+
{
11+
/**
12+
* Constrói a configuração dos processadores a partir de um atributo processável.
13+
*
14+
* @param ProcessableAttribute $attribute o atributo que fornece os processadores
15+
*
16+
* @return array a configuração dos processadores
17+
*/
18+
public function build(ProcessableAttribute $attribute): array;
19+
}

src/Processor/ProcessorConfigBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
namespace KaririCode\PropertyInspector\Processor;
66

77
use KaririCode\Contract\Processor\Attribute\ProcessableAttribute;
8+
use KaririCode\PropertyInspector\Contract\ProcessorConfigBuilder as ProcessorConfigBuilderContract;
89

9-
readonly class ProcessorConfigBuilder
10+
readonly class ProcessorConfigBuilder implements ProcessorConfigBuilderContract
1011
{
1112
public function build(ProcessableAttribute $attribute): array
1213
{

0 commit comments

Comments
 (0)