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 Extensions Taggable Laravel Package

anh/doctrine-extensions-taggable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

Since this package is Doctrine2-based, Laravel developers will need to integrate it via Doctrine ORM (e.g., using doctrine/dbal and doctrine/orm). Start by installing the package and its dependencies:

composer require anh/doctrine-extensions-taggable doctrine/dbal doctrine/orm

First Use Case: Tagging a Model

  1. Define a Taggable Entity: Extend your model (e.g., Post) with Anh\Taggable\TaggableEntity and annotate it with @Taggable:

    use Anh\Taggable\TaggableEntity;
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    #[ORM\Table(name: 'posts')]
    class Post extends TaggableEntity
    {
        // Your fields (id, title, content, etc.)
    }
    
  2. Configure Doctrine Mappings: Add the taggable mappings to your Doctrine config (e.g., in config/doctrine.php):

    'mappings' => [
        'taggable' => [
            'type' => 'annotation',
            'prefix' => 'Anh\Taggable\Entity',
            'dir' => __DIR__.'/../../vendor/anh/doctrine-extensions-taggable/lib/Anh/Taggable/Entity',
        ],
    ],
    
  3. Initialize the Taggable Manager: Register the TaggableManager as a service in Laravel (e.g., in config/services.php):

    'taggable.manager' => \Anh\Taggable\TaggableManager::class,
    

    Bind it in a service provider:

    $this->app->bind(\Anh\Taggable\TaggableManager::class, function ($app) {
        return new \Anh\Taggable\TaggableManager(
            $app->make(\Doctrine\ORM\EntityManager::class),
            \Anh\Taggable\Entity\Tag::class,
            \Anh\Taggable\Entity\Tagging::class
        );
    });
    
  4. Tag a Model: Use the manager to tag an entity:

    $post = new Post();
    $tagManager = app(\Anh\Taggable\TaggableManager::class);
    $tagManager->tag($post, ['laravel', 'php', 'doctrine']);
    

Implementation Patterns

Workflow: CRUD with Tagging

  1. Create:

    $post = new Post();
    $post->setTitle('Doctrine in Laravel');
    $tagManager->tag($post, ['doctrine', 'orm']);
    $entityManager->persist($post);
    $entityManager->flush();
    
  2. Retrieve Tagged Entities: Use the manager to fetch entities by tags:

    $posts = $tagManager->findByTag('laravel');
    
  3. Update Tags:

    $tagManager->retag($post, ['laravel', 'framework']); // Replaces all tags
    $tagManager->addTag($post, 'updated'); // Adds a tag
    $tagManager->removeTag($post, 'php'); // Removes a tag
    

Integration with Eloquent

Since Laravel primarily uses Eloquent, bridge Doctrine and Eloquent by:

  • Using Doctrine ORM alongside Eloquent (e.g., via laravel-doctrine/orm).
  • Creating a repository pattern to abstract Doctrine queries:
    class PostRepository {
        protected $entityManager;
    
        public function __construct(\Doctrine\ORM\EntityManager $em) {
            $this->entityManager = $em;
        }
    
        public function findByTag($tag) {
            return $this->entityManager->getRepository(Post::class)
                ->createQueryBuilder('p')
                ->where('p IN (
                    SELECT t0.entity FROM Anh\Taggable\Entity\Tagging t0
                    JOIN t0.tag t1 WHERE t1.name = :tag
                )')
                ->setParameter('tag', $tag)
                ->getQuery()
                ->getResult();
        }
    }
    

Event Subscribers

Leverage Doctrine events for automatic tagging (e.g., on postPersist):

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;

class TaggableSubscriber implements EventSubscriber
{
    public function getSubscribedEvents() {
        return ['postPersist'];
    }

    public function postPersist(LifecycleEventArgs $args) {
        $entity = $args->getEntity();
        if ($entity instanceof TaggableEntity) {
            $tagManager = app(\Anh\Taggable\TaggableManager::class);
            $tagManager->tag($entity, ['default']); // Auto-tag new entities
        }
    }
}

Register the subscriber in a service provider:

$this->app->make(\Doctrine\ORM\EntityManager::class)
    ->getEventManager()
    ->addEventSubscriber(new TaggableSubscriber());

Gotchas and Tips

Pitfalls

  1. Doctrine vs. Eloquent Conflict:

    • Avoid mixing raw Eloquent queries with Doctrine queries on taggable entities, as they may not share the same metadata.
    • Fix: Use repositories or abstract the ORM layer.
  2. Tagging Performance:

    • Fetching entities by tags via joins can be slow for large datasets.
    • Fix: Add database indexes on tagging.entity_id and tagging.tag_id:
      CREATE INDEX idx_tagging_entity ON tagging(entity_id);
      CREATE INDEX idx_tagging_tag ON tagging(tag_id);
      
  3. Circular Dependencies:

    • The TaggableManager requires EntityManager, which may not be autowired in Laravel’s DI container.
    • Fix: Explicitly bind the manager as shown in Getting Started.
  4. Case Sensitivity:

    • Tag comparisons are case-sensitive by default. Normalize tags (e.g., strtolower()) if needed:
      $tagManager->tag($post, array_map('strtolower', ['Laravel', 'PHP']));
      

Debugging

  • Check Tagging Tables: Verify tag, tagging, and your entity tables exist and are linked correctly:
    php artisan doctrine:schema:update --dump-sql
    
  • Log Queries: Enable Doctrine logging to debug complex queries:
    $entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    

Extension Points

  1. Custom Tagging Logic: Extend TaggableManager to add validation or business rules:

    class CustomTaggableManager extends \Anh\Taggable\TaggableManager {
        public function tag($entity, array $tags) {
            $tags = $this->validateTags($tags); // Custom logic
            parent::tag($entity, $tags);
        }
    }
    
  2. Tag Hierarchies: Extend the Tag entity to support parent-child relationships:

    #[ORM\ManyToOne(targetEntity: Tag::class, inversedBy: 'children')]
    #[ORM\JoinColumn(name: 'parent_id', referencedColumnName: 'id')]
    private $parent;
    
  3. Soft Deletes: Integrate with laravel-soft-deletes by overriding the Tagging entity’s lifecycle callbacks:

    use Illuminate\Database\Eloquent\SoftDeletes;
    
    class Tagging extends \Anh\Taggable\Entity\Tagging {
        use SoftDeletes;
    }
    

Configuration Quirks

  • Namespace Conflicts: Ensure Anh\Taggable\Entity namespaces are unique in your project (e.g., avoid naming your own Tag entity Anh\Taggable\Entity\Tag).
  • Autoloading: If using Laravel’s autoloader, ensure the Doctrine mappings directory is included in composer.json:
    "autoload": {
        "psr-4": {
            "Anh\\Taggable\\": "vendor/anh/doctrine-extensions-taggable/lib/Anh/Taggable"
        }
    }
    
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