Eloquent Viewable Documentation
repository·main·Indexed 21 days ago
https://github.com/cyrildewit/eloquent-viewableA minimalistic analytics package for Laravel that provides view tracking for Eloquent models by storing views as individual database records. It supports calculating total and unique views, filtering by custom time periods using the Period class, queueing view records for high-traffic pages, and ordering models by view count via query scopes.
What's inside Eloquent Viewable
- Eloquent Viewable is a minimalistic analytics package for Laravel designed to track views for Eloquent models. Unlike simple counter increments, it stores each view as an individual database record. This allows for advanced analytics such as calculating total views, unique visitors, and filtering views by custom time periods directly within your application.
How the new Cache Key format works
mainThe internal
CacheKeyclass now uses a readable prefix followed by a hash of the count's full identity ({prefix}:{morph class}:{key}:{digest}). This ensures shorter, fixed-length keys that avoid backend limits (like Memcached's 250-byte cap) and prevent collisions across different models.No action is required for standard usage. Existing cache entries under the old format will be ignored and recomputed on the next
count()call. If you want to clear old entries immediately, runphp artisan cache:clear.How the `Period` class works in v8.0.0
mainIn
v8.0.0,Periodis now afinal, immutable (readonly) value object.Key changes:
- Immutability: Setters like
setStartDateTime()have been removed. You must build a new period instead of mutating an existing one. - No Subclassing: The class is now
finaland cannot be extended. - Removed Methods: The following are no longer available:
getStartDateTimeString(),getEndDateTimeString(),getStartDateTimestamp(),getEndDateTimestamp()(UseDateTimeInterfacegetters instead).PAST_*andSUB_*constants.sub(),subToday(),subNow()static helpers.getSubType(),getSubValue(),hasFixedDateTimes().
Usage Pattern: To get formatted strings or timestamps, use the
DateTimeInterfacereturned bygetStartDateTime()orgetEndDateTime().-$period->getStartDateTimeString(); +$period->getStartDateTime()?->format('Y-m-d H:i:s'); -$period->getStartDateTimestamp(); +$period->getStartDateTime()?->timestamp;- Immutability: Setters like
Set up Eloquent Viewable database migrations
mainAfter installing the package, you must publish and run the migrations to create the necessary tables for storing view records.
- Publish the migrations:
php artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="migrations"- Run the migrations:
php artisan migratephp artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="migrations" php artisan migrateQueue view recording
mainOn high-traffic pages, you can defer the database write to a queued job using the
queue()method. This keeps the request fast.Individual Queueing
Use
views($post)->queue()->record();to queue a specific view.Global Queueing
You can enable queueing globally in the
eloquent-viewable.phpconfig file:'queue' => [ 'enabled' => true, // queue every recorded view 'connection' => null, // null uses the default queue connection 'queue' => null, // null uses the connection's default queue ],If global queueing is enabled, you can force a synchronous record using
views($post)->queue(false)->record();.Important: Request Context
When a view is queued, the
ViewRecordedevent is dispatched from the queue worker. Listeners will run without request context (session, cookies,request(), andauth()->user()will be unavailable). If your listener needs request-derived data, capture it during the request and pass it to the listener manually.// Queue an individual view on the fly views($post)->queue()->record();Prepare your Eloquent model for views
mainTo associate views with a model, the model must implement the
CyrildeWit\EloquentViewable\Contracts\Viewableinterface and use theCyrildeWit\EloquentViewable\InteractsWithViewstrait.use Illuminate\Database\Eloquent\Model; use CyrildeWit\EloquentViewable\InteractsWithViews; use CyrildeWit\EloquentViewable\Contracts\Viewable; class Post extends Model implements Viewable { use InteractsWithViews; // ... }Install Eloquent Viewable via Composer
mainTo install the package, run the following Composer command. Ensure you are using a compatible version of Laravel and PHP as specified in the version compatibility guide.
composer require cyrildewit/eloquent-viewable:^8Migrate the `visitor` column type to string
mainIn
v8.0.0, thecreate_views_tablemigration stub defines thevisitorcolumn as astring(VARCHAR(255)) instead oftextto allow direct indexing.If you have already run the migration and wish to adopt the new type on an existing table, you must create a new migration. Note that on large tables this will rewrite the table, and any
visitorvalue longer than 255 characters will be truncated (though the built-in identifier is only 80 characters).Schema::table('views', function (Blueprint $table) { $table->string('visitor')->nullable()->change(); });Upgrade requirements for v8.0.0
mainWhen upgrading to
v8.0.0, ensure your environment meets the following minimum requirements:- PHP:
^8.5(previously supported^7.4 || ^8.0) - Laravel:
13only (support for Laravel 6 through 12 has been dropped) - Carbon:
^3.0only (support for Carbon 2 has been dropped)
- PHP:
Publish Eloquent Viewable configuration
mainIf you need to customize the package behavior, you can publish the configuration file using the following command:
php artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="config"How the Views API works
mainThe
Viewsclass acts as a fluent builder for managing view interactions with Eloquent models.- Targeting: You start by calling
forViewable($model)to tell the service which model is being viewed. - Configuration: You chain methods like
unique(),period(), orcooldown()to define the constraints of your query or recording action. - Execution: You call an execution method, typically
count()to retrieve data orrecord()to persist a new view.
This pattern allows you to use the same service for both high-frequency recording (often queued) and complex analytical querying (often cached).
- Targeting: You start by calling
Configure connection and cache store defaults
mainThe default configuration for
models.view.connectionandcache.storehas changed tonull. Anullvalue defers to the application's default database connection and default cache store.Important considerations:
- Laravel 11+ Compatibility: Laravel 11 renamed
CACHE_DRIVERtoCACHE_STORE. If your published config still usesenv('CACHE_DRIVER', 'file'), it may ignore your application's actual cache configuration. Setcache.storetonullorenv('CACHE_STORE')to fix this. - Fallback Behavior: If you previously relied on the
filedriver fallback, you should now setcache.storeexplicitly instead of usingnull.
- Laravel 11+ Compatibility: Laravel 11 renamed