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

Eloquent Taggable Laravel Package

cviebrock/eloquent-taggable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require cviebrock/eloquent-taggable
    

    Run migrations:

    php artisan vendor:publish --provider="Cviebrock\EloquentTaggable\ServiceProvider" --tag="migrations"
    php artisan migrate
    
  2. First Use Case: Add the Taggable trait to your Eloquent model (e.g., Post.php):

    use Cviebrock\EloquentTaggable\Taggable;
    
    class Post extends Model
    {
        use Taggable;
      }
    
  3. Tagging a Model:

    $post = new Post();
    $post->tags()->attach(['laravel', 'php', 'eloquent']);
    $post->save();
    

Where to Look First

  • README: Focus on the Usage section for quick examples.
  • Migrations: Check database/migrations/[timestamp]_create_tags_table.php and database/migrations/[timestamp]_create_model_tag_ppivot_table.php for schema details.
  • API Docs: The package follows Laravel conventions, so Eloquent relationships (hasManyThrough) are well-documented in the source.

Implementation Patterns

Core Workflows

  1. Tagging Models:

    • Attach Tags:
      $model->tags()->attach(['tag1', 'tag2']); // Array or comma-separated string
      $model->tags()->attach('tag3'); // Single tag
      
    • Detach Tags:
      $model->tags()->detach(['tag1']); // Remove specific tags
      $model->tags()->detach(); // Remove all tags
      
  2. Querying by Tags:

    • Find Models with Specific Tags:
      $posts = Post::tags(['laravel'])->get();
      
    • Find Models with Any of Multiple Tags:
      $posts = Post::tags(['laravel', 'php'])->get();
      
    • Exclude Models with Specific Tags:
      $posts = Post::notTags(['spam'])->get();
      
  3. Tag Management:

    • Sync Tags (replace existing tags):
      $model->tags()->sync(['new', 'tags']);
      
    • Toggle Tags (add if missing, remove if present):
      $model->tags()->toggle(['tag1', 'tag2']);
      

Integration Tips

  1. Custom Tag Models: Extend the default Tag model by publishing the provider and modifying the Tag class:

    php artisan vendor:publish --provider="Cviebrock\EloquentTaggable\ServiceProvider" --tag="config"
    

    Override Cviebrock\EloquentTaggable\Tag in app/Models/Tag.php.

  2. Scopes for Complex Queries: Use the package’s built-in scopes or create custom ones:

    class Post extends Model
    {
        use Taggable;
    
        public function scopePopular($query)
        {
            return $query->tags(['popular'])->orderBy('views', 'desc');
        }
    }
    
  3. API Responses: Eager-load tags to avoid N+1 queries:

    $posts = Post::with('tags')->get();
    

    Or use the tagList accessor for a comma-separated string:

    $post->tagList; // "laravel,php,eloquent"
    
  4. Validation: Validate tags in Form Requests:

    public function rules()
    {
        return [
            'tags' => 'sometimes|array',
            'tags.*' => 'string|max:255',
        ];
    }
    

Gotchas and Tips

Pitfalls

  1. Migration Conflicts:

    • If you’ve manually created a tags table, drop it before running the package migrations to avoid conflicts.
    • The package creates two tables: tags (for tag definitions) and [model]_tag (pivot table).
  2. Case Sensitivity: Tags are case-sensitive by default. Normalize tags (e.g., strtolower()) if case-insensitive behavior is needed:

    $model->tags()->attach(array_map('strtolower', ['Laravel', 'PHP']));
    
  3. Tag Duplication: The package prevents duplicate tags automatically, but ensure your input is sanitized to avoid edge cases (e.g., trailing whitespace):

    $tags = array_map('trim', explode(',', $request->input('tags')));
    
  4. Performance with Large Datasets:

    • Avoid whereHas('tags') on tables with millions of rows. Use tags() scopes instead for better performance:
      // Faster:
      Post::tags(['laravel'])->get();
      // Slower (may trigger N+1):
      Post::whereHas('tags', fn($q) => $q->where('name', 'laravel'))->get();
      
  5. Caching Tag Queries: Cache frequent tag-based queries (e.g., "trending tags") to reduce database load:

    $trendingTags = Cache::remember('trending-tags', now()->addHours(1), function () {
        return Tag::whereHas('models')->orderByDesc('models_count')->limit(10)->get();
    });
    

Debugging Tips

  1. Check Pivot Table: If tags aren’t attaching, verify the pivot table exists and has the correct columns (model_id, tag_id, and optionally created_at, updated_at).

  2. Tag Existence: Ensure tags exist before attaching. Use syncWithoutDetaching to avoid errors:

    $model->tags()->syncWithoutDetaching(['tag1', 'tag2']); // Won't detach missing tags
    
  3. Log Queries: Enable Laravel query logging to debug tag-related queries:

    DB::enableQueryLog();
    $model->tags()->attach(['test']);
    dd(DB::getQueryLog());
    

Extension Points

  1. Custom Tag Sync Logic: Override the syncTags method in your model:

    public function syncTags(array $tags)
    {
        // Custom logic (e.g., log tag changes)
        $this->tags()->sync($tags);
    }
    
  2. Tag Events: Listen for tag-related events (e.g., tagging, tagged) via the taggable facade:

    use Cviebrock\EloquentTaggable\Taggable as EloquentTaggable;
    
    EloquentTaggable::listen('tagging', function ($model, $tags) {
        // Log or process tags before attachment
    });
    
  3. Custom Tag Model Methods: Add methods to the Tag model for business logic:

    class Tag extends \Cviebrock\EloquentTaggable\Tag
    {
        public function isTrending()
        {
            return $this->models_count > 100;
        }
    }
    
  4. API Resources: Create a custom TagResource to format tag responses:

    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'slug' => Str::slug($this->name),
            'models_count' => $this->models()->count(),
        ];
    }
    
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