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

nitra/doctrine-behaviors

PHP 5.4+ trait-based behaviors for Doctrine2 entities and repositories: tree, translatable, timestampable, soft deletable, blameable, loggable, geocodable, filterable, and sluggable. Includes optional Doctrine event listeners for behavior support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require knplabs/doctrine-behaviors
    

    For Symfony, import the YAML config:

    # config/packages/doctrine_behaviors.yaml
    imports:
        - { resource: "@KnpDoctrineBehaviors/config/orm-services.yml" }
    
  2. First Use Case: Add a behavior trait to an entity (e.g., Timestampable):

    use Knp\DoctrineBehaviors\Model as ORMBehaviors;
    
    class Post
    {
        use ORMBehaviors\Timestampable\Timestampable;
    }
    

    Ensure the entity has use Doctrine\ORM\Mapping as ORM; at the top.

  3. Verify Listeners: For behaviors requiring listeners (e.g., Translatable, Blameable), confirm they’re registered via Symfony’s DI or manually:

    $em->getEventManager()->addEventSubscriber(new \Knp\DoctrineBehaviors\ORM\Translatable\TranslatableListener);
    

Implementation Patterns

Common Workflows

  1. Combining Behaviors: Chain traits in a single entity (e.g., Tree + Translatable):

    class Category
    {
        use ORMBehaviors\Tree\Node,
           ORMBehaviors\Translatable\Translatable;
    }
    
    • Tree: Use getTree() in the repository to fetch hierarchical data.
    • Translatable: Create a CategoryTranslation entity and use translate('locale')->setField().
  2. Repository-Level Behaviors: Extend repositories with traits like Filterable or Tree:

    class CategoryRepository extends EntityRepository
    {
        use ORMBehaviors\Tree\Tree;
        use ORMBehaviors\Filterable\FilterableRepository;
    
        public function getLikeFilterColumns() { return ['name']; }
    }
    
  3. Dynamic Slugs: Override getSluggableFields() for custom slug generation:

    class BlogPost
    {
        use ORMBehaviors\Sluggable\Sluggable;
    
        public function getSluggableFields() { return ['title', 'author']; }
    }
    
  4. Geocoding: Integrate with geocoder/geocoder for address-to-coordinates conversion:

    $geocoder = new \Geocoder\Geocoder();
    $listener->setGeolocationCallable(function($entity) use ($geocoder) {
        $location = $geocoder->geocode($entity->getAddress());
        $entity->setLocation(new Point($location->getLatitude(), $location->getLongitude()));
    });
    

Integration Tips

  • Symfony Forms: Use Translatable with Symfony\Bridge\Doctrine\Form\Type\EntityType for locale-aware fields.
  • APIs: Leverage Blameable to track user actions in audit logs.
  • Soft Deletes: Override isDeleted() logic to exclude records from queries:
    $qb->andWhere('entity.deletedAt IS NULL');
    

Gotchas and Tips

Pitfalls

  1. Listener Registration:

    • Forgetting to register listeners (e.g., TranslatableListener) causes silent failures. Verify via:
      $em->getEventManager()->getListeners();
      
    • Fix: Use Symfony’s orm-services.yml or register manually.
  2. Annotation Driver:

    • Traits like Translatable require @ORM\Entity annotations. Missing use Doctrine\ORM\Mapping as ORM; breaks functionality.
  3. Tree Behavior:

    • Nodes must have an id set before setChildOf():
      $child->setId(2); // Required!
      $child->setChildOf($parent);
      
    • Fix: Use postPersist lifecycle callbacks to auto-assign IDs.
  4. Slug Uniqueness:

    • Sluggable does not enforce uniqueness. Handle collisions manually:
      $slug = $this->generateSlug();
      if ($this->slugExists($slug)) {
          $slug = $slug . '-' . uniqid();
      }
      
  5. Geocodable Dependencies:

    • PostgreSQL cube/earthdistance extensions are required for spatial queries. Test with:
      CREATE EXTENSION cube;
      

Debugging

  • Event Subscribers: Check if listeners are active:
    $listeners = $em->getEventManager()->getListeners();
    print_r(array_keys($listeners));
    
  • Translatable Proxies: Ensure __call() proxies translations correctly:
    public function __call($method, $args) {
        if (strpos($method, 'get') === 0) {
            return $this->proxyCurrentLocaleTranslation($method, $args);
        }
        throw new \BadMethodCallException(...);
    }
    

Extension Points

  1. Custom Callables:
    • Override default callables (e.g., Blameable user provider):
      $listener->setUserCallable(function() {
          return $this->getCurrentUser(); // Your logic
      });
      
  2. Filterable Joins:
    • Extend createFilterQueryBuilder() for complex joins:
      protected function createFilterQueryBuilder() {
          return $this->createQueryBuilder('e')
              ->leftJoin('e.tags', 't')
              ->where('t.name = :tag');
      }
      
  3. Timestampable Overrides:
    • Disable auto-updating updatedAt:
      public function setUpdatedAt($date = null) { /* No-op */ }
      
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity