anh/doctrine-extensions-taggable
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
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.)
}
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',
],
],
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
);
});
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']);
Create:
$post = new Post();
$post->setTitle('Doctrine in Laravel');
$tagManager->tag($post, ['doctrine', 'orm']);
$entityManager->persist($post);
$entityManager->flush();
Retrieve Tagged Entities: Use the manager to fetch entities by tags:
$posts = $tagManager->findByTag('laravel');
Update Tags:
$tagManager->retag($post, ['laravel', 'framework']); // Replaces all tags
$tagManager->addTag($post, 'updated'); // Adds a tag
$tagManager->removeTag($post, 'php'); // Removes a tag
Since Laravel primarily uses Eloquent, bridge Doctrine and Eloquent by:
laravel-doctrine/orm).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();
}
}
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());
Doctrine vs. Eloquent Conflict:
Tagging Performance:
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);
Circular Dependencies:
TaggableManager requires EntityManager, which may not be autowired in Laravel’s DI container.Case Sensitivity:
strtolower()) if needed:
$tagManager->tag($post, array_map('strtolower', ['Laravel', 'PHP']));
tag, tagging, and your entity tables exist and are linked correctly:
php artisan doctrine:schema:update --dump-sql
$entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
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);
}
}
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;
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;
}
Anh\Taggable\Entity namespaces are unique in your project (e.g., avoid naming your own Tag entity Anh\Taggable\Entity\Tag).composer.json:
"autoload": {
"psr-4": {
"Anh\\Taggable\\": "vendor/anh/doctrine-extensions-taggable/lib/Anh/Taggable"
}
}
How can I help you explore Laravel packages today?