## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require austral/content-block-bundle
Ensure Austral\ContentBlockBundle\AustralContentBlockBundle is registered in config/bundles.php.
Database Migration Run migrations to create the required tables:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Content Block
Create a custom block type by extending Austral\ContentBlockBundle\Entity\ContentBlockInterface and implementing the required methods. Example:
namespace App\Entity;
use Austral\ContentBlockBundle\Entity\ContentBlockInterface;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class CustomBlock implements ContentBlockInterface
{
#[ORM\Column(type: 'string', length: 255)]
private string $title;
#[ORM\Column(type: 'text')]
private string $content;
// Implement required methods from ContentBlockInterface
public function getType(): string { return 'custom_block'; }
public function getContent(): string { return $this->content; }
// ... other methods
}
Register Block Type
Add your block type to the bundle’s configuration in config/packages/austral_content_block.yaml:
austral_content_block:
block_types:
custom_block: App\Entity\CustomBlock
Admin Integration
The bundle includes a CRUD interface for managing blocks. Access it via /admin/content-blocks (adjust route if needed).
Create a Block Entity
Extend ContentBlockInterface for a hero section:
class HeroBlock implements ContentBlockInterface
{
#[ORM\Column(type: 'string', length: 255)]
private string $heading;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $subheading;
#[ORM\Column(type: 'string', length: 255)]
private string $backgroundImage;
// Implement ContentBlockInterface methods
public function getType(): string { return 'hero'; }
public function getContent(): string { return json_encode([...]); }
}
Render the Block in Twig
Use the content_block Twig function to render blocks in templates:
{% for block in blocks %}
{% if block.type == 'hero' %}
<section class="hero">
<h1>{{ block.heading }}</h1>
<img src="{{ block.backgroundImage }}" alt="{{ block.heading }}">
</section>
{% endif %}
{% endfor %}
Fetch Blocks in Controller
Retrieve blocks via the ContentBlockRepository:
use Austral\ContentBlockBundle\Repository\ContentBlockRepository;
public function showHomepage(ContentBlockRepository $blockRepo)
{
$heroBlocks = $blockRepo->findBy(['type' => 'hero']);
return view('homepage', compact('heroBlocks'));
}
Define Block Types
Create modular block entities (e.g., FeatureBlock, TestimonialBlock, CTABlock) for reusable components.
Admin Management
Use the built-in admin interface to create, edit, and organize blocks. Leverage the Library feature (v3.1+) to manage blocks across multiple domains:
austral_content_block:
library:
enabled: true
domains:
- '*.example.com'
- '*.client-site.com'
Twig Integration
Use the content_block Twig function to render blocks dynamically:
{% for block in blocks %}
{% include ['@AustralContentBlock/blocks/' ~ block.type ~ '.html.twig', 'blocks/default.html.twig'] %}
{% endfor %}
templates/AustralContentBlock/blocks/.Caching Cache rendered blocks or block collections to improve performance:
$cachedBlocks = Cache::remember("blocks_{$pageId}", 3600, function() use ($blockRepo) {
return $blockRepo->findBy(['page' => $pageId]);
});
Form Handling
Use Austral\FormBundle to create custom forms for block types. Example:
use Austral\FormBundle\Form\Type\AustralFormType;
class HeroBlockType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('heading', TextType::class)
->add('subheading', TextType::class, ['required' => false])
->add('backgroundImage', AustralFormType::class, [
'type' => 'media',
'label' => 'Background Image',
]);
}
}
Register the form type in config/packages/austral_content_block.yaml:
austral_content_block:
block_types:
hero:
form_type: App\Form\Type\HeroBlockType
Event Listeners Extend functionality with events. Example: Log block creation:
use Austral\ContentBlockBundle\Event\ContentBlockEvents;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: ContentBlockEvents::POST_CREATE, method: 'onBlockCreate')]
public function onBlockCreate(ContentBlockEvent $event)
{
$block = $event->getBlock();
\Log::info("Block created: {$block->getType()}", ['block_id' => $block->getId()]);
}
API Exposure Expose blocks via API using Symfony’s Serializer:
use Symfony\Component\Serializer\Annotation\Groups;
class HeroBlock implements ContentBlockInterface
{
#[Groups(['api'])]
public function getHeading(): string { return $this->heading; }
#[Groups(['api'])]
public function getBackgroundImage(): string { return $this->backgroundImage; }
}
Configure serialization groups in config/packages/api_platform.yaml:
api_platform:
formats:
jsonld:
mime_types: ['application/ld+json']
jsonld_contexts:
blocks: ['/api/contexts/blocks.jsonld']
Multi-Language Support
Use Austral\ToolsBundle for translations. Example:
#[ORM\Column(type: 'json')]
private array $translations = [];
public function getTranslatedContent(string $locale): string
{
return $this->translations[$locale]['content'] ?? $this->content;
}
Block Type Registration
austral_content_block.yaml will cause the admin interface to ignore it.austral_content_block:
block_types:
custom_block: App\Entity\CustomBlock
Content Serialization
getContent() may break rendering or cause serialization errors.public function getContent(): string { return json_encode($this->complexData); }
public function setContent(string $content): void { $this->complexData = json_decode($content, true); }
Admin Permissions
Austral\FormBundle or Austral\ToolsBundle are misconfigured.composer require austral/form-bundle austral/tools-bundle
Database Schema Changes
make:entity and make:migration commands:
php bin/console make:entity --regenerate Austral/ContentBlockBundle/Entity/ContentBlock
php bin/console make:migration
Circular Dependencies
GalleryBlock containing ImageBlock instances) can cause infinite loops in rendering.public function getGalleryImages(): array
{
return $this->imageBlocks->map(fn($block) => $block->getImageUrl());
}
#[AsEventListener(event: ContentBlockEvents::PRE_SAVE, method: 'onPreSave')]
public function onPreSave(ContentBlockEvent
How can I help you explore Laravel packages today?