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 Viewable Laravel Package

cyrildewit/eloquent-viewable

Track and query page views on Eloquent models without external analytics. Record views with optional cooldown, count totals/unique views, filter by date periods, order models by views, and ignore crawlers. Stores each view as a DB record.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require cyrildewit/eloquent-viewable
   php artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="migrations"
   php artisan migrate

(Optional: Publish config with --tag="config")

  1. Model Integration: Add InteractsWithViews trait and implement Viewable interface to your Eloquent model:

    use CyrildeWit\EloquentViewable\InteractsWithViews;
    use CyrildeWit\EloquentViewable\Contracts\Viewable;
    
    class Post extends Model implements Viewable
    {
        use InteractsWithViews;
    }
    
  2. First Use Case: Track views in a controller:

    public function show(Post $post)
    {
        views($post)->record(); // Record view
        return view('post.show', compact('post'));
    }
    

    Retrieve counts:

    $totalViews = views($post)->count();
    $uniqueViews = views($post)->unique()->count();
    

Implementation Patterns

Core Workflows

  1. View Recording:

    • Standard: views($model)->record();
    • With Cooldown: views($model)->cooldown(now()->addHours(2))->record();
    • Custom Collections: views($model)->collection('premium')->record();
  2. Querying Views:

    • Periodic Counts: views($post)->period(Period::pastDays(7))->count();
    • Unique Counts: views($post)->unique()->count();
    • Type-Level Counts: views(new Post())->count();
  3. Model Ordering:

    // Order posts by total views (descending)
    Post::orderByViews()->get();
    
    // Order by unique views in last 30 days
    Post::orderByUniqueViews('asc', Period::pastDays(30))->get();
    
  4. Caching:

    // Cache for 1 hour
    views($post)->remember(3600)->count();
    
    // Cache until specific date
    views($post)->remember(now()->addWeek())->count();
    

Integration Tips

  • Middleware: Create middleware to auto-record views for routes:
    public function handle($request, Closure $next)
    {
        views($request->route('post'))->record();
        return $next($request);
    }
    
  • API Responses: Include view counts in JSON responses:
    return response()->json([
        'post' => $post,
        'views' => views($post)->count(),
        'unique_views' => views($post)->unique()->count()
    ]);
    
  • Admin Panels: Use for trending content:
    $trending = Post::orderByViews('desc', Period::pastHours(24))->take(5)->get();
    

Gotchas and Tips

Common Pitfalls

  1. Crawler Filtering:

    • Default behavior blocks crawlers (Postman, bots). Test locally with:
      config(['eloquent-viewable.ignore_crawlers' => false]);
      
    • Exclude specific IPs in config/eloquent-viewable.php:
      'ignored_ips' => ['127.0.0.1', '192.168.1.*'],
      
  2. Database Bloat:

    • Solution: Add indexes to views table:
      Schema::table('views', function (Blueprint $table) {
          $table->index(['viewable_type', 'viewable_id', 'visitor']);
      });
      
    • Warning: Unique visitor tracking requires visitor column indexing.
  3. Cooldown Misuse:

    • Session-based cooldowns expire when the session ends. For persistent cooldowns, use database storage:
      views($post)->cooldown(now()->addDays(7))->record();
      
  4. Caching Caveats:

    • Cache keys include the entire query chain. Avoid caching dynamic periods:
      // ❌ Avoid (dynamic period)
      views($post)->period(Period::since($userInputDate))->remember()->count();
      
      // ✅ Better (static period)
      views($post)->period(Period::pastDays(7))->remember()->count();
      

Debugging Tips

  1. View Records: Inspect raw records:

    $views = \CyrildeWit\EloquentViewable\View::where('viewable_id', $post->id)->get();
    
  2. Visitor Tracking: Check visitor identification logic in Visitor class. Override if needed:

    // config/eloquent-viewable.php
    'visitor_resolver' => \App\Services\CustomVisitorResolver::class;
    
  3. Performance:

    • Use remember() for static queries.
    • For dynamic queries, consider denormalizing counts (e.g., unique_views_count column).

Extension Points

  1. Custom Visitor Data: Extend Visitor model or override resolver:

    // app/Providers/EloquentViewableServiceProvider.php
    public function boot()
    {
        \CyrildeWit\EloquentViewable\Visitor::addResolveCallback(function ($request) {
            return $request->user() ? $request->user()->id : $request->ip();
        });
    }
    
  2. Custom View Model: Replace View model by binding your own in the service provider:

    $this->app->bind(
        \CyrildeWit\EloquentViewable\Contracts\View::class,
        \App\Models\CustomView::class
    );
    
  3. Crawler Detection: Replace CrawlerDetectAdapter:

    $this->app->bind(
        \CyrildeWit\EloquentViewable\Contracts\CrawlerDetect::class,
        \App\Services\CustomCrawlerDetector::class
    );
    
  4. Macros: Add custom methods to Views facade:

    \CyrildeWit\EloquentViewable\Views::macro('trending', function () {
        return $this->period(Period::pastHours(24))->orderBy('created_at', 'desc');
    });
    

    Usage:

    views($post)->trending()->count();
    

Pro Tips

  • Batch Updates: Use scheduled jobs to update denormalized counts:
    // app/Console/Commands/UpdateViewCounts.php
    public function handle()
    {
        Post::chunk(100, function ($posts) {
            foreach ($posts as $post) {
                $post->unique_views_count = views($post)->unique()->count();
                $post->save();
            }
        });
    }
    
  • Soft Deletes: Combine with SoftDeletes trait for graceful view cleanup:
    class Post extends Model implements Viewable
    {
        use InteractsWithViews, SoftDeletes;
    }
    
  • Analytics Dashboard: Use package for real-time dashboards:
    $recentViews = \CyrildeWit\EloquentViewable\View::where('created_at', '>', now()->subHours(1))
        ->with('viewable')
        ->get();
    
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony