Skip to content

Commit 232e6c5

Browse files
committed
added DomQuery::closest()
1 parent 0460a3f commit 232e6c5

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
@@ -115,6 +115,19 @@ public function matches(string $selector): bool
115115
}
116116

117117

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

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)