Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Behaviors Laravel Package

besmartand-pro/doctrine-behaviors

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. 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.)

  2. 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
    }
    
  3. 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
    
  4. 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);
    

Implementation Patterns

Common Workflows

  1. Blameable:

    • Track creation and updates by users.
    • Useful for audit logs or user activity tracking.
    • Example:
      $post->setCreatedBy($currentUser);
      $post->setUpdatedBy($currentUser); // Updates on save
      
  2. Sluggable:

    • Generate SEO-friendly slugs from titles.
    • Configure slug fields in 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' => '-']),
              ];
          }
      }
      
  3. SoftDeletable:

    • Soft-delete entities instead of hard-deleting.
    • Override delete() in repositories to use softDelete():
      $entityManager->remove($post); // Hard delete (default)
      $post->softDelete(); // Soft delete
      
  4. Uuidable:

    • Use UUIDs instead of auto-increment IDs.
    • Ensure your database supports UUIDs and configure the field:
      #[ORM\Id]
      #[ORM\Column(type: 'uuid', unique: true)]
      #[ORM\GeneratedValue(strategy: 'CUSTOM')]
      #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
      private ?UUID $id = null;
      
  5. Translatable:

    • Manage multilingual content.
    • Define translations in a separate table and use translate():
      $post->translate('title', 'fr', 'Titre traduit');
      $translation = $post->getTranslation('title', 'fr');
      
  6. Tree:

    • Handle hierarchical data (e.g., categories).
    • Use repository traits for tree operations:
      $rootNodes = $categoryRepository->getRootNodes();
      $children = $categoryRepository->getChildren($parentCategory);
      

Integration Tips

  • 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]);
    

Gotchas and Tips

Pitfalls

  1. Database Schema Mismatch:

    • Ensure your database schema matches the behavior's requirements (e.g., deletedAt for SoftDeletable).
    • Run migrations after adding behaviors.
  2. Circular Dependencies:

    • Avoid circular references in Tree behaviors (e.g., parent-child loops).
    • Use getRootNodes() to traverse hierarchies safely.
  3. 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])
      
  4. UUID Generation:

    • Ensure your database supports UUIDs (e.g., PostgreSQL, MySQL 8+).
    • For MySQL 5.7, use the ramsey/uuid-doctrine package for UUID generation.
  5. Translatable Performance:

    • Translations can bloat your database. Consider denormalizing or caching translations for read-heavy apps.
  6. Blameable Null Users:

    • Blameable allows null for createdBy/updatedBy. Validate this in your application logic if needed.

Debugging

  1. Missing Fields:

    • If behaviors don't work, check if the required fields (e.g., createdAt, updatedAt) are mapped in your entity.
    • Example for Timestampable:
      #[ORM\Column(type: 'datetime_immutable')]
      private ?\DateTimeImmutable $createdAt = null;
      
  2. Repository Traits:

    • For Tree, ensure your repository extends EntityRepository and uses the correct trait (e.g., TreeTrait).
  3. PHPStan Errors:

    • If using PHPStan, install the extension:
      composer require --dev besmartand-pro/doctrine-behaviors-phpstan
      
    • Configure PHPStan to load the extension in phpstan.neon:
      includes:
          - vendor/besmartand-pro/doctrine-behaviors-phpstan/extension.neon
      

Extension Points

  1. Custom Events:

    • Extend behaviors by listening to Doctrine events (e.g., prePersist):
      $eventManager->addEventListener(
          Events::prePersist,
          function (LifecycleEventArgs $args) {
              $entity = $args->getObject();
              if ($entity instanceof BlameableInterface) {
                  $entity->setCreatedBy($this->getCurrentUser());
              }
          }
      );
      
  2. Custom Slug Logic:

    • Override generateSlug() in Sluggable:
      protected function generateSlug(string $text): string
      {
          return strtolower(parent::generateSlug($text));
      }
      
  3. Custom Tree Queries:

    • Extend 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();
      }
      
  4. SoftDelete Query Filter:

    • Add a global query filter to exclude soft-deleted entities:
      $entityManager->getFilters()->enable(new SoftDeleteFilter());
      

Configuration Quirks

  1. 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);
          }
      }
      
  2. Translatable Fallback:

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware