Installation
composer require chamber-orchestra/meta
Add the bundle to config/bundles.php (Symfony) or register the service provider in config/app.php (Laravel via Symfony bridge):
ChamberOrchestra\MetaBundle\MetaBundle::class => ['all' => true],
Doctrine Trait Integration
Add the MetaTrait to your entity:
use ChamberOrchestra\MetaBundle\Model\MetaTrait;
class Page extends AbstractEntity
{
use MetaTrait;
// ...
}
Database Migration
Run migrations to add the meta fields (meta_title, meta_description, etc.) to your table.
First Use Case Define meta fields in your entity:
$page = new Page();
$page->setMetaTitle('My SEO Title');
$page->setMetaDescription('Optimized description for search engines');
$page->setMetaKeywords(['keyword1', 'keyword2']);
$page->setMetaRobots('index,follow');
$page->setMetaOpenGraphImage('/path/to/image.jpg');
Dynamic Meta Generation
Override getMetaTitle() in your entity to generate dynamic titles:
public function getMetaTitle(): ?string
{
return "Default: {$this->title} | {$this->getSiteName()}";
}
Form Integration (Symfony)
Use MetaType in your form builder:
$builder->add('meta', MetaType::class, [
'mapped' => false,
'fields' => ['title', 'description', 'keywords', 'robots', 'og_image'],
]);
Laravel-Specific Twist
Create a MetaService to centralize meta logic:
class MetaService {
public function generateMetaTags(Page $page): array
{
return [
'title' => $page->getMetaTitle(),
'description' => $page->getMetaDescription(),
// ...
];
}
}
Repository Filtering Filter entities by meta fields in Doctrine queries:
$pages = $repo->findBy(['meta_title' => '%SEO%']);
Twig Integration (Symfony) Access meta fields in templates:
<title>{{ page.metaTitle }}</title>
<meta name="description" content="{{ page.metaDescription }}">
Missing Trait Initialization
Ensure MetaTrait is used after TimestampableTrait (if applicable) to avoid field conflicts.
Doctrine Lifecycle Hooks
Override prePersist()/preUpdate() if you need to sanitize meta fields:
public function prePersist()
{
$this->setMetaKeywords(array_map('strtolower', $this->getMetaKeywords()));
}
Open Graph Image Paths
Store absolute URLs (not relative paths) for metaOpenGraphImage to avoid 404s.
Robots Meta Quirks
Default value is index,follow. Explicitly set to noindex if needed:
$page->setMetaRobots('noindex');
Check Database Schema Verify fields exist via:
php bin/console doctrine:schema:validate
Log Meta Fields Add a debug method to your entity:
public function debugMeta(): string
{
return json_encode([
'title' => $this->getMetaTitle(),
'description' => $this->getMetaDescription(),
// ...
]);
}
Custom Meta Fields
Extend the trait to add fields (e.g., twitter_card):
use Doctrine\ORM\Mapping as ORM;
#[ORM\Column(nullable: true)]
private ?string $metaTwitterCard = null;
public function getMetaTwitterCard(): ?string { return $this->metaTwitterCard; }
public function setMetaTwitterCard(?string $card): self { $this->metaTwitterCard = $card; return $this; }
Validation Add Symfony Validator constraints:
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\Length(max: 60)]
private ?string $metaTitle = null;
Event Listeners Trigger events on meta changes (e.g., log updates):
// config/services.yaml
ChamberOrchestra\MetaBundle\EventListener\MetaUpdateListener:
tags:
- { name: doctrine.event_listener, event: preUpdate }
How can I help you explore Laravel packages today?