Skip to content

Commit e849d75

Browse files
committed
[FEATURE] Add MigrateEmailFlagToEmailTypeFlexFormFractor
1 parent f3ce55b commit e849d75

24 files changed

+695
-44
lines changed

composer.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"eta-orionis/composer-json-manipulator": "^1.0",
1919
"nette/utils": "^4.0",
2020
"sebastian/diff": "^5.0",
21+
"shanethehat/pretty-xml": "^1.0",
2122
"symfony/config": "^6.4",
2223
"symfony/console": "^6.4",
2324
"symfony/dependency-injection": "^6.4",
@@ -93,12 +94,14 @@
9394
"scripts": {
9495
"analyze:php": "phpstan analyze",
9596
"contribute": [
97+
"@merge-composer-json",
9698
"@style:composer:normalize:fix",
97-
"@merge-composer-json"
99+
"@style:php:fix"
98100
],
99101
"merge-composer-json": "monorepo-builder merge",
100102
"rector": "rector",
101103
"style:composer:normalize:fix": [
104+
"@composer normalize --no-check-lock composer.json",
102105
"@composer normalize --no-check-lock e2e/composer.json",
103106
"@composer normalize --no-check-lock packages/extension-installer/composer.json",
104107
"@composer normalize --no-check-lock packages/fractor/composer.json",

packages/fractor-xml/composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"ext-xml": "*",
1717
"a9f/fractor": "^0.2",
1818
"a9f/fractor-extension-installer": "^0.2",
19+
"shanethehat/pretty-xml": "^1.0",
1920
"webmozart/assert": "^1.11"
2021
},
2122
"require-dev": {

packages/fractor-xml/config/application.php

+5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
declare(strict_types=1);
44

5+
use a9f\FractorXml\Contract\Formatter;
56
use a9f\FractorXml\Contract\XmlFractor;
7+
use a9f\FractorXml\PrettyXmlFormatter;
68
use a9f\FractorXml\XmlFileProcessor;
79
use Symfony\Component\DependencyInjection\ContainerBuilder;
810
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
@@ -19,5 +21,8 @@
1921
$services->set(XmlFileProcessor::class)
2022
->arg('$rules', tagged_iterator('fractor.xml_rule'));
2123

24+
$services->set(\PrettyXml\Formatter::class);
25+
$services->alias(Formatter::class, PrettyXmlFormatter::class);
26+
2227
$containerBuilder->registerForAutoconfiguration(XmlFractor::class)->addTag('fractor.xml_rule');
2328
};

packages/fractor-xml/src/AbstractXmlFractor.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212

1313
abstract class AbstractXmlFractor implements DomNodeVisitor, XmlFractor
1414
{
15-
private ?File $file = null;
15+
protected ?File $file = null;
1616

17-
public function beforeTraversal(File $file, \DOMNode $rootNode): void
17+
public function beforeTraversal(File $file, \DOMDocument $rootNode): void
1818
{
1919
$this->file = $file;
2020
}
@@ -41,7 +41,7 @@ public function leaveNode(\DOMNode $node): void
4141
// no-op for now
4242
}
4343

44-
public function afterTraversal(\DOMNode $rootNode): void
44+
public function afterTraversal(\DOMDocument $rootNode): void
4545
{
4646
// no-op for now
4747
}

packages/fractor-xml/src/Contract/DomNodeVisitor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
interface DomNodeVisitor
1414
{
15-
public function beforeTraversal(File $file, \DOMNode $rootNode): void;
15+
public function beforeTraversal(File $file, \DOMDocument $rootNode): void;
1616

1717
/**
1818
* @return \DOMNode|DomDocumentIterator::*
@@ -21,5 +21,5 @@ public function enterNode(\DOMNode $node): \DOMNode|int;
2121

2222
public function leaveNode(\DOMNode $node): void;
2323

24-
public function afterTraversal(\DOMNode $rootNode): void;
24+
public function afterTraversal(\DOMDocument $rootNode): void;
2525
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorXml\Contract;
6+
7+
use a9f\Fractor\ValueObject\Indent;
8+
9+
interface Formatter
10+
{
11+
public function format(Indent $indent, string $content): string;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorXml;
6+
7+
use a9f\Fractor\ValueObject\Indent;
8+
use a9f\FractorXml\Contract\Formatter;
9+
10+
final readonly class PrettyXmlFormatter implements Formatter
11+
{
12+
public function __construct(
13+
private \PrettyXml\Formatter $prettyXmlFormatter
14+
) {
15+
}
16+
17+
public function format(Indent $indent, string $content): string
18+
{
19+
$indentCharacter = $indent->isSpace() ? Indent::CHARACTERS[Indent::STYLE_SPACE] : Indent::CHARACTERS[Indent::STYLE_TAB];
20+
$this->prettyXmlFormatter->setIndentCharacter($indentCharacter);
21+
$this->prettyXmlFormatter->setIndentSize($indent->length());
22+
23+
return $this->prettyXmlFormatter->format($content);
24+
}
25+
}

packages/fractor-xml/src/XmlFileProcessor.php

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use a9f\Fractor\Application\Contract\FileProcessor;
88
use a9f\Fractor\Application\ValueObject\File;
99
use a9f\Fractor\Exception\ShouldNotHappenException;
10+
use a9f\Fractor\ValueObject\Indent;
11+
use a9f\FractorXml\Contract\Formatter;
1012
use a9f\FractorXml\Contract\XmlFractor;
1113
use a9f\FractorXml\ValueObjectFactory\DomDocumentFactory;
1214

@@ -20,6 +22,7 @@
2022
*/
2123
public function __construct(
2224
private DomDocumentFactory $domDocumentFactory,
25+
private Formatter $formatter,
2326
private iterable $rules
2427
) {
2528
}
@@ -43,6 +46,9 @@ public function handle(File $file, iterable $appliedRules): void
4346

4447
$newXml = $this->saveXml($document);
4548

49+
// TODO make the indentation configurable in fractor config
50+
$newXml = $this->formatter->format(Indent::fromSizeAndStyle(4, Indent::STYLE_SPACE), $newXml);
51+
4652
if ($newXml === $originalXml) {
4753
return;
4854
}

packages/fractor-xml/tests/DomDocumentIteratorTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public function __construct(
231231
) {
232232
}
233233

234-
public function beforeTraversal(File $file, \DOMNode $rootNode): void
234+
public function beforeTraversal(File $file, \DOMDocument $rootNode): void
235235
{
236236
$this->calls[] = sprintf('%s:beforeTraversal:%s', $this->visitorName, $rootNode->nodeName);
237237
}
@@ -247,7 +247,7 @@ public function leaveNode(\DOMNode $node): void
247247
$this->calls[] = sprintf('%s:leaveNode:%s', $this->visitorName, $node->nodeName);
248248
}
249249

250-
public function afterTraversal(\DOMNode $rootNode): void
250+
public function afterTraversal(\DOMDocument $rootNode): void
251251
{
252252
$this->calls[] = sprintf('%s:afterTraversal:%s', $this->visitorName, $rootNode->nodeName);
253253
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\Fractor\Helper;
6+
7+
class ArrayUtility
8+
{
9+
/**
10+
* @return string[]
11+
*
12+
* @see GeneralUtility::trimExplode in TYPO3 Core
13+
*/
14+
public static function trimExplode(string $delimiter, string $string, bool $removeEmptyValues = false): array
15+
{
16+
if ($delimiter === '') {
17+
throw new \InvalidArgumentException('Please define a correct delimiter');
18+
}
19+
20+
$result = explode($delimiter, $string);
21+
22+
if ($removeEmptyValues) {
23+
$temp = [];
24+
foreach ($result as $value) {
25+
if (trim($value) !== '') {
26+
$temp[] = $value;
27+
}
28+
}
29+
30+
$result = $temp;
31+
}
32+
33+
return array_map('trim', $result);
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\Fractor\Helper;
6+
7+
class StringUtility
8+
{
9+
/**
10+
* Check if an item exists in a comma-separated list of items.
11+
*
12+
* @param string $list Comma-separated list of items (string)
13+
* @param string $item Item to check for
14+
* @return bool TRUE if $item is in $list
15+
*
16+
* @see GeneralUtility::inList in TYPO3 Core
17+
*/
18+
public static function inList(string $list, string $item): bool
19+
{
20+
return str_contains(',' . $list . ',', ',' . $item . ',');
21+
}
22+
}

packages/fractor/src/ValueObject/Indent.php

+10-3
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@
1212
*/
1313
final readonly class Indent
1414
{
15+
public const STYLE_SPACE = 'space';
16+
17+
public const STYLE_TAB = 'tab';
18+
1519
/**
1620
* @var array<string, string>
1721
*/
1822
public const CHARACTERS = [
19-
'space' => ' ',
20-
'tab' => "\t",
23+
self::STYLE_SPACE => ' ',
24+
self::STYLE_TAB => "\t",
2125
];
2226

2327
private function __construct(
@@ -49,7 +53,10 @@ public function length(): int
4953
return strlen($this->value);
5054
}
5155

52-
private static function fromSizeAndStyle(int $size, string $style): self
56+
/**
57+
* @phpstan-param self::STYLE_* $style
58+
*/
59+
public static function fromSizeAndStyle(int $size, string $style): self
5360
{
5461
Assert::greaterThanEq($size, 1);
5562
Assert::keyExists(self::CHARACTERS, $style);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\Fractor\Tests\Helper;
6+
7+
use a9f\Fractor\Helper\ArrayUtility;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\Attributes\Test;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class ArrayUtilityTest extends TestCase
13+
{
14+
/**
15+
* @param string[] $expectedResult
16+
*/
17+
#[DataProvider('trimExplodeReturnsCorrectResultDataProvider')]
18+
#[Test]
19+
public function trimExplodeReturnsCorrectResult(
20+
string $delimiter,
21+
string $testString,
22+
bool $removeEmpty,
23+
array $expectedResult
24+
): void {
25+
self::assertSame($expectedResult, ArrayUtility::trimExplode($delimiter, $testString, $removeEmpty));
26+
}
27+
28+
/**
29+
* @return array<string, array{0: string, 1: string, 2:bool, 3:array<string>}>
30+
*/
31+
public static function trimExplodeReturnsCorrectResultDataProvider(): array
32+
{
33+
return [
34+
'spaces at element start and end' => [
35+
',',
36+
' a , b , c ,d ,, e,f,',
37+
false,
38+
['a', 'b', 'c', 'd', '', 'e', 'f', ''],
39+
],
40+
'removes newline' => [',', ' a , b , ' . chr(10) . ' ,d ,, e,f,', true, ['a', 'b', 'd', 'e', 'f']],
41+
'removes empty elements' => [',', 'a , b , c , ,d ,, ,e,f,', true, ['a', 'b', 'c', 'd', 'e', 'f']],
42+
'keeps zero as string' => [
43+
',',
44+
'a , b , c , ,d ,, ,e,f, 0 ,',
45+
true,
46+
['a', 'b', 'c', 'd', 'e', 'f', '0'],
47+
],
48+
'keeps whitespace inside elements' => [
49+
',',
50+
'a , b , c , ,d ,, ,e,f, g h ,',
51+
true,
52+
['a', 'b', 'c', 'd', 'e', 'f', 'g h'],
53+
],
54+
'can use internal regex delimiter as explode delimiter' => [
55+
'/',
56+
'a / b / c / /d // /e/f/ g h /',
57+
true,
58+
['a', 'b', 'c', 'd', 'e', 'f', 'g h'],
59+
],
60+
'can use whitespaces as delimiter' => [' ', '* * * * *', true, ['*', '*', '*', '*', '*']],
61+
'can use words as delimiter' => ['All', 'HelloAllTogether', true, ['Hello', 'Together']],
62+
'can use word with appended and prepended spaces as delimiter' => [
63+
' all ',
64+
'Hello all together',
65+
true,
66+
['Hello', 'together'],
67+
],
68+
'can use word with appended and prepended spaces as delimiter and do not remove empty' => [
69+
' all ',
70+
'Hello all together all there all all are all none',
71+
false,
72+
['Hello', 'together', 'there', '', 'are', 'none'],
73+
],
74+
'can use words as delimiter and do not remove empty' => [
75+
'all there',
76+
'Helloall theretogether all there all there are all there none',
77+
false,
78+
['Hello', 'together', '', 'are', 'none'],
79+
],
80+
'can use words as delimiter, remove empty' => [
81+
'all there',
82+
'Helloall theretogether all there all there are all there none',
83+
true,
84+
['Hello', 'together', 'are', 'none'],
85+
],
86+
'can use new line as delimiter' => [
87+
chr(10),
88+
"Hello\nall\ntogether",
89+
true,
90+
['Hello', 'all', 'together'],
91+
],
92+
'works with whitespace separator' => [
93+
"\t",
94+
" a b \t c \t \t d \t e \t u j \t s",
95+
false,
96+
['a b', 'c', '', 'd', 'e', 'u j', 's'],
97+
],
98+
'works with whitespace separator and remove empty' => [
99+
"\t",
100+
" a b \t c \t \t d \t e \t u j \t s",
101+
true,
102+
['a b', 'c', 'd', 'e', 'u j', 's'],
103+
],
104+
];
105+
}
106+
}

0 commit comments

Comments
 (0)