besmartand-pro/doctrine-behaviors
Installation:
composer require besmartand-pro/doctrine-behaviors
(Note: The package appears to be a fork of knplabs/doctrine-behaviors, so ensure compatibility checks are done.)
Entity Setup:
Add the required trait and interface to your Doctrine entity. Example for Blameable:
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\ORM\Blameable\BlameableInterface;
use Knp\DoctrineBehaviors\ORM\Blameable\BlameableTrait;
#[ORM\Entity]
class Post implements BlameableInterface
{
use BlameableTrait;
// ... other fields and methods
}
Configuration:
Add the following to your config/packages/doctrine.yaml (if not already present):
doctrine:
orm:
mappings:
knp_doctrine_behaviors:
type: attribute
prefix: 'Knp\DoctrineBehaviors\ORM'
dir: '%kernel.project_dir%/vendor/knplabs/doctrine-behaviors/src/Resources/mapping'
is_bundle: false
First Use Case:
Use the behavior in your application. For Blameable, ensure you have a User entity and set it in the setCreatedBy()/setUpdatedBy() methods:
$post = new Post();
$post->setCreatedBy($user); // Automatically sets createdAt and updatedAt
$entityManager->persist($post);
Blameable:
$post->setCreatedBy($currentUser);
$post->setUpdatedBy($currentUser); // Updates on save
Sluggable:
configureSlugs():
use Knp\DoctrineBehaviors\ORM\Sluggable\SluggableInterface;
use Knp\DoctrineBehaviors\ORM\Sluggable\SluggableTrait;
class Post implements SluggableInterface
{
use SluggableTrait;
public function configureSlugs(): array
{
return [
new Sluggable('title', ['field' => 3, 'separator' => '-']),
];
}
}
SoftDeletable:
delete() in repositories to use softDelete():
$entityManager->remove($post); // Hard delete (default)
$post->softDelete(); // Soft delete
Uuidable:
#[ORM\Id]
#[ORM\Column(type: 'uuid', unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?UUID $id = null;
Translatable:
translate():
$post->translate('title', 'fr', 'Titre traduit');
$translation = $post->getTranslation('title', 'fr');
Tree:
$rootNodes = $categoryRepository->getRootNodes();
$children = $categoryRepository->getChildren($parentCategory);
Event Listeners:
Automate behavior triggers (e.g., set createdBy/updatedBy on prePersist/preUpdate):
$entityManager->getEventManager()->addEventListener(
KernelEvents::REQUEST,
[$this, 'onKernelRequest']
);
QueryBuilder Extensions: Filter soft-deleted entities:
$qb = $entityManager->createQueryBuilder();
$qb->andWhere('entity.deletedAt IS NULL');
Migrations:
Add behavior fields (e.g., createdBy, updatedBy, deletedAt) in migrations:
$table->addColumn('created_by', 'integer', ['nullable' => true]);
$table->addColumn('updated_by', 'integer', ['nullable' => true]);
Database Schema Mismatch:
deletedAt for SoftDeletable).Circular Dependencies:
Tree behaviors (e.g., parent-child loops).getRootNodes() to traverse hierarchies safely.Slug Uniqueness:
Sluggable does not enforce uniqueness by default. Add a unique constraint in your schema or handle duplicates in configureSlugs():
new Sluggable('title', ['field' => 3, 'unique' => true])
UUID Generation:
ramsey/uuid-doctrine package for UUID generation.Translatable Performance:
Blameable Null Users:
Blameable allows null for createdBy/updatedBy. Validate this in your application logic if needed.Missing Fields:
createdAt, updatedAt) are mapped in your entity.Timestampable:
#[ORM\Column(type: 'datetime_immutable')]
private ?\DateTimeImmutable $createdAt = null;
Repository Traits:
Tree, ensure your repository extends EntityRepository and uses the correct trait (e.g., TreeTrait).PHPStan Errors:
composer require --dev besmartand-pro/doctrine-behaviors-phpstan
phpstan.neon:
includes:
- vendor/besmartand-pro/doctrine-behaviors-phpstan/extension.neon
Custom Events:
prePersist):
$eventManager->addEventListener(
Events::prePersist,
function (LifecycleEventArgs $args) {
$entity = $args->getObject();
if ($entity instanceof BlameableInterface) {
$entity->setCreatedBy($this->getCurrentUser());
}
}
);
Custom Slug Logic:
generateSlug() in Sluggable:
protected function generateSlug(string $text): string
{
return strtolower(parent::generateSlug($text));
}
Custom Tree Queries:
TreeRepository to add custom methods:
public function getSiblings(Category $category): array
{
return $this->createQueryBuilder('c')
->andWhere('c.parent = :parent')
->andWhere('c.id != :id')
->setParameter('parent', $category->getParent())
->setParameter('id', $category->getId())
->getQuery()
->getResult();
}
SoftDelete Query Filter:
$entityManager->getFilters()->enable(new SoftDeleteFilter());
Timezone Handling:
Timestampable uses the system timezone. Set it explicitly in your entity:
use Knp\DoctrineBehaviors\ORM\Timestampable\TimestampableInterface;
use Knp\DoctrineBehaviors\ORM\Timestampable\TimestampableTrait;
class Post implements TimestampableInterface
{
use TimestampableTrait;
public function setUpdatedAt(?\DateTimeImmutable $updatedAt): self
{
$updatedAt = $updatedAt?->setTimezone(new \DateTimeZone('UTC'));
return parent::setUpdatedAt($updatedAt);
}
}
How can I help you explore Laravel packages today?