Worked extension examples
These developer-facing recipes are kept beside the package contract. Replace the example values with the site-specific records and data objects used by the calling workflow.
<?phpdeclare(strict_types=1);final class ExamplePublicLayoutWidgetAssetsRendererImplementation implements \Capell\LayoutBuilder\Contracts\Assets\PublicLayoutWidgetAssetsRenderer{ /** * @param array<string, mixed> $widgetData * @param array<string, mixed> $options */ public function render(mixed $widget, string $containerKey, array $widgetData = [], mixed $widgetAssets = null, mixed $widgetAssetsByWidget = null, array $options = []): string { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\Assets\PublicLayoutWidgetAssetsRenderer::class, ExamplePublicLayoutWidgetAssetsRendererImplementation::class);<?phpdeclare(strict_types=1);final class ExampleLayoutContainerSchemaExtenderImplementation implements \Capell\LayoutBuilder\Contracts\Extenders\LayoutContainerSchemaExtender{ public function themeKey(): string { throw new LogicException('Implement this package contract for the calling site.'); } public function themeLabel(): string { throw new LogicException('Implement this package contract for the calling site.'); } public function supports(\Capell\LayoutBuilder\Data\LayoutContainerSchemaContextData $context): bool { throw new LogicException('Implement this package contract for the calling site.'); } /** * @return array<int, Htmlable> */ public function extendContainerComponents(\Filament\Schemas\Schema $schema, \Capell\LayoutBuilder\Data\LayoutContainerSchemaContextData $context): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\Extenders\LayoutContainerSchemaExtender::class, ExampleLayoutContainerSchemaExtenderImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetAssetSchemaExtenderImplementation implements \Capell\LayoutBuilder\Contracts\Extenders\WidgetAssetSchemaExtender{ /** * @param array<int, mixed> $components * @return array<int, mixed> */ public function extendAssetComponents(\Filament\Schemas\Schema $schema, array $components): array { throw new LogicException('Implement this package contract for the calling site.'); } /** * @param array<int, mixed> $components * @return array<int, mixed> */ public function extendRepeaterComponents(array $components): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\Extenders\WidgetAssetSchemaExtender::class, ExampleWidgetAssetSchemaExtenderImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetSchemaExtenderImplementation implements \Capell\LayoutBuilder\Contracts\Extenders\WidgetSchemaExtender{ /** * @param array<int, mixed> $components * @return array<int, mixed> */ public function extendDisplayComponents(\Filament\Schemas\Schema $schema, array $components): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\Extenders\WidgetSchemaExtender::class, ExampleWidgetSchemaExtenderImplementation::class);<?phpdeclare(strict_types=1);final class ExampleLayoutContainerThemePresentationProjectorImplementation implements \Capell\LayoutBuilder\Contracts\LayoutContainerThemePresentationProjector{ public function themeKey(): string { throw new LogicException('Implement this package contract for the calling site.'); } /** * @param array<string, mixed> $state */ public function project(array $state): \Capell\LayoutBuilder\Data\LayoutContainerThemePresentationData { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\LayoutContainerThemePresentationProjector::class, ExampleLayoutContainerThemePresentationProjectorImplementation::class);<?phpdeclare(strict_types=1);final class ExampleLayoutContentGroupContributorImplementation implements \Capell\LayoutBuilder\Contracts\LayoutContentGroupContributor{ public function priority(): int { throw new LogicException('Implement this package contract for the calling site.'); } public function group(\Capell\LayoutBuilder\Data\LayoutContentGroupData $group, \Capell\LayoutBuilder\Data\LayoutContentInventoryContextData $context): \Capell\LayoutBuilder\Data\LayoutContentGroupData { throw new LogicException('Implement this package contract for the calling site.'); } public function item(\Capell\LayoutBuilder\Data\LayoutContentItemData $item, \Capell\LayoutBuilder\Data\LayoutContentInventoryContextData $context): \Capell\LayoutBuilder\Data\LayoutContentItemData { throw new LogicException('Implement this package contract for the calling site.'); } /** * @return array<int, string> */ public function eagerLoads(): array { throw new LogicException('Implement this package contract for the calling site.'); } /** * @return array<int, string> */ public function cacheDependencies(): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\LayoutContentGroupContributor::class, ExampleLayoutContentGroupContributorImplementation::class);<?phpdeclare(strict_types=1);final class ExampleLayoutSidebarWidgetContributorImplementation implements \Capell\LayoutBuilder\Contracts\LayoutSidebarWidgetContributor{ /** * @return array<int, LayoutSidebarWidgetData> */ public function sidebarWidgets(): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\LayoutSidebarWidgetContributor::class, ExampleLayoutSidebarWidgetContributorImplementation::class);<?phpdeclare(strict_types=1);final class ExamplePublicLayoutWidgetPayloadContributorImplementation implements \Capell\LayoutBuilder\Contracts\PublicLayoutWidgetPayloadContributor{ public function priority(): int { throw new LogicException('Implement this package contract for the calling site.'); } /** * @return array<string, mixed> */ public function data(\Capell\LayoutBuilder\Models\Widget $widget, \Capell\Core\Models\Page $page, \Capell\Core\Models\Language $language, string $containerKey, int $occurrence): array { throw new LogicException('Implement this package contract for the calling site.'); } public function html(\Capell\LayoutBuilder\Models\Widget $widget, \Capell\Core\Models\Page $page, \Capell\Core\Models\Language $language, string $containerKey, int $occurrence): ?string { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\PublicLayoutWidgetPayloadContributor::class, ExamplePublicLayoutWidgetPayloadContributorImplementation::class);<?phpdeclare(strict_types=1);final class ExamplePublicLayoutWidgetPayloadResolverImplementation implements \Capell\LayoutBuilder\Contracts\PublicLayoutWidgetPayloadResolver{ /** * @return array<string, mixed> */ public function data(\Capell\LayoutBuilder\Models\Widget $widget, \Capell\Core\Models\Page $page, \Capell\Core\Models\Language $language, string $containerKey, int $occurrence): array { throw new LogicException('Implement this package contract for the calling site.'); } public function html(\Capell\LayoutBuilder\Models\Widget $widget, \Capell\Core\Models\Page $page, \Capell\Core\Models\Language $language, string $containerKey, int $occurrence): ?string { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\PublicLayoutWidgetPayloadResolver::class, ExamplePublicLayoutWidgetPayloadResolverImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetAssetReferenceRepointerImplementation implements \Capell\LayoutBuilder\Contracts\WidgetAssetReferenceRepointer{ public function repoint(\Illuminate\Database\Eloquent\Model $asset, int|string $fromAssetId, int|string $toAssetId): int { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\WidgetAssetReferenceRepointer::class, ExampleWidgetAssetReferenceRepointerImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetExtensionBatchPayloadResolverImplementation implements \Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionBatchPayloadResolver{ /** * Resolve public payloads for a batch keyed by opaque widget instance ID. * * @return array<string, Data> */ public function resolve(\Capell\LayoutBuilder\Data\WidgetExtensions\WidgetExtensionPayloadBatchData $batch): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionBatchPayloadResolver::class, ExampleWidgetExtensionBatchPayloadResolverImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetExtensionDependencyResolverImplementation implements \Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionDependencyResolver{ /** * Resolve stable content-graph dependency identifiers such as `media:123`. * * @return list<string> */ public function resolve(\Spatie\LaravelData\Data $input): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionDependencyResolver::class, ExampleWidgetExtensionDependencyResolverImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetExtensionStateUpcasterImplementation implements \Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionStateUpcaster{ /** * @param array<string, mixed> $state * @return array<string, mixed> */ public function upcast(array $state, int $fromVersion, int $toVersion): array { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\WidgetExtensions\WidgetExtensionStateUpcaster::class, ExampleWidgetExtensionStateUpcasterImplementation::class);<?phpdeclare(strict_types=1);final class ExampleWidgetSnapshotLocatorCipherImplementation implements \Capell\LayoutBuilder\Contracts\WidgetSnapshots\WidgetSnapshotLocatorCipher{ public function encrypt(string $plaintext): string { throw new LogicException('Implement this package contract for the calling site.'); } public function decrypt(string $ciphertext): string { throw new LogicException('Implement this package contract for the calling site.'); }}
app()->bind(\Capell\LayoutBuilder\Contracts\WidgetSnapshots\WidgetSnapshotLocatorCipher::class, ExampleWidgetSnapshotLocatorCipherImplementation::class);<?phpdeclare(strict_types=1);$inputs = []; // Supply the arguments required by the action handle() method.resolve(\Capell\LayoutBuilder\Actions\InstallLayoutBuilderPackageAction::class)->handle(...$inputs);<?phpdeclare(strict_types=1);$inputs = []; // Supply the arguments required by the action handle() method.resolve(\Capell\LayoutBuilder\Actions\PruneLayoutBulkChangeRunsAction::class)->handle(...$inputs);<?phpdeclare(strict_types=1);$inputs = []; // Supply the arguments required by the action handle() method.resolve(\Capell\LayoutBuilder\Actions\SetupLayoutBuilderPackageAction::class)->handle(...$inputs);