Skip to content

Commit 3c5bdbd

Browse files
stloydnorberttech
authored andcommitted
Add a new DOMElementNextSibling & DOMElementPreviousSibling
1 parent dd63b4b commit 3c5bdbd

File tree

7 files changed

+172
-27
lines changed

7 files changed

+172
-27
lines changed

src/core/etl/src/Flow/ETL/Function/DOM/ElementSibling.php

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/core/etl/src/Flow/ETL/Function/DOMElementSibling.php renamed to src/core/etl/src/Flow/ETL/Function/DOMElementNextSibling.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66

77
use function Flow\Types\DSL\type_instance_of;
88
use Dom\{CharacterData, HTMLElement};
9-
use Flow\ETL\{Exception\InvalidArgumentException, FlowContext, Function\DOM\ElementSibling, Row};
9+
use Flow\ETL\{Exception\InvalidArgumentException, FlowContext, Row};
1010

11-
final class DOMElementSibling extends ScalarFunctionChain
11+
final class DOMElementNextSibling extends ScalarFunctionChain
1212
{
1313
public function __construct(
1414
private readonly ScalarFunction|\DOMNode|CharacterData|HTMLElement $element,
15-
private readonly ElementSibling $sibling,
1615
private readonly bool $allowOnlyElement,
1716
) {
1817
}
@@ -40,17 +39,17 @@ public function eval(Row $row, FlowContext $context) : \DOMNode|CharacterData|HT
4039

4140
if ($this->allowOnlyElement) {
4241
if (!$node instanceof \DOMElement) {
43-
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementSibling with option $allowOnlyElement requires DOMElement.'));
42+
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementNextSibling with option $allowOnlyElement requires DOMElement.'));
4443
}
4544

4645
if ($node instanceof CharacterData) {
47-
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementSibling with option $allowOnlyElement requires HTMLElement.'));
46+
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementNextSibling with option $allowOnlyElement requires HTMLElement.'));
4847
}
4948

50-
return $this->sibling === ElementSibling::NEXT ? $node->nextElementSibling : $node->previousElementSibling;
49+
return $node->nextElementSibling;
5150
}
5251

5352
/* @phpstan-ignore-next-line */
54-
return $this->sibling === ElementSibling::NEXT ? $node->nextSibling : $node->previousSibling;
53+
return $node->nextSibling;
5554
}
5655
}
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 Flow\ETL\Function;
6+
7+
use function Flow\Types\DSL\type_instance_of;
8+
use Dom\{CharacterData, HTMLElement};
9+
use Flow\ETL\{Exception\InvalidArgumentException, FlowContext, Row};
10+
11+
final class DOMElementPreviousSibling extends ScalarFunctionChain
12+
{
13+
public function __construct(
14+
private readonly ScalarFunction|\DOMNode|CharacterData|HTMLElement $element,
15+
private readonly bool $allowOnlyElement,
16+
) {
17+
}
18+
19+
public function eval(Row $row, FlowContext $context) : \DOMNode|CharacterData|HTMLElement|null
20+
{
21+
$types = [
22+
type_instance_of(\DOMNode::class),
23+
];
24+
25+
if (\class_exists('\Dom\HTMLElement')) {
26+
$types[] = type_instance_of(CharacterData::class);
27+
$types[] = type_instance_of(HTMLElement::class);
28+
}
29+
30+
$node = (new Parameter($this->element))->as(
31+
$row,
32+
$context,
33+
...$types
34+
);
35+
36+
if ($node instanceof \DOMDocument) {
37+
$node = $node->documentElement;
38+
}
39+
40+
if ($this->allowOnlyElement) {
41+
if (!$node instanceof \DOMElement) {
42+
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementPreviousSibling with option $allowOnlyElement requires DOMElement.'));
43+
}
44+
45+
if ($node instanceof CharacterData) {
46+
return $context->functions()->invalidResult(new InvalidArgumentException('DOMElementPreviousSibling with option $allowOnlyElement requires HTMLElement.'));
47+
}
48+
49+
return $node->previousElementSibling;
50+
}
51+
52+
/* @phpstan-ignore-next-line */
53+
return $node->previousSibling;
54+
}
55+
}

src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use Flow\ETL\Function\ArrayExpand\ArrayExpand;
1212
use Flow\ETL\Function\ArraySort\Sort;
1313
use Flow\ETL\Function\Between\Boundary;
14-
use Flow\ETL\Function\DOM\ElementSibling;
1514
use Flow\ETL\Function\StyleConverter\StringStyles as OldStringStyles;
1615
use Flow\ETL\Hash\{Algorithm, NativePHPHash};
1716
use Flow\ETL\String\StringStyles;
@@ -242,14 +241,19 @@ public function domElementAttributeValue(ScalarFunction|string $attribute) : DOM
242241
return new DOMElementAttributeValue($this, $attribute);
243242
}
244243

244+
public function domElementNextSibling(bool $allowOnlyElement = false) : DOMElementNextSibling
245+
{
246+
return new DOMElementNextSibling($this, $allowOnlyElement);
247+
}
248+
245249
public function domElementParent() : DOMElementParent
246250
{
247251
return new DOMElementParent($this);
248252
}
249253

250-
public function domElementSibling(ElementSibling $sibling, bool $allowOnlyElement = false) : DOMElementSibling
254+
public function domElementPreviousSibling(bool $allowOnlyElement = false) : DOMElementPreviousSibling
251255
{
252-
return new DOMElementSibling($this, $sibling, $allowOnlyElement);
256+
return new DOMElementPreviousSibling($this, $allowOnlyElement);
253257
}
254258

255259
public function domElementValue() : DOMElementValue

src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementSiblingTest.php renamed to src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementNextSiblingTest.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
namespace Flow\ETL\Tests\Integration\Function;
66

77
use function Flow\ETL\DSL\{df, from_rows, html_element_entry, ref, row, rows, xml_element_entry};
8-
use Flow\ETL\Function\DOM\ElementSibling;
98
use Flow\ETL\Tests\FlowTestCase;
109
use PHPUnit\Framework\Attributes\RequiresPhp;
1110

12-
final class DOMElementSiblingTest extends FlowTestCase
11+
final class DOMElementNextSiblingTest extends FlowTestCase
1312
{
1413
#[RequiresPhp('>= 8.4')]
1514
public function test_dom_element_sibling_text_value() : void
@@ -24,7 +23,7 @@ public function test_dom_element_sibling_text_value() : void
2423
))
2524
->withEntry('user_details', ref('html_element')->htmlQuerySelector('section'))
2625
->withEntry('user_name', ref('user_details')->htmlQuerySelector('h1')->domElementValue())
27-
->withEntry('user_id', ref('user_details')->domElementSibling(ElementSibling::NEXT)->domElementValue())
26+
->withEntry('user_id', ref('user_details')->domElementNextSibling()->domElementValue())
2827
->select('user_name', 'user_id')
2928
->fetch();
3029

@@ -52,7 +51,7 @@ public function test_dom_element_sibling_text_value_when_only_element_is_allowed
5251
))
5352
->withEntry('user_details', ref('html_element')->htmlQuerySelector('section'))
5453
->withEntry('user_name', ref('user_details')->htmlQuerySelector('h1')->domElementValue())
55-
->withEntry('user_id', ref('user_details')->domElementSibling(ElementSibling::NEXT, true)->domElementValue())
54+
->withEntry('user_id', ref('user_details')->domElementNextSibling(true)->domElementValue())
5655
->select('user_name', 'user_id')
5756
->fetch();
5857

@@ -83,7 +82,7 @@ public function test_xml_sibling_element_value() : void
8382
)
8483
)
8584
->withEntry('user_name', ref('xml_element')->domElementValue())
86-
->withEntry('user_id', ref('xml_element')->domElementSibling(ElementSibling::NEXT)->domElementValue())
85+
->withEntry('user_id', ref('xml_element')->domElementNextSibling()->domElementValue())
8786
->select('user_name', 'user_id')
8887
->fetch();
8988

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flow\ETL\Tests\Integration\Function;
6+
7+
use function Flow\ETL\DSL\{df, from_rows, html_element_entry, ref, row, rows, xml_element_entry};
8+
use Flow\ETL\Tests\FlowTestCase;
9+
use PHPUnit\Framework\Attributes\RequiresPhp;
10+
11+
final class DOMElementPreviousSiblingTest extends FlowTestCase
12+
{
13+
#[RequiresPhp('>= 8.4')]
14+
public function test_dom_element_sibling_text_value() : void
15+
{
16+
$rows = df()
17+
->read(from_rows(
18+
rows(
19+
row(
20+
html_element_entry('html_element', '<article>01<section><h1>User Name</h1></section></article>')
21+
)
22+
)
23+
))
24+
->withEntry('user_details', ref('html_element')->htmlQuerySelector('section'))
25+
->withEntry('user_name', ref('user_details')->htmlQuerySelector('h1')->domElementValue())
26+
->withEntry('user_id', ref('user_details')->domElementPreviousSibling()->domElementValue())
27+
->select('user_name', 'user_id')
28+
->fetch();
29+
30+
self::assertSame(
31+
[
32+
[
33+
'user_name' => 'User Name',
34+
'user_id' => '01',
35+
],
36+
],
37+
$rows->toArray()
38+
);
39+
}
40+
41+
#[RequiresPhp('>= 8.4')]
42+
public function test_dom_element_sibling_text_value_when_only_element_is_allowed() : void
43+
{
44+
$rows = df()
45+
->read(from_rows(
46+
rows(
47+
row(
48+
html_element_entry('html_element', '<article>01<section><h1>User Name</h1></section></article>')
49+
)
50+
)
51+
))
52+
->withEntry('user_details', ref('html_element')->htmlQuerySelector('section'))
53+
->withEntry('user_name', ref('user_details')->htmlQuerySelector('h1')->domElementValue())
54+
->withEntry('user_id', ref('user_details')->domElementPreviousSibling(true)->domElementValue())
55+
->select('user_name', 'user_id')
56+
->fetch();
57+
58+
self::assertSame(
59+
[
60+
[
61+
'user_name' => 'User Name',
62+
'user_id' => null,
63+
],
64+
],
65+
$rows->toArray()
66+
);
67+
}
68+
69+
public function test_xml_sibling_element_value() : void
70+
{
71+
$dom = new \DOMDocument();
72+
$dom->loadXML('<user><name>User Name</name><number>01</number></user>');
73+
74+
$rows = df()
75+
->read(
76+
from_rows(
77+
rows(
78+
row(
79+
xml_element_entry('xml_element', $dom->getElementsByTagName('number')->item(0))
80+
)
81+
)
82+
)
83+
)
84+
->withEntry('user_id', ref('xml_element')->domElementValue())
85+
->withEntry('user_name', ref('xml_element')->domElementPreviousSibling()->domElementValue())
86+
->select('user_name', 'user_id')
87+
->fetch();
88+
89+
self::assertSame(
90+
[
91+
[
92+
'user_name' => 'User Name',
93+
'user_id' => '01',
94+
],
95+
],
96+
$rows->toArray()
97+
);
98+
}
99+
}

web/landing/resources/api.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)