Installation
composer require edumedia/tag-bundle
Add the bundle to config/bundles.php:
return [
// ...
eduMedia\TagBundle\TagBundle::class => ['all' => true],
];
Define Core Entities
Create Tag and Tagging entities as shown in the README. These are the foundational models for the bundle.
Tag an Entity
Use the TagService to attach tags to any entity:
use eduMedia\TagBundle\Service\TagService;
// In a controller or service
$tagService = $this->container->get(TagService::class);
$user = $this->entityManager->getRepository(User::class)->find(1);
$tagService->tag($user, ['laravel', 'php']);
Fetch Tags Retrieve tags for an entity:
$tags = $tagService->getTags($user);
Categorize Blog Posts
Post entity implementing TaggableInterface.TagService to assign tags like ['laravel', 'tutorial'] to posts.{% for tag in post.tags %}
<span class="tag">{{ tag.name }}</span>
{% endfor %}
Tagging Entities
TagService::tag() to attach tags to any entity (e.g., User, Post).
$tagService->tag($entity, ['tag1', 'tag2']);
$tagService->bulkTag([$entity1, $entity2], ['common-tag']);
Querying Tags
$tagService->findByTag('laravel', Post::class);
TagService::autocomplete() for search-as-you-type functionality:
$suggestions = $tagService->autocomplete('lar', 5); // Top 5 matches for 'lar'
Tag Management
TagService:
$tagService->createTag('new-tag', ['slug' => 'custom-slug']);
Tagging entities):
$tagService->deleteTag($tag);
EntityType with Tag for tag selection:
$builder->add('tags', EntityType::class, [
'class' => Tag::class,
'multiple' => true,
'expanded' => true,
]);
#[Route('/posts/{id}/tags', methods: ['POST'])]
public function addTags(Post $post, Request $request): JsonResponse
{
$tags = json_decode($request->getContent(), true);
$this->tagService->tag($post, $tags);
return new JsonResponse(['status' => 'success']);
}
TagAddedEvent) to trigger side effects:
$dispatcher->addListener(TagAddedEvent::class, function (TagAddedEvent $event) {
// Log or notify when tags are added
});
Tag Ownership
fpn/tag-bundle). This means:
tags property on User or Post; use TagService to fetch tags.Tagging entities can cause N+1 queries. Use fetch: 'EAGER' or DQL joins:
$query->leftJoin('tagging', 't', 'WITH', 't.tagged = :entity')
->where('t.tagged = :entity');
Tagging Entity Requirements
TaggableInterface and include the TaggableTrait:
use eduMedia\TagBundle\Entity\TaggableInterface;
use eduMedia\TagBundle\Entity\TaggableTrait;
class Post implements TaggableInterface
{
use TaggableTrait;
// ...
}
TagService to throw exceptions.Tagging Join Table
Tagging entity’s tagged field must reference the primary key of the taggable entity (e.g., user.id). Misconfiguration breaks tagging.TaggableTrait to auto-generate the tagged field correctly.Case Sensitivity
TagService::normalizeTag() to enforce consistency:
$normalizedTag = $tagService->normalizeTag('Laravel'); // 'laravel'
Tagging entity’s tagged field points to the correct entity ID:
$tagging = $entityManager->getRepository(Tagging::class)->findOneBy(['tag' => $tag]);
dump($tagging->getTagged()->getId()); // Should match your entity's ID
$entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
TagAddedEvent or TagRemovedEvent payloads.Custom Tag Storage
TagService to use a custom repository or cache layer:
class CustomTagService extends TagService
{
public function getTags(object $taggable): array
{
// Custom logic (e.g., cache results)
return parent::getTags($taggable);
}
}
services.yaml:
services:
App\Service\CustomTagService: '@eduMedia\TagBundle\Service\TagService'
Tag Validation
TagInterface to add validation rules (e.g., max length):
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\Length(max: 50)]
protected string $name;
Tagging Strategies
TagService:
public function tag(object $taggable, array $tags, string $strategy = 'default')
{
if ($strategy === 'hierarchical') {
// Custom logic
}
parent::tag($taggable, $tags);
}
Performance
BatchProcessing:
$connection = $entityManager->getConnection();
$connection->beginTransaction();
// Bulk INSERT/UPDATE queries
$connection->commit();
tagging.tagged and tagging.tag for faster queries:
CREATE INDEX idx_tagging_tagged ON tagging(tagged);
CREATE INDEX idx_tagging_tag ON tagging(tag);
Tagging entity’s tagged field uses the correct type (e.g., string for UUIDs, integer for auto-increment IDs).TagService methods:
php bin/console cache:clear
TagTranslation entity or Symfony’s translation system for multilingual tags.How can I help you explore Laravel packages today?