Installation:
composer require c975l/ui-bundle
php bin/console doctrine:migrations:diff && php bin/console doctrine:migrations:migrate
Add to config/bundles.php:
return [
// ...
C975L\UiBundle\C975LUiBundle::class => ['all' => true],
];
Enable in EasyAdmin:
Extend your EasyAdmin CRUD controller to include the UiBundle's block management:
use C975L\UiBundle\EasyAdmin\BlockFieldType;
class YourCrudController extends AbstractCrudController {
public static function getBlocksField(): array {
return [
'property' => 'blocks',
'type' => BlockFieldType::class,
'type_options' => [
'block_kinds' => ['text', 'image', 'custom'], // Your registered block kinds
],
];
}
}
First Use Case:
Create a text block in EasyAdmin via the BlockFieldType. The block will render dynamically in your Twig template using:
{% for block in entity.blocks %}
{{ render_block(block) }}
{% endfor %}
Block Registration:
Define custom block kinds via a service tag in config/services.yaml:
services:
App\Block\CustomBlock:
tags: [ 'c975l_ui.block_kind' ]
Implement C975L\UiBundle\Block\BlockKindInterface for form/template logic.
EasyAdmin Integration:
Use BlockFieldType for drag-and-drop management:
$builder->add('blocks', BlockFieldType::class, [
'block_kinds' => ['text', 'image', 'App\Block\CustomBlock'],
]);
Twig Rendering:
Override render_block() in Twig (default in C975LUiBundle:Block:block.html.twig) or extend:
{% extends 'C975LUiBundle:Block:block.html.twig' %}
{% block custom_block %}
{{ include('App:Block/custom_block.html.twig', { block: block }) }}
{% endblock %}
Media Handling:
VichUploader is auto-configured for blocks with UploadableBlockKindInterface. Example:
class ImageBlock implements UploadableBlockKindInterface {
// ...
}
Dynamic CSS Injection: Declare stylesheets for your block kinds via service tag:
services:
App\Twig\BlockStylesheetExtension:
tags: [ 'c975l_ui.stylesheet' ]
Use in Twig:
{{ bundle_stylesheets('AppBlockBundle') }}
Sortable Collections:
Reuse the drag-and-drop script for any EasyAdmin CollectionField:
import { sortableCollection } from '@c975l/ui-bundle/controllers';
sortableCollection();
Block Reusability:
Share blocks across entities by referencing them via BlockReference (implement C975L\UiBundle\Block\BlockReferenceInterface).
Migration Conflicts:
Ensure doctrine:migrations:diff is run after installation to avoid schema conflicts. The bundle creates tables for Block, BlockKind, and BlockPosition.
EasyAdmin Caching:
Clear EasyAdmin cache (php bin/console ea:crud:cache:clear) after adding new block kinds to reflect changes in the UI.
Stimulus Controllers:
The drag-and-drop functionality relies on Stimulus. Ensure importmap.php is correctly configured (see Installation). Missing controllers will break reordering.
VichUploader Dependencies: The bundle assumes VichUploader is configured. If media uploads fail, verify:
vich_uploader.directories is set in config/packages/vich_uploader.yaml.UploadableBlockKindInterface is implemented for media-enabled blocks.Twig Auto-escaping:
Blocks rendered via render_block() are auto-escaped. Use {{ render_block(block, {'escape': false}) }} for raw HTML.
Block Not Rendering:
Check if the block kind is registered (debug:container c975l_ui.block_kind) and the Twig template exists. Enable debug mode (APP_DEBUG=1) to see missing template errors.
Drag-and-Drop Failing:
Verify Stimulus controllers are loaded (inspect the network tab for @c975l/ui-bundle/controllers.js). Ensure no JavaScript errors block the sortableCollection initialization.
Form Validation:
Custom block kinds must implement BlockKindInterface::configureFormBuilder(). Missing this will cause form submission errors.
Custom Block Kinds:
Extend AbstractBlockKind for boilerplate reduction:
class CustomBlock extends AbstractBlockKind {
protected static string $template = 'App:Block/custom_block.html.twig';
}
Override Default Templates:
Copy templates/Block/ from the bundle to your project and modify. The bundle follows Twig’s template inheritance.
Block Events:
Listen for block lifecycle events (e.g., block.pre_save) via Symfony’s event dispatcher:
services:
App\EventListener\BlockListener:
tags:
- { name: 'kernel.event_listener', event: 'c975l_ui.block.pre_save', method: 'onBlockPreSave' }
API Integration: Expose blocks via API by serializing them in your controller:
use C975L\UiBundle\Serializer\BlockNormalizer;
// Auto-registered via `resources/config/serializer/Entity.Block.yaml`
Multi-Entity Blocks:
Use BlockReference to link blocks across entities (e.g., a "Hero" block reused on Homepage and About). Implement BlockReferenceInterface for custom logic.
How can I help you explore Laravel packages today?