Skip to content

Commit 327dac2

Browse files
committed
feat: update data and string processors for enhanced transformation functionality
- Updated `DateTransformer`: - Added `inputFormat`, `outputFormat`, `inputTimezone`, and `outputTimezone` options for flexible date transformation. - Enhanced `JsonTransformer`: - Configurable options `assoc`, `depth`, and `encodeOptions` for JSON encoding and decoding with error handling. - Improved `NumberTransformer`: - Added options for decimal control, multipliers, rounding, and separators for number formatting. - Updated string processors: - `CaseTransformer`: Supports multiple case transformations, including lower, upper, title, sentence, camel, pascal, snake, and kebab cases. - `MaskTransformer`: Allows masking strings with custom patterns and pre-defined types (e.g., phone, CPF, CNPJ). - `SlugTransformer`: Generates slugs with custom separators, lowercase option, and locale-based transliteration. - `TemplateTransformer`: Template replacement with configurable placeholders and support for missing value handlers. - Updated `TransformationResult`: - Implements `TransformationResult` contract with methods for validation, error retrieval, and transformed data handling.
1 parent e22f0d8 commit 327dac2

File tree

8 files changed

+494
-0
lines changed

8 files changed

+494
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\Data;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
10+
class DateTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
11+
{
12+
private string $inputFormat = 'Y-m-d';
13+
private string $outputFormat = 'Y-m-d';
14+
private ?string $inputTimezone = null;
15+
private ?string $outputTimezone = null;
16+
17+
public function configure(array $options): void
18+
{
19+
$this->inputFormat = $options['inputFormat'] ?? $this->inputFormat;
20+
$this->outputFormat = $options['outputFormat'] ?? $this->outputFormat;
21+
$this->inputTimezone = $options['inputTimezone'] ?? $this->inputTimezone;
22+
$this->outputTimezone = $options['outputTimezone'] ?? $this->outputTimezone;
23+
}
24+
25+
public function process(mixed $input): string
26+
{
27+
if (!is_string($input)) {
28+
$this->setInvalid('notString');
29+
30+
return '';
31+
}
32+
33+
try {
34+
$date = $this->createDateTime($input);
35+
36+
return $this->formatDate($date);
37+
} catch (\Exception $e) {
38+
$this->setInvalid('invalidDate');
39+
40+
return '';
41+
}
42+
}
43+
44+
private function createDateTime(string $input): \DateTime
45+
{
46+
$date = \DateTime::createFromFormat($this->inputFormat, $input);
47+
48+
if (false === $date) {
49+
throw new \RuntimeException('Invalid date format');
50+
}
51+
52+
if ($this->inputTimezone) {
53+
$date->setTimezone(new \DateTimeZone($this->inputTimezone));
54+
}
55+
56+
return $date;
57+
}
58+
59+
private function formatDate(\DateTime $date): string
60+
{
61+
if ($this->outputTimezone) {
62+
$date->setTimezone(new \DateTimeZone($this->outputTimezone));
63+
}
64+
65+
return $date->format($this->outputFormat);
66+
}
67+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\Data;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
10+
class JsonTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
11+
{
12+
private bool $assoc = true;
13+
private int $depth = 512;
14+
private int $encodeOptions = 0;
15+
16+
public function configure(array $options): void
17+
{
18+
$this->assoc = $options['assoc'] ?? $this->assoc;
19+
$this->depth = $options['depth'] ?? $this->depth;
20+
$this->encodeOptions = $options['encodeOptions'] ?? $this->encodeOptions;
21+
}
22+
23+
public function process(mixed $input): mixed
24+
{
25+
if (is_string($input)) {
26+
return $this->decode($input);
27+
}
28+
29+
return $this->encode($input);
30+
}
31+
32+
private function decode(string $input): mixed
33+
{
34+
try {
35+
$decoded = json_decode($input, $this->assoc, $this->depth, JSON_THROW_ON_ERROR);
36+
} catch (\JsonException $e) {
37+
$this->setInvalid('invalidJson');
38+
39+
return $this->assoc ? [] : new \stdClass();
40+
}
41+
42+
return $decoded;
43+
}
44+
45+
private function encode(mixed $input): string
46+
{
47+
try {
48+
return json_encode($input, $this->encodeOptions | JSON_THROW_ON_ERROR);
49+
} catch (\JsonException $e) {
50+
$this->setInvalid('unserializable');
51+
52+
return '';
53+
}
54+
}
55+
}
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\Data;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
10+
class NumberTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
11+
{
12+
private int $decimals = 2;
13+
private string $decimalPoint = '.';
14+
private string $thousandsSeparator = '';
15+
private ?float $multiplier = null;
16+
private bool $roundUp = false;
17+
18+
public function configure(array $options): void
19+
{
20+
$this->decimals = $options['decimals'] ?? $this->decimals;
21+
$this->decimalPoint = $options['decimalPoint'] ?? $this->decimalPoint;
22+
$this->thousandsSeparator = $options['thousandsSeparator'] ?? $this->thousandsSeparator;
23+
$this->multiplier = $options['multiplier'] ?? $this->multiplier;
24+
$this->roundUp = $options['roundUp'] ?? $this->roundUp;
25+
}
26+
27+
public function process(mixed $input): string
28+
{
29+
if (!is_numeric($input)) {
30+
$this->setInvalid('notNumeric');
31+
32+
return '';
33+
}
34+
35+
$number = (float) $input;
36+
37+
if (null !== $this->multiplier) {
38+
$number *= $this->multiplier;
39+
}
40+
41+
if ($this->roundUp) {
42+
$number = ceil($number * (10 ** $this->decimals)) / (10 ** $this->decimals);
43+
}
44+
45+
return number_format(
46+
$number,
47+
$this->decimals,
48+
$this->decimalPoint,
49+
$this->thousandsSeparator
50+
);
51+
}
52+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\String;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
use KaririCode\Transformer\Trait\StringTransformerTrait;
10+
11+
class CaseTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
12+
{
13+
use StringTransformerTrait;
14+
15+
private const CASE_LOWER = 'lower';
16+
private const CASE_UPPER = 'upper';
17+
private const CASE_TITLE = 'title';
18+
private const CASE_SENTENCE = 'sentence';
19+
private const CASE_CAMEL = 'camel';
20+
private const CASE_PASCAL = 'pascal';
21+
private const CASE_SNAKE = 'snake';
22+
private const CASE_KEBAB = 'kebab';
23+
24+
private string $case = self::CASE_LOWER;
25+
private bool $preserveNumbers = true;
26+
27+
public function configure(array $options): void
28+
{
29+
if (isset($options['case']) && in_array($options['case'], $this->getAllowedCases(), true)) {
30+
$this->case = $options['case'];
31+
}
32+
$this->preserveNumbers = $options['preserveNumbers'] ?? $this->preserveNumbers;
33+
}
34+
35+
public function process(mixed $input): string
36+
{
37+
if (!is_string($input)) {
38+
$this->setInvalid('notString');
39+
40+
return '';
41+
}
42+
43+
return match ($this->case) {
44+
self::CASE_LOWER => $this->toLowerCase($input),
45+
self::CASE_UPPER => $this->toUpperCase($input),
46+
self::CASE_TITLE => $this->toTitleCase($input),
47+
self::CASE_SENTENCE => $this->toSentenceCase($input),
48+
self::CASE_CAMEL => $this->toCamelCase($input),
49+
self::CASE_PASCAL => $this->toPascalCase($input),
50+
self::CASE_SNAKE => $this->toSnakeCase($input),
51+
self::CASE_KEBAB => $this->toKebabCase($input),
52+
default => $input,
53+
};
54+
}
55+
56+
private function getAllowedCases(): array
57+
{
58+
return [
59+
self::CASE_LOWER,
60+
self::CASE_UPPER,
61+
self::CASE_TITLE,
62+
self::CASE_SENTENCE,
63+
self::CASE_CAMEL,
64+
self::CASE_PASCAL,
65+
self::CASE_SNAKE,
66+
self::CASE_KEBAB,
67+
];
68+
}
69+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KaririCode\Transformer\Processor\String;
6+
7+
use KaririCode\Contract\Processor\ConfigurableProcessor;
8+
use KaririCode\Transformer\Processor\AbstractTransformerProcessor;
9+
use KaririCode\Transformer\Trait\StringTransformerTrait;
10+
11+
class MaskTransformer extends AbstractTransformerProcessor implements ConfigurableProcessor
12+
{
13+
use StringTransformerTrait;
14+
15+
private string $mask = '';
16+
private string $placeholder = '#';
17+
private array $customMasks = [
18+
'phone' => '(##) #####-####',
19+
'cpf' => '###.###.###-##',
20+
'cnpj' => '##.###.###/####-##',
21+
'cep' => '#####-###',
22+
];
23+
24+
public function configure(array $options): void
25+
{
26+
if (isset($options['mask'])) {
27+
$this->mask = $options['mask'];
28+
} elseif (isset($options['type']) && isset($this->customMasks[$options['type']])) {
29+
$this->mask = $this->customMasks[$options['type']];
30+
}
31+
32+
$this->placeholder = $options['placeholder'] ?? $this->placeholder;
33+
34+
if (isset($options['customMasks']) && is_array($options['customMasks'])) {
35+
$this->customMasks = array_merge($this->customMasks, $options['customMasks']);
36+
}
37+
}
38+
39+
public function process(mixed $input): string
40+
{
41+
if (!is_string($input)) {
42+
$this->setInvalid('notString');
43+
44+
return '';
45+
}
46+
47+
if (empty($this->mask)) {
48+
$this->setInvalid('noMask');
49+
50+
return $input;
51+
}
52+
53+
return $this->applyMask($input);
54+
}
55+
56+
private function applyMask(string $input): string
57+
{
58+
$result = '';
59+
$inputPos = 0;
60+
61+
for ($maskPos = 0; $maskPos < strlen($this->mask) && $inputPos < strlen($input); ++$maskPos) {
62+
if ($this->mask[$maskPos] === $this->placeholder) {
63+
$result .= $input[$inputPos];
64+
++$inputPos;
65+
} else {
66+
$result .= $this->mask[$maskPos];
67+
}
68+
}
69+
70+
return $result;
71+
}
72+
}

0 commit comments

Comments
 (0)