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

Doctrineextensions Laravel Package

beberlei/doctrineextensions

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