Skip to content

Commit 9fdb29f

Browse files
committed
SmartNull: noEncode() and the other SmartString shims no longer fatal on missing keys
- noEncode/toString/jsEncode/stripTags only exist inside SmartString's __call, so method_exists() couldn't see them and missing keys threw an undefined-method Error - worked on every populated row, fataled only when the field was missing or the result set empty - now delegates them by name and answers like a present null value, deprecations still log - the name list mirrors SmartString's - comments on both sides say to keep them in sync
1 parent e9d499d commit 9fdb29f

2 files changed

Lines changed: 33 additions & 2 deletions

File tree

src/SmartNull.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,15 @@ public function __call($name, array $arguments): mixed
306306
// so it's rarely called. And caching the method names breaks mixed-case calls:
307307
// PHP doesn't care that it's ->dateFormat() not ->dateformat(), but an isset()
308308
// lookup would.
309+
// The in_array list mirrors the deprecated shims in SmartString::__call, which
310+
// method_exists() can't see. Keep both sites in sync: when SmartString drops a
311+
// shim, drop it here too.
309312
$isSmartStringMethod = $this->useSmartStrings
310313
&& $name !== 'getIterator'
311-
&& method_exists(SmartString::class, $name)
312-
&& (new ReflectionMethod(SmartString::class, $name))->isPublic();
314+
&& (
315+
(method_exists(SmartString::class, $name) && (new ReflectionMethod(SmartString::class, $name))->isPublic())
316+
|| in_array(strtolower($name), ['noencode', 'tostring', 'jsencode', 'striptags'], true)
317+
);
313318

314319
if ($isSmartStringMethod) {
315320
if ($name === 'map' || $name === 'apply') {

tests/Unit/SmartNullTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,32 @@ public function testApplyAliasPropagatesLikeMapInHtmlMode(): void
307307
$this->assertSame('n/a', $smartNull->apply('strtoupper')->or('n/a')->value(), 'chain stays open after apply');
308308
}
309309

310+
public function testDeprecatedSmartStringShimsWorkOnMissingKeysInHtmlMode(): void
311+
{
312+
// noEncode/toString/jsEncode/stripTags only exist inside SmartString's
313+
// __call, which method_exists() can't see, so they need their own list in
314+
// SmartNull::__call. Each one answers like it would on a present null
315+
// value and logs its normal deprecation instead of throwing.
316+
$smartNull = $this->smartNullFrom(SmartArrayHtml::class);
317+
318+
[$result, $messages] = $this->captureDeprecations(fn() => $smartNull->noEncode());
319+
$this->assertNull($result, 'noEncode() returns null, same as on a present null value');
320+
$this->assertCount(1, $messages);
321+
$this->assertStringContainsString('rawHtml()', $messages[0]);
322+
323+
[$result, $messages] = $this->captureDeprecations(fn() => $smartNull->toString());
324+
$this->assertSame('', $result);
325+
$this->assertCount(1, $messages);
326+
327+
[$result, $messages] = $this->captureDeprecations(fn() => $smartNull->jsEncode());
328+
$this->assertSame('', $result);
329+
$this->assertCount(1, $messages);
330+
331+
[$result, $messages] = $this->captureDeprecations(fn() => $smartNull->stripTags());
332+
$this->assertSame($smartNull, $result, 'stripTags() propagates, chain stays open');
333+
$this->assertCount(1, $messages);
334+
}
335+
310336
public function testMapStillRunsOnAKeyThatExistsWithANullValue(): void
311337
{
312338
// The boundary map() propagation must not cross: NULL is a present value

0 commit comments

Comments
 (0)