Installation
Add the bundle to your composer.json:
composer require anh/content-bundle
Enable it in config/bundles.php:
Anh\ContentBundle\AnhContentBundle::class => ['all' => true],
First Use Case: Basic Content Entity
Create a content entity (e.g., Article) extending Anh\ContentBundle\Entity\Content:
namespace App\Entity;
use Anh\ContentBundle\Entity\Content;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class Article extends Content
{
#[ORM\Column(type: 'string', length: 255)]
private $title;
// Getters/setters...
}
Run migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Key Configuration
Check config/packages/anh_content.yaml for default settings (e.g., upload paths, image processing). Override as needed:
anh_content:
upload_dir: '%kernel.project_dir%/public/uploads'
image_quality: 80
CRUD with Admin Bundle
Leverage anh/admin-bundle for scaffolding:
php bin/console anh:admin:generate --entity=Article
Customize fields in config/admin/article.yaml:
properties:
title:
type: string
label: 'Article Title'
content:
type: 'anh\markup-bundle\Admin\Type\MarkupType'
Tagging and Categorization
Use anh/taggable-bundle for tags:
$article->addTag('laravel');
$article->addTag('php');
$tagManager = $this->get('anh.taggable.manager');
$tagManager->save($article);
Media Handling
Upload files via oneup/uploader-bundle:
$article->setImage($file); // Automatically processes via LiipImagineBundle
Configure presets in config/packages/liip_imagine.yaml:
liip_imagine:
filter_sets:
article_thumbnail:
quality: 75
filters:
thumbnail: { size: [200, 200], mode: outbound }
Feed Generation
Expose content as RSS/Atom via anh/feed-bundle:
anh_feed:
feeds:
articles:
route: article_show
template: AnhContentBundle:Feed:article.atom.twig
stof/doctrine-extensions-bundle for soft deletes or timestamps:
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
class Article extends Content { ... }
anh/markup-bundle:
{{ article.content|markup }}
anh/paginator-bundle for lists:
$paginator = $this->get('anh.paginator');
$articles = $paginator->paginate($articles, $page, 10);
Upload Permissions
Ensure upload_dir is writable:
chmod -R 775 %kernel.project_dir%/public/uploads
Debug with:
php bin/console anh:content:debug-uploads
Image Processing Failures
Verify liip_imagine filters in config/packages/liip_imagine.yaml:
# Missing filters cause silent failures
filter_sets:
default:
filters:
thumbnail: ~
Clear cache after changes:
php bin/console cache:clear
Admin Bundle Conflicts
Override templates in templates/AnhAdmin/ to avoid style clashes. Example:
{# templates/AnhAdmin/Article/edit.html.twig #}
{% extends 'AnhAdminBundle:CRUD:edit.html.twig' %}
{% block anh_admin_content %}
{{ form_row(form.title) }}
{{ form_row(form.content) }}
{% endblock %}
Doctrine Events Avoid infinite loops in lifecycle callbacks. Example:
// ❌ Bad: Triggers on save
public function prePersist()
{
$this->setSlug($this->title); // Use @PreUpdate instead
}
Log Uploads: Enable debug mode in config/packages/anh_content.yaml:
anh_content:
debug: true
Check logs at var/log/dev.log.
Doctrine Queries: Use STDOUT for SQL queries:
php bin/console doctrine:query:sql "SELECT * FROM article"
Symfony Profiler: Install web-profiler-bundle to inspect:
Custom Content Types
Extend Anh\ContentBundle\Entity\Content for domain-specific logic:
class BlogPost extends Content
{
public function getExcerpt(): string
{
return substr($this->content, 0, 200) . '...';
}
}
Event Listeners
Subscribe to anh.content.pre_save:
// src/EventListener/ContentListener.php
public function onPreSave(ContentEvent $event)
{
$content = $event->getContent();
if ($content instanceof Article) {
$content->setSlug(Str::slug($content->getTitle()));
}
}
Register in services.yaml:
services:
App\EventListener\ContentListener:
tags:
- { name: 'kernel.event_listener', event: 'anh.content.pre_save' }
Custom Fields Create a new field type (e.g., for rich text):
// src/Form/Type/RichTextType.php
class RichTextType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('body', MarkupType::class);
}
}
Use in Article entity:
#[ORM\Column(type: 'text')]
private $body;
How can I help you explore Laravel packages today?