Weave 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

Doctrineextensions Laravel Package

beberlei/doctrineextensions

A set of useful extensions for Doctrine ORM/DBAL, adding extra DQL functions and database features such as date/time, string and math functions. Helps bridge common SQL capabilities across platforms and improves query expressiveness in Doctrine.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the package via Composer:

    composer require beberlei/doctrineextensions
    

    Register the extensions in your config/doctrine.php (or equivalent) by extending the Doctrine\ORM\Configuration:

    use DoctrineExtensions\ORM\Config\DoctrineExtensions;
    use Doctrine\ORM\Configuration;
    
    $config = Configuration::create();
    $config->registerExtensions(new DoctrineExtensions());
    
  2. First Use Case: Soft Deletes Enable soft deletes for an entity by:

    • Adding the SoftDeleteable trait to your model:
      use DoctrineExtensions\ORM\SoftDeleteable\Entity;
      use DoctrineExtensions\ORM\SoftDeleteable\SoftDeleteableEntity;
      
      class User extends Entity implements SoftDeleteableEntity
      {
          use SoftDeleteable;
      }
      
    - Adding the `deletedAt` column to your migration:
      ```php
      $table->timestamp('deleted_at')->nullable()->after('updated_at');
    
    • Querying soft-deleted records:
      $softDeletedUsers = $entityManager->getRepository(User::class)
          ->findBy([], ['deletedAt' => 'DESC'], null, ['SoftDeleteable']);
      

Implementation Patterns

Common Workflows

  1. Soft Deletes

    • Deleting Records:
      $user = $entityManager->find(User::class, 1);
      $user->delete(); // Soft delete (sets `deletedAt` timestamp)
      
    • Permanent Deletion:
      $user->forceDelete(); // Hard delete (removes record entirely)
      
    • Querying Soft-Deleted Records:
      $queryBuilder = $entityManager->getRepository(User::class)->createQueryBuilder('u');
      $queryBuilder->where('u.deletedAt IS NULL'); // Only active records
      // OR
      $queryBuilder->andWhere('u.deletedAt IS NOT NULL'); // Only soft-deleted records
      
  2. Sluggable Entities

    • Enable slug generation in your entity:
      use DoctrineExtensions\ORM\Sluggable\SluggableEntity;
      use DoctrineExtensions\ORM\Sluggable\Sluggable;
      
      class Post implements SluggableEntity
      {
          use Sluggable;
      
          protected $slugFieldName = 'slug';
          protected $sluggableFields = ['title'];
      }
      
    • Generate slugs manually:
      $post = new Post();
      $post->setTitle('My Awesome Post');
      $post->generateSlug(); // Generates slug from `title`
      
  3. Tree Entities (Nested Sets)

    • Define a tree structure:
      use DoctrineExtensions\ORM\Tree\TreeEntity;
      use DoctrineExtensions\ORM\Tree\Tree;
      
      class Category implements TreeEntity
      {
          use Tree;
      }
      
    • Manipulate the tree:
      $parent = $entityManager->find(Category::class, 1);
      $child = new Category();
      $child->setParent($parent);
      $entityManager->persist($child);
      $entityManager->flush();
      
  4. Sortable Entities

    • Enable sorting:
      use DoctrineExtensions\ORM\Sortable\SortableEntity;
      use DoctrineExtensions\ORM\Sortable\Sortable;
      
      class Product implements SortableEntity
      {
          use Sortable;
      }
      
    • Reorder items:
      $product = $entityManager->find(Product::class, 1);
      $product->moveUp(); // or moveDown(), moveToTop(), moveToBottom()
      

Integration Tips

  1. Laravel-Specific Setup

    • Override Doctrine\ORM\EntityManager in your service provider to register extensions:
      $entityManager->getConfiguration()->registerExtensions(new DoctrineExtensions());
      
  2. Customizing Behavior

    • Override default slug generation:
      protected function generateSlugFromFields()
      {
          return str_slug($this->title . '-' . $this->id);
      }
      
    • Customize soft delete behavior:
      protected $dateTimeType = 'datetime'; // or 'timestamp'
      protected $deletedAtColumn = 'deleted_at';
      
  3. Querying with Extensions

    • Use DQL for advanced queries:
      $query = $entityManager->createQuery(
          'SELECT u FROM App\Entity\User u WHERE u.deletedAt IS NULL'
      );
      
  4. Event Listeners

    • Attach listeners for pre/post operations:
      $entityManager->getEventManager()->addEventListener(
          \Doctrine\ORM\Events::prePersist,
          function (LifecycleEventArgs $args) {
              $entity = $args->getEntity();
              if ($entity instanceof SluggableEntity) {
                  $entity->generateSlug();
              }
          }
      );
      

Gotchas and Tips

Pitfalls

  1. Soft Deletes and Migrations

    • Issue: Forgetting to add deletedAt to migrations can cause errors.
    • Fix: Always include the column in your schema:
      $table->timestamp('deleted_at')->nullable()->after('updated_at');
      
  2. Tree Entities and Performance

    • Issue: Deeply nested trees can slow down queries.
    • Fix: Use MaterializedPath or NestedSet strategies wisely. For large trees, consider MaterializedPath.
  3. Slug Conflicts

    • Issue: Duplicate slugs may occur if not handled.
    • Fix: Implement a unique constraint in the database and override generateSlug() to append a counter if needed.
  4. Sortable Entities and Concurrency

    • Issue: Race conditions can occur when reordering items.
    • Fix: Use database transactions or optimistic locking:
      $entityManager->beginTransaction();
      try {
          $product->moveUp();
          $entityManager->flush();
          $entityManager->commit();
      } catch (\Exception $e) {
          $entityManager->rollBack();
          throw $e;
      }
      
  5. Doctrine Version Compatibility

    • Issue: Some extensions may not work with older Doctrine versions.
    • Fix: Check the package's composer.json for supported versions and update Doctrine accordingly.

Debugging Tips

  1. Enable SQL Logging Debug queries to understand how extensions modify them:

    $entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    
  2. Check Event Subscribers Extensions often rely on Doctrine events. Verify they are registered:

    $eventManager = $entityManager->getEventManager();
    $listeners = $eventManager->getListeners();
    
  3. Use DQL for Complex Queries Extensions may not work as expected with QueryBuilder. Use DQL directly:

    $query = $entityManager->createQuery('SELECT u FROM App\Entity\User u WHERE u.deletedAt IS NULL');
    
  4. Clear Cache After Configuration Changes Extensions may require cache clearing:

    php artisan doctrine:cache:clear-metadata
    php artisan doctrine:cache:clear-query
    

Extension Points

  1. Custom Soft Delete Logic Extend the SoftDeleteable trait to add custom logic:

    protected function getDeletedAtValue()
    {
        return new \DateTime('now', new \DateTimeZone('UTC'));
    }
    
  2. Add New Sluggable Fields Dynamically Override getSluggableFields():

    public function getSluggableFields()
    {
        return ['title', 'subtitle'];
    }
    
  3. Custom Tree Strategies Implement your own tree strategy by extending DoctrineExtensions\ORM\Tree\TreeStrategy.

  4. Hook into Lifecycle Events Use Doctrine lifecycle callbacks for custom logic:

    use Doctrine\ORM\Mapping as ORM;
    
    class User
    {
        /**
         * @ORM\PrePersist
         */
        public function prePersist()
        {
            $this->generateSlug();
        }
    }
    
  5. Integrate with Laravel Events Dispatch Laravel events when extensions trigger actions:

    use Illuminate\Support\Facades\Event;
    
    $entityManager->getEventManager()->addEventListener(
        \Doctrine\ORM\Events::preRemove,
        function (LifecycleEventArgs $args) {
            $entity = $args->getEntity();
            if ($entity instanceof SoftDeleteableEntity) {
                Event::dispatch('user.softDeleting', $entity);
            }
        }
    );
    
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json