Skip to content

Commit 54c6db4

Browse files
committed
added DomQuery::closest()
1 parent a378fb0 commit 54c6db4

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

src/Framework/DomQuery.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ public function matches(string $selector): bool
112112
}
113113

114114

115+
/**
116+
* Returns closest ancestor matching CSS selector.
117+
*/
118+
public function closest(string $selector): ?self
119+
{
120+
if (PHP_VERSION_ID < 80400) {
121+
throw new \LogicException('Requires PHP 8.4 or newer.');
122+
}
123+
$el = Dom\import_simplexml($this)->closest($selector);
124+
return $el ? simplexml_import_dom($el, self::class) : null;
125+
}
126+
127+
115128
/**
116129
* Converts a CSS selector into an XPath expression.
117130
*/

tests/Framework/DomQuery.fromHtml.84.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ test('matches() checks if element matches selector', function () {
9797
Assert::false($para->matches('.test'));
9898
});
9999

100+
test('closest() finds nearest matching ancestor', function () {
101+
$dom = DomQuery::fromHtml('
102+
<div class="outer">
103+
<div class="middle">
104+
<div class="inner">
105+
<p>Test</p>
106+
</div>
107+
</div>
108+
</div>
109+
');
110+
111+
$p = $dom->find('p')[0];
112+
Assert::type(DomQuery::class, $p->closest('div'));
113+
Assert::true($p->closest('div')->matches('.inner'));
114+
Assert::true($p->closest('.outer')->matches('.outer'));
115+
Assert::null($p->closest('span'));
116+
});
117+
100118
test('find() returns empty array for no matches', function () {
101119
$dom = DomQuery::fromHtml('<div></div>');
102120
Assert::same([], $dom->find('nonexistent'));

0 commit comments

Comments
 (0)