ali/doctrine-extensions-bundle
Install the Bundle
composer require ali/doctrine-extensions-bundle
Ensure your composer.json aligns with the package's PHP (^7.1.3) and Symfony (^4.3 || ^5.0) requirements.
Enable the Bundle
Add to config/bundles.php:
return [
// ...
Ali\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
];
Configure Doctrine
Add to config/packages/doctrine.yaml:
doctrine:
orm:
mappings:
gedmo_loggable:
type: attribute
prefix: Gedmo\Loggable\Entity
dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Entity"
alias: GedmoLoggable
# Add other extensions (e.g., translatable, sluggable) similarly
First Use Case: Loggable Entity Annotate an entity to track changes:
use Gedmo\Mapping\Annotation as Gedmo;
#[ORM\Entity]
class Product
{
#[Gedmo\Loggable]
private $name;
}
Run migrations (php bin/console doctrine:migrations:diff + php bin/console doctrine:migrations:migrate).
/products/awesome-widget).#[Gedmo\Slug(fields={"name"}, unique=true)]
private $slug;
$product->setName('Awesome Widget');
$slugger = $this->get('gedmo_slugger.slugger.product');
$product->setSlug($slugger->slugify($product));
#[Gedmo\TranslationEntity(class: ProductTranslation::class)]
class Product {}
$product = $entityManager->getRepository(Product::class)->findOneBy(['id' => 1]);
$translations = $product->getTranslations(); // Array of ProductTranslation
use Stof\DoctrineExtensionsBundle\Uploadable\Uploadable;
#[ORM\Entity]
class Document implements Uploadable
{
#[ORM\Column(type: 'string', length: 255)]
private $file;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $fileName;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $mimeType;
#[ORM\Column(type: 'integer', nullable: true)]
private $size;
// Implement Uploadable methods (getters/setters for file, fileName, etc.)
}
$document = new Document();
$document->setFile($uploadedFile); // Symfony\Component\HttpFoundation\File\UploadedFile
$uploadableManager = $this->get('stof_doctrine_extensions.uploadable.manager');
$uploadableManager->upload($document);
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
class Product {}
$product->setDeletedAt(new \DateTime());
$entityManager->flush();
$qb = $entityManager->createQueryBuilder();
$qb->from(Product::class, 'p')
->where('p.deletedAt IS NULL');
#[Gedmo\Tree(type: 'nested')]
class Category {}
$parent = $entityManager->getRepository(Category::class)->find(1);
$child = new Category();
$child->setParent($parent);
$entityManager->persist($child);
$entityManager->flush();
Event Listeners Use Doctrine lifecycle events to trigger extensions automatically:
#[ORM\PrePersist]
#[ORM\PreUpdate]
public function updateTimestamps()
{
if (!$this->createdAt) {
$this->createdAt = new \DateTime();
}
$this->updatedAt = new \DateTime();
}
Custom Slug Generation Override slug logic in a service:
# config/services.yaml
services:
App\Service\CustomSlugger:
arguments:
$baseSlugger: '@gedmo_slugger.slugger.product'
// src/Service/CustomSlugger.php
class CustomSlugger
{
public function __construct(private Slugger $baseSlugger) {}
public function slugify(Product $product): string
{
$slug = $this->baseSlugger->slugify($product);
return strtolower($slug); // Custom logic
}
}
Querying Extensions Filter soft-deleted records:
$qb = $entityManager->createQueryBuilder();
$qb->from(Product::class, 'p')
->where('p.deletedAt IS NULL');
Or use DQL:
$query = $entityManager->createQuery(
'SELECT p FROM App\Entity\Product p WHERE p.deletedAt IS NULL'
);
Combining Extensions Example: Loggable + SoftDeletable:
#[Gedmo\Loggable]
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
class Product {}
Ensure deletedAt is not logged (add to loggable.ignored_fields in config).
Migration Order
Loggable require additional tables (e.g., AUDIT_ENTRY).Circular Dependencies
Uploadable entities. Use lazy loading or custom upload logic.Slug Uniqueness Conflicts
unique: true in @Gedmo\Slug has a unique index in the database.php bin/console doctrine:schema:validate
Translatable Performance
Gedmo\Translatable\TranslatableListener sparingly on large datasets. Consider denormalizing translations.SoftDelete + Loggable
# config/packages/gedmo_loggable.yaml
gedmo_loggable:
log_entry_class: App\Entity\AuditEntry
ignored_fields: ['deletedAt']
Uploadable File Paths
uploadable.directories in config/packages/stof_doctrine_extensions.yaml:
stof_doctrine_extensions:
uploadable:
directories:
product_images: '%kernel.project_dir%/public/uploads/products'
chmod -R 775 public/uploads).Doctrine Cache Invalidation
php bin/console cache:clear
Loggable Issues
AUDIT_ENTRY table for missing logs. Verify loggable.enabled: true in config.Slug Generation
slugify() in a custom service to debug:
public function slugify($string): string
{
$slug = parent::slugify($string);
error_log("Generated slug: $slug"); // Debug
return $slug;
}
Uploadable Errors
php bin/console debug:config stof_doctrine_extensions
UploadableListener exceptions.Tree (NestedSet) Errors
lft/rgt columns exist. Run:
How can I help you explore Laravel packages today?