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

diabelb/doctrine-behaviors

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require knplabs/doctrine-behaviors
    

    Ensure your Laravel project uses Doctrine ORM (e.g., via doctrine/orm or laravel-doctrine/orm).

  2. First Use Case: Add a behavior to an entity. For example, to make an entity Blameable (track created/updated by users):

    // src/Entity/Post.php
    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Knp\DoctrineBehaviors\Model\Blameable\BlameableInterface;
    use Knp\DoctrineBehaviors\Model\Blameable\BlameableTrait;
    
    #[ORM\Entity]
    class Post implements BlameableInterface
    {
        use BlameableTrait;
    
        // ... other fields/methods
    }
    
  3. Configuration:

    • For Blameable, set the blameable.user and blameable.ip services in your Doctrine config (e.g., config/packages/doctrine.yaml):
      knp_doctrine_behaviors:
          blameable:
              user: 'App\Service\CurrentUserService'
              ip: 'App\Service\CurrentIpService'
      
  4. Migrations: Run migrations to add required fields (e.g., createdBy, updatedBy for Blameable):

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

Implementation Patterns

Common Workflows

  1. Entity Behaviors:

    • Blameable: Track who created/updated an entity. Useful for auditing.
      $post = new Post();
      $post->setTitle('Hello World');
      $post->setCreatedBy($currentUser); // Automatically set by trait
      
    • Timestampable: Auto-manage createdAt/updatedAt.
      $post->setTitle('Updated');
      // $post->updatedAt is auto-updated
      
    • SoftDeletable: Soft-delete entities (mark as deleted instead of removing).
      $post->delete(); // Sets `deletedAt` instead of deleting
      $deletedPosts = $entityManager->getRepository(Post::class)->findDeleted();
      
  2. Repository Behaviors:

    • Tree: Manage hierarchical data (e.g., categories).
      // src/Repository/CategoryRepository.php
      use Knp\DoctrineBehaviors\ORM\Tree\TreeTrait;
      
      class CategoryRepository extends EntityRepository
      {
          use TreeTrait;
      
          public function getTree(): TreeInterface
          {
              return $this->tree;
          }
      }
      
      Usage:
      $root = $categoryRepo->getRoot();
      $children = $categoryRepo->getChildren($parentCategory);
      
  3. Translatable:

    • Store multi-language content. Requires a Translation entity.
      // src/Entity/Product.php
      use Knp\DoctrineBehaviors\Model\Translatable\TranslatableInterface;
      use Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait;
      
      class Product implements TranslatableInterface
      {
          use TranslatableTrait;
      
          // ...
      }
      
      Usage:
      $product->setTranslation('name', 'en', 'Laptop');
      $translations = $product->getTranslations();
      
  4. Sluggable:

    • Auto-generate SEO-friendly slugs.
      $post->setTitle('My Awesome Post');
      $post->generateSlug(); // Auto-generates `slug` field
      

Integration Tips

  • Laravel-Specific:

    • Use Laravel’s Auth facade to resolve blameable.user:
      knp_doctrine_behaviors:
          blameable:
              user: 'App\Services\AuthService' # Custom service wrapping auth()->user()
      
    • For Uuidable, combine with Laravel’s ramsey/uuid:
      use Ramsey\Uuid\Uuid;
      $post->setId(Uuid::uuid4());
      
  • Custom Logic:

    • Extend traits to add custom validation or business logic:
      trait CustomBlameableTrait extends BlameableTrait
      {
          public function setCreatedBy(User $user): self
          {
              if (!$user->isAdmin()) {
                  throw new \RuntimeException('Only admins can create posts.');
              }
              return parent::setCreatedBy($user);
          }
      }
      
  • Querying:

    • Use repository methods for behavior-specific queries:
      // SoftDeletable: Find non-deleted items
      $activePosts = $entityManager->getRepository(Post::class)->findNonDeleted();
      
      // Tree: Get siblings
      $siblings = $categoryRepo->getSiblings($category);
      

Gotchas and Tips

Pitfalls

  1. Missing Configuration:

    • Forgetting to configure services (e.g., blameable.user) will cause NullReferenceException.
    • Fix: Always validate your config/packages/knp_doctrine_behaviors.yaml.
  2. Migration Order:

    • Behaviors like Blameable or Timestampable add fields. Run migrations after adding traits to entities.
    • Fix: Use doctrine:migrations:diff and migrate in the correct order.
  3. Circular References:

    • Translatable requires a separate Translation entity. Forgetting to define it causes errors.
    • Fix: Follow the Translatable docs to set up the association.
  4. Tree Behavior Quirks:

    • The TreeTrait requires lft/rgt columns for nested sets. If missing, queries fail.
    • Fix: Run migrations or manually add columns:
      ALTER TABLE categories ADD lft INT, ADD rgt INT;
      
  5. Overwriting Defaults:

    • Some traits (e.g., Timestampable) auto-set fields. Overwriting them manually can cause inconsistencies.
    • Fix: Use setCreatedAt()/setUpdatedAt() sparingly; let the trait handle it.
  6. PHPStan Conflicts:

    • If using PHPStan, ensure the extension is installed:
      composer require --dev knplabs/doctrine-behaviors-phpstan
      
    • Fix: Add to phpstan.neon:
      includes:
          - vendor/knplabs/doctrine-behaviors-phpstan/extension.neon
      

Debugging Tips

  1. Enable SQL Logging: Debug tree queries or soft deletes with:

    $entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    
  2. Check Event Listeners: Behaviors use Doctrine events (e.g., prePersist). Disable them temporarily to isolate issues:

    $eventManager->removeEventListeners([YourEntity::class]);
    
  3. Validate Entities: Use Doctrine’s validator to catch pre-save issues:

    $errors = $validator->validate($entity);
    if (count($errors) > 0) {
        throw new \RuntimeException((string) $errors);
    }
    

Extension Points

  1. Custom Events: Extend behaviors by listening to their events. Example for Blameable:

    $eventManager->addEventListener(
        [YourEntity::class],
        function (LifecycleEventArgs $args) {
            $entity = $args->getObject();
            if ($entity instanceof BlameableInterface) {
                // Custom logic before/after save
            }
        },
        ['prePersist', 'preUpdate']
    );
    
  2. Override Trait Methods: Customize behavior logic:

    trait CustomSoftDeletableTrait extends SoftDeletableTrait
    {
        public function delete(): void
        {
            if (!$this->isDeletable()) {
                throw new \RuntimeException('Cannot delete this entity.');
            }
            parent::delete();
        }
    }
    
  3. Add New Behaviors: Create your own traits by following the existing patterns (e.g., BlameableTrait). Example skeleton:

    trait MyCustomBehaviorTrait
    {
        #[ORM\Column]
        private ?string $customField = null;
    
        public function setCustomField(string $value): self
        {
            $this->customField = $value;
            return $this;
        }
    
        // Add lifecycle callbacks
        #[ORM\PrePersist]
        public function prePersist(): void
        {
            $this->customField = strtoupper($this->customField);
    
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