['innerContent' => ['desktop' => ['value' => 'Müller GmbH'], 'phone' => ['value' => 'Müller']]], 'content' => ['innerContent' => ['desktop' => ['value' => '
Seit 1987: Müller & Söhne. Anruf bei MÜLLER.
']]], 'button' => ['innerContent' => ['desktop' => ['value' => ['text' => 'Müller anrufen', 'linkUrl' => '/mueller-kontakt']]]], 'module' => ['meta' => ['adminLabel' => ['desktop' => ['value' => 'Müller-Hero']]]], 'dyn' => ['innerContent' => ['desktop' => ['value' => '$variable({"type":"content","value":{"name":"Müller","settings":{}}})$']]], ]; private const REF = '$variable({"type":"content","value":{"name":"post_title","settings":{}}})$'; /** @return callable(string, ?string, string): string */ private static function same(): callable { return static fn (string $p, ?string $k, string $v): string => $v; } /** @param arraySeit 1987: Schmidt & Söhne. Anruf bei MÜLLER.
', $result['attrs']['content']['innerContent']['desktop']['value']); self::assertSame(['text' => 'Schmidt anrufen', 'linkUrl' => '/mueller-kontakt'], $result['attrs']['button']['innerContent']['desktop']['value']); self::assertSame('Müller-Hero', $result['attrs']['module']['meta']['adminLabel']['desktop']['value']); self::assertSame(self::ATTRS['dyn'], $result['attrs']['dyn']); self::assertContains('button.innerContent|text', $seen); self::assertSame(['path' => 'button.innerContent.text', 'before' => 'Müller anrufen', 'after' => 'Schmidt anrufen'], $result['samples'][0]); } public function testCaseInsensitiveIncludingUmlauts(): void { $result = (new TextReplacer('müller', 'Schmidt', false))->apply(self::ATTRS, self::same()); self::assertSame(5, $result['count']); self::assertStringContainsString('Anruf bei Schmidt.', $result['attrs']['content']['innerContent']['desktop']['value']); } public function testNothingFound(): void { $result = (new TextReplacer('Meier', 'X'))->apply(self::ATTRS, self::same()); self::assertSame(0, $result['count']); self::assertSame(self::ATTRS, $result['attrs']); } /** Ruling S8: tags with their attributes, entities and references are never touched. */ public function testTagsEntitiesAndReferencesStayUntouched(): void { $value = 'Kontakt & ' . 'kontakt@kunde.test ' . self::REF . ' amp
'; $result = (new TextReplacer('kontakt', 'Anfrage', false))->apply(self::text($value), self::same()); self::assertSame( 'Anfrage & ' . 'Anfrage@kunde.test ' . self::REF . ' amp
', self::valueOf($result['attrs']) ); self::assertSame(2, $result['count']); $entity = (new TextReplacer('amp', 'X'))->apply(self::text($value), self::same()); self::assertStringContainsString('& ', (string) self::valueOf($entity['attrs'])); self::assertStringEndsWith(self::REF . ' X', (string) self::valueOf($entity['attrs'])); self::assertSame(1, $entity['count']); $inside = (new TextReplacer('post_title', 'post_date'))->apply(self::text('Titel: ' . self::REF), self::same()); self::assertSame(0, $inside['count'], 'text inside an embedded reference is not replaced'); } /** Script and style bodies are code, not visible text (D10: never styles). */ public function testScriptAndStyleBodiesAreNotText(): void { $value = 'Müller
' . ' Müller'; $result = (new TextReplacer('Müller', 'Schmidt'))->apply(self::text($value), self::same()); self::assertSame( 'Schmidt
' . ' Schmidt', self::valueOf($result['attrs']) ); self::assertSame(2, $result['count']); $unclosed = (new TextReplacer('Müller', 'Schmidt'))->apply(self::text('