Installation
composer require akyos/builder-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Akyos\BuilderBundle\AkyosBuilderBundle::class => ['all' => true],
];
Basic Configuration
Override default settings in config/packages/akyos_builder.yaml:
akyos_builder:
blocks: ['header', 'content', 'footer'] # Define available blocks
templates: ['default', 'custom'] # Define templates
First Use Case: Creating a Page
Define a page entity (e.g., Page):
// src/Entity/Page.php
use Akyos\BuilderBundle\Entity\PageInterface;
class Page implements PageInterface {
// ...
}
Use the builder in a controller:
use Akyos\BuilderBundle\Builder\PageBuilder;
class PageController {
public function edit(PageBuilder $builder, Page $page) {
return $builder->edit($page);
}
}
Key Directories
templates/akyos_builder/ – Default Twig templates for blocks.src/Resources/config/akyos_builder.yaml – Default config.Block-Based Development
config/packages/akyos_builder.yaml:
akyos_builder:
blocks:
header:
type: 'header' # Block type (e.g., 'text', 'image', 'custom')
template: 'blocks/header.html.twig'
fields:
- { name: 'title', type: 'text' }
- { name: 'logo', type: 'media' }
content:
type: 'rich_text'
template: 'blocks/content.html.twig'
Template Inheritance
Override default templates by copying files from templates/akyos_builder/ to your project’s templates/ directory.
Dynamic Page Assembly
Use the PageBuilder to construct pages programmatically:
$page = $builder->createPage('home');
$page->addBlock('header', ['title' => 'Welcome']);
$page->addBlock('content', ['content' => '<p>Hello!</p>']);
$builder->save($page);
Integration with CMS
PageRepository to fetch/save pages:
$repository = $this->get(PageRepository::class);
$page = $repository->findOneBy(['slug' => 'about']);
prePersist, preUpdate) via Doctrine listeners.Frontend Rendering Render pages in Twig:
{{ render(akyos_builder_page(page)) }}
Or use the PageRenderer service:
$renderer = $this->get(PageRenderer::class);
echo $renderer->render($page);
Symfony Forms Integrate with Symfony Forms for block configuration:
use Akyos\BuilderBundle\Form\Type\BlockType;
$builder->add('header', BlockType::class, [
'block_type' => 'header',
'data' => $page->getBlock('header'),
]);
Media Handling Use VichUploaderBundle or similar for media fields in blocks:
fields:
- { name: 'image', type: 'media', options: { vich_uploader: 'images' } }
Localization
Support multilingual blocks by extending BlockInterface and using Symfony’s translation tools.
API Endpoints Expose pages/blocks via API (e.g., with API Platform):
# config/api_platform/resources.yaml
resources:
Akyos\BuilderBundle\Entity\Page:
collectionOperations:
- GET
itemOperations:
- GET
- PUT
Asset Management Use Webpack Encore or similar to compile block-specific CSS/JS:
{# templates/blocks/custom.html.twig #}
{{ encore_entry_link_tags('blocks-custom') }}
Block Type Mismatches
block_type in config matches the registered type (e.g., 'header' must have a corresponding HeaderBlockType service).services.yaml for custom block types:
services:
Akyos\BuilderBundle\Form\Type\HeaderBlockType:
tags: [akyos_builder.block_type]
Template Overrides
templates/akyos_builder/blocks/header.html.twig).{{ parent() }} in Twig to extend parent templates.Circular Dependencies
Doctrine Lifecycle Conflicts
prePersist) may conflict with BuilderBundle’s listeners.->addEventListener(PrePersist::class, [$listener, 'onPrePersist'], 20) // Lower priority
Performance with Large Pages
$renderer->render($page, ['cache' => true]);
Enable Debug Mode
Set AKYOS_BUILDER_DEBUG: true in .env to log block rendering issues.
Common Errors
config/packages/akyos_builder.yaml for typos.BlockType classes.Logging Use Symfony’s logger to debug block processing:
$this->logger->debug('Block data:', ['data' => $block->getData()]);
Custom Block Types
Create reusable block types by extending AbstractBlockType:
class CustomBlockType extends AbstractBlockType {
public function getBlockType() { return 'custom'; }
public function getFields() {
return [
['name' => 'title', 'type' => 'text'],
['name' => 'content', 'type' => 'rich_text'],
];
}
}
Register the service with the akyos_builder.block_type tag.
Dynamic Block Configuration
Use Symfony’s ParameterBag to pass dynamic options:
akyos_builder:
blocks:
dynamic:
type: 'custom'
options:
max_items: '%env(int:MAX_DYNAMIC_BLOCKS)%'
Versioning Implement soft-deletes for pages/blocks using Doctrine Extensions:
use Gedmo\SoftDeleteable\SoftDeleteableEntity;
class Page extends SoftDeleteableEntity implements PageInterface { ... }
Testing Use functional tests to verify page rendering:
public function testPageRendering(Client $client) {
$page = $this->createTestPage();
$client->request('GET', '/page/' . $page->getSlug());
$this->assertSelectorTextContains('h1', 'Welcome');
}
Extension Points
AbstractBlockType and tag services.PageRepository for custom queries.PageBuiltEvent) via Symfony’s event dispatcher.Security
# config/packages/security.yaml
access_control:
- { path: ^/admin/builder, roles: ROLE_ADMIN }
How can I help you explore Laravel packages today?