*/ private array $registryCalls = []; private function composition(): DiviComposition { $modules = Mockery::mock(DiviModules::class); $modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog()); $modules->allows('builderVersion')->andReturn('5.2.1'); $design = Mockery::mock(DesignSystemReader::class); $design->allows('read')->andReturn(DesignSystemTest::sample()); $registry = new DynamicContentMap(function (int $postId): array { $this->registryCalls[] = $postId; return DynamicContentMapTest::registry(); }); return new DiviComposition($modules, $design, ComposeFixture::sanitizer(), ComposeFixture::media(), $registry); } private static function siteTitle(): string { return VariableRef::serialize('content', 'site_title', ['before' => '', 'after' => '']); } public function testOneLiveMapIsSharedByTheFullAndTheShortForm(): void { $composition = $this->composition()->forPost(7); // Full form (AttrWriter). $full = $composition->attrWriter()->apply( 'divi/text', [], ['content.innerContent' => ['desktop' => self::siteTitle()]], 'attrs' ); self::assertSame([], $full['errors']); self::assertSame(self::siteTitle(), AttrMap::desktop($full['attrs'], 'content.innerContent')); // Short form through the Composer (ShortformWriter) – same map, same AttrWriter. $short = $composition->composer()->compose( [['type' => 'button', 'text' => self::siteTitle()]], Block::create('divi/column'), 'nodes' ); self::assertSame([], $short['errors']); self::assertStringContainsString('site_title', json_encode($short['blocks'][0]->attrs(), JSON_THROW_ON_ERROR)); self::assertSame([7], $this->registryCalls, 'the registry is read once per post'); self::assertSame($composition->attrWriter(), $composition->attrWriter()); self::assertSame($composition->placeholders(), $composition->placeholders()); } public function testWithoutAPostTheDefaultMapApplies(): void { $composition = $this->composition(); $result = $composition->attrWriter()->apply( 'divi/text', [], ['content.innerContent' => ['desktop' => self::siteTitle()]], 'attrs' ); self::assertStringContainsString('Unbekannter Name "site_title"', $result['errors']['attrs.content.innerContent']); self::assertSame([], $this->registryCalls); } public function testForPostIsAFreshCompositionPerPost(): void { $base = $this->composition(); $seven = $base->forPost(7); $eight = $base->forPost(8); self::assertNotSame($base, $seven); self::assertNotSame($seven->placeholders(), $eight->placeholders()); self::assertNotSame($base->placeholders(), $seven->placeholders()); self::assertSame([7, 8], $this->registryCalls); } public function testRulesEditorAndWarnings(): void { $composition = $this->composition(); self::assertNull($composition->rules()->violation(Block::create('divi/column'), 'divi/button')); self::assertNotNull($composition->rules()->violation(null, 'divi/button')); self::assertSame([], $composition->warnings()->collect(NodeIndex::build(new Document()), [])); self::assertInstanceOf(TreeEditor::class, $composition->editor()); } }