Installation Add the bundle via Composer:
composer require austral/entity-seo-bundle
Enable it in config/bundles.php:
Austral\EntitySeoBundle\EntitySeoBundle::class => ['all' => true],
First Use Case: Basic SEO Entity
Create a new entity (e.g., Page) extending Austral\EntityBundle\Entity\AbstractEntity and embed SEO metadata:
use Austral\EntitySeoBundle\Entity\SeoEntityInterface;
use Austral\EntitySeoBundle\Entity\Traits\SeoTrait;
class Page extends AbstractEntity implements SeoEntityInterface
{
use SeoTrait;
// Your entity fields (title, slug, etc.)
}
Configuration
Check config/packages/austral_entity_seo.yaml for default settings (e.g., slug generation rules). Override as needed:
austral_entity_seo:
slug:
separator: '-'
max_length: 100
First Hydration
Use the PagesService (or equivalent) to hydrate SEO fields:
$page = $pagesService->hydrate($pageEntity);
// Automatically triggers SEO subscriber for metadata population
CRUD with SEO
metaTitle, metaDescription, and slug during entity creation.
$page = new Page();
$page->setMetaTitle('My Awesome Page');
$page->setSlug('my-awesome-page'); // Auto-generated if omitted
$entityManager->persist($page);
SeoTrait methods to update SEO fields:
$page->updateSeo(['metaDescription' => 'Updated description']);
Slug Generation
Leverage the slugify() method for dynamic slugs:
$page->setSlug($page->slugify('My Dynamic Title'));
Customize generation via config or override the slugify() method in your entity.
Subscriber Integration
The bundle includes a subscriber to auto-hydrate SEO fields when entities are loaded. Extend or disable it in config/services.yaml:
services:
Austral\EntitySeoBundle\EventSubscriber\SeoSubscriber:
tags: ['kernel.event_subscriber']
# Disable by setting to false
API/Serialization Use Symfony Serializer to expose SEO fields:
use Symfony\Component\Serializer\Annotation\Groups;
class Page {
#[Groups(['seo'])]
private string $metaTitle;
}
Configure normalization in config/serializer.yaml:
Austral\EntitySeoBundle\Entity\SeoEntityInterface: ~
Validation Add constraints to SEO fields in your entity:
use Symfony\Component\Validator\Constraints as Assert;
class Page {
#[Assert\NotBlank]
#[Assert\Length(max: 60)]
private string $metaTitle;
}
Slug Collisions
if ($page->slugExists('my-slug')) {
$page->setSlug($page->slugify('My Title - Alternative'));
}
slugify() to add unique suffixes (e.g., -1, -2).Subscriber Conflicts
SeoSubscriber runs at the correct priority. Check kernel.event_listener tags in config/services.yaml.Performance with Large Datasets
slug fields:
/**
* @ORM\Table(indexes={@ORM\Index(name="slug_idx", columns={"slug"})})
*/
class Page {}
Deprecation Warnings
austral/tools-bundle or austral/entity-bundle (required dependencies).Missing Documentation
Austral\EntitySeoBundle\EventSubscriber\SeoSubscriber for available events like onHydrate.Custom SEO Fields
Extend the SeoTrait to add custom metadata:
use Doctrine\ORM\Mapping as ORM;
class Page {
use SeoTrait;
#[ORM\Column(nullable: true)]
private ?string $twitterCard = 'summary';
public function getTwitterCard(): ?string { return $this->twitterCard; }
public function setTwitterCard(?string $card): self { $this->twitterCard = $card; return $this; }
}
Testing SEO Logic Use PHPUnit to test slug generation and validation:
public function testSlugGeneration() {
$page = new Page();
$page->setTitle('Test Title');
$this->assertEquals('test-title', $page->slugify($page->getTitle()));
}
Debugging Subscribers Enable debug mode to trace subscriber execution:
# config/packages/dev/monolog.yaml
handlers:
seo_subscriber:
type: stream
path: "%kernel.logs_dir%/seo_subscriber.log"
level: debug
channels: ["event"]
Integration with Austral CMS
If using Austral’s PagesService, leverage its built-in SEO hydration:
$page = $pagesService->create([
'title' => 'Home',
'metaTitle' => 'Welcome to Our Site',
// Automatically hydrates SEO fields
]);
Localization For multilingual SEO, use Doctrine Extensions or Symfony’s translation system:
#[ORM\Column]
private ?string $metaTitleEn;
#[ORM\Column]
private ?string $metaTitleFr;
Override SeoTrait to handle locale-specific fields.
Caching SEO Data Cache SEO metadata for performance (e.g., using Symfony Cache):
$cache = $container->get('cache.app');
$seoData = $cache->get('seo:'.$page->getId(), function() use ($page) {
return $page->getSeoData();
});
Migration from v2.x
If upgrading from an older version, check for renamed methods (e.g., getMetaTitle() vs. getSeoTitle()). Review the SeoTrait for changes.
How can I help you explore Laravel packages today?