feat: DiviComposition::inLoop() – VariableRef und Placeholders mit Schleifen-Kontext; S31 je Kontext (X3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 20:50:24 +02:00
co-authored by Claude Sonnet 5.5
parent 6da2c0090f
commit 2f484b77ae
2 changed files with 107 additions and 19 deletions
@@ -9,6 +9,7 @@ use LIT\MCP\Integrations\Divi\BlockTree\Block;
use LIT\MCP\Integrations\Divi\BlockTree\Document;
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
use LIT\MCP\Integrations\Divi\Compose\LoopScope;
use LIT\MCP\Integrations\Divi\Compose\StoredNodeGuard;
use LIT\MCP\Integrations\Divi\Compose\TreeEditor;
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
@@ -265,4 +266,46 @@ final class DiviCompositionTest extends TestCase
self::assertCount(1, $covering);
self::assertStringContainsString('„CTA primär“', $covering[0]);
}
/**
* Ruling X3: inLoop() gives a fresh composition bound to a loop scope – placeholders and references of the
* entry's map plus the loop options of that kind; outside a loop and in another kind loop content fails.
*/
public function testInLoopChecksLoopContentAgainstItsScope(): void
{
$post = $this->composition()->forPost(7);
$inPostLoop = $post->inLoop(LoopScope::ofQueryType('post_types'));
$compose = static fn (DiviComposition $composition, string $content = '{{loop:post_title}}'): array => $composition
->composer()->compose(
[['type' => 'text', 'content' => $content]],
Block::create('divi/column'),
'nodes'
);
$inside = $compose($inPostLoop);
self::assertSame([], $inside['errors']);
self::assertSame(
VariableRef::serialize('content', 'loop_post_title', ['before' => '', 'after' => '']),
AttrMap::desktop($inside['blocks'][0]->attrs(), 'content.innerContent')
);
// Placeholders get the loop fields: the short form carries before/after; outside a loop it is refused.
$date = $compose($inPostLoop, '{{loop:post_date}}');
self::assertSame([], $date['errors']);
self::assertStringContainsString(
'loop_post_date',
(string) AttrMap::desktop($date['blocks'][0]->attrs(), 'content.innerContent')
);
self::assertStringContainsString('braucht eine Divi-Schleife', implode(' ', $compose($post, '{{loop:post_date}}')['errors']));
self::assertStringContainsString('braucht eine Divi-Schleife', implode(' ', $compose($post)['errors']));
self::assertStringContainsString(
'passt nicht zur Schleife dieses Elements (Typ: Terme)',
implode(' ', $compose($post->inLoop(LoopScope::ofQueryType('post_taxonomies')))['errors'])
);
self::assertNotSame($post->references(), $inPostLoop->references());
self::assertNotSame($post->placeholders(), $inPostLoop->placeholders());
self::assertSame($inPostLoop->references(), $inPostLoop->references(), 'one VariableRef per scope');
}
}