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

Watchable Laravel Package

jamesmills/watchable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require jamesmills/watchable
    

    For Laravel <5.5, register the service provider in config/app.php:

    'providers' => [
        // ...
        Jamesmills\Watchable\WatchableServiceProvider::class,
    ],
    
  2. Enable Watchable on a Model: Use the Watchable trait in your Eloquent model (e.g., Post.php):

    use Jamesmills\Watchable\Watchable;
    
    class Post extends Model
    {
        use Watchable;
    }
    
  3. Migrate the Database: Publish and run the migrations:

    php artisan vendor:publish --provider="Jamesmills\Watchable\WatchableServiceProvider" --tag="migrations"
    php artisan migrate
    
  4. First Use Case: Watch a model instance:

    $post = Post::find(1);
    $post->watch(); // User is authenticated via Laravel's auth
    

Implementation Patterns

Core Workflows

  1. Watching/Unwatching Models:

    // Watch a model
    $post->watch(); // Creates a watch record for the authenticated user
    
    // Unwatch a model
    $post->unwatch(); // Removes the watch record
    
    // Check if a model is watched
    $isWatched = $post->isWatched(); // Returns boolean
    
  2. Querying Watched Models: Fetch all watched models for the current user:

    $watchedPosts = Post::watched()->get();
    
  3. Events and Notifications: Listen for watched and unwatched events:

    // In EventServiceProvider
    protected $listen = [
        'Jamesmills\Watchable\Events\Watched' => [
            'App\Listeners\SendWatchNotification',
        ],
        'Jamesmills\Watchable\Events\Unwatched' => [
            'App\Listeners\HandleUnwatchLogic',
        ],
    ];
    

    Trigger notifications via the notify method:

    $post->watch()->notify(new PostWatchedNotification());
    
  4. Customizing Watch Behavior: Override the getWatchableKey() method in your model to use a custom key (e.g., slug):

    public function getWatchableKey()
    {
        return $this->slug;
    }
    

Integration Tips

  1. Middleware for Protected Routes: Use middleware to restrict access to watched models:

    Route::middleware(['auth', 'can:view-watched'])->group(function () {
        Route::get('/watched', [PostController::class, 'index']);
    });
    
  2. Eager Loading Watched Models: Optimize queries by eager-loading watches:

    $posts = Post::with(['watches' => function($query) {
        $query->where('user_id', auth()->id());
    }])->get();
    
  3. Batch Processing: Use syncWatched() to update watches in bulk (e.g., for syncing with an external service):

    $post->syncWatched([1, 2, 3]); // Watch IDs 1, 2, 3
    
  4. Scopes for Complex Queries: Combine scopes for advanced filtering:

    $watchedAndPublished = Post::watched()->published()->get();
    

Gotchas and Tips

Pitfalls

  1. Authentication Dependency:

    • The package assumes the current user is authenticated. Always verify auth()->check() before calling watch()/unwatch().
    • Fix: Wrap calls in middleware or add checks:
      if (auth()->check()) {
          $post->watch();
      }
      
  2. Key Collisions:

    • If getWatchableKey() returns the same value for multiple models, watches may behave unexpectedly.
    • Fix: Ensure uniqueness (e.g., use id by default or override getWatchableKey() carefully).
  3. Migration Conflicts:

    • The watches table may conflict with existing tables if not published correctly.
    • Fix: Run php artisan vendor:publish --tag=migrations and review the generated migration.
  4. Event Listener Order:

    • Events (Watched, Unwatched) fire after the watch is created/removed. If you need pre-actions, use model observers or middleware.

Debugging

  1. Check Watch Records: Inspect the watches table directly or log queries:

    \DB::enableQueryLog();
    $post->watch();
    \Log::info(\DB::getQueryLog());
    
  2. Verify User ID: Ensure the user_id in the watches table matches the authenticated user:

    $this->assertEquals(auth()->id(), $post->watches()->first()->user_id);
    
  3. Clear Cached Config: If changes to config aren’t reflected, clear the config cache:

    php artisan config:clear
    

Extension Points

  1. Custom Watch Model: Extend the Watch model (published via php artisan vendor:publish --tag=watchable-models):

    class CustomWatch extends \Jamesmills\Watchable\Models\Watch
    {
        protected $table = 'custom_watches';
    }
    

    Update the trait to use your model:

    use Jamesmills\Watchable\Concerns\UsesCustomWatchModel;
    
  2. Add Metadata to Watches: Attach extra data to watches via accessors/mutators:

    // In Watch model
    protected $casts = ['metadata' => 'array'];
    
    // When watching
    $post->watch(['notified_at' => now()]);
    
  3. Custom Watch Logic: Override the watch() method in your model:

    public function watch(array $options = [])
    {
        $this->fireModelEvent('watching', false);
        $result = parent::watch($options);
        $this->fireModelEvent('watched', false);
        return $result;
    }
    
  4. Soft Deletes: If your models use soft deletes, ensure the watches table also supports soft deletes:

    use Illuminate\Database\Eloquent\SoftDeletes;
    
    class Watch extends Model
    {
        use SoftDeletes;
        protected $dates = ['deleted_at'];
    }
    
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.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony