Package Data | |
---|---|
Maintainer Username: | cyrildewit |
Maintainer Contact: | info@cyrildewit.nl (Cyril de Wit) |
Package Create Date: | 2017-06-12 |
Package Last Update: | 2024-10-28 |
Home Page: | |
Language: | PHP |
License: | MIT |
Last Refreshed: | 2024-11-15 03:04:10 |
Package Statistics | |
---|---|
Total Downloads: | 864,884 |
Monthly Downloads: | 10,688 |
Daily Downloads: | 448 |
Total Stars: | 836 |
Total Watchers: | 16 |
Total Forks: | 107 |
Total Open Issues: | 1 |
This Laravel >= 5.5 package allows you to associate views with Eloquent models.
Once installed you can do stuff like this:
// Return total views count
views($post)->count();
// Return total views count that have been made since 20 February 2017
views($post)->period(Period::since('2017-02-20'))->count();
// Return total views count that have been made between 2014 and 216
views($post)->period(Period::create('2014', '2016'))->count();
// Return total unique views count (based on visitor cookie)
views($post)->unique()->count();
// Record a new view
views($post)->record();
// Record a new view with session delay between views
views($post)->delayInSession(now()->addHours(2))->record();
Eloquent Viewable allows you to easiliy associate views with Eloquent models. It's designed with simplicity in mind. This package will save all view records in a database table, so we can make different views counts. For example, if we want to know how many people has viewed a specific post between January 10 and February 17 in 2018, we can do the following: $post->views()->period(Period::create('10-01-2018', '17-02-2018'))->count();
.
This package is not built with the intent to collect analytical data. It is made to simply store the views of a Laravel Eloquent model. You would use this package for models like: Post, Video, Profile and Hotel, but of course, you can use this package as you want.
Here are some of the main features:
In this documentation, you will find some helpful information about the use of this Laravel package.
This package requires PHP 7.1+ and Laravel 5.5+.
Lumen is not supported!
| Version | Illuminate | Status | PHP Version | |---------|------------|----------------|-------------| | ^3.0 | 5.5 - 5.8 | Active support | >= 7.1.0 | | ^2.0 | 5.5 - 5.7 | Bug fixes only | >= 7.0.0 | | ^1.0 | 5.5 - 5.6 | Bug fixes only | >= 7.0.0 |
First, you need to install the package via Composer:
composer require cyrildewit/eloquent-viewable
Secondly, you can publish the migrations with:
php artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="migrations"
Finally, you need to run the migrate
command:
php artisan migrate
You can optionally publish the config file with:
php artisan vendor:publish --provider="CyrildeWit\EloquentViewable\EloquentViewableServiceProvider" --tag="config"
If you prefer to register packages manually, you can add the following provider to your application's providers list.
// config/app.php
'providers' => [
// ...
CyrildeWit\EloquentViewable\EloquentViewableServiceProvider::class,
];
To associate views with a model, the model must implement the following interface and trait.
use Illuminate\Database\Eloquent\Model;
use CyrildeWit\EloquentViewable\Viewable;
use CyrildeWit\EloquentViewable\Contracts\Viewable as ViewableContract;
class Post extends Model implements ViewableContract
{
use Viewable;
// ...
}
To make a view record, you can call the record
method on the fluent Views
instance.
views($post)->record();
The best place where you should record a visitors's view would be inside your controller. For example:
// PostController.php
public function show(Post $post)
{
views($post)->record();
return view('post.show', compact('post'));
}
// ...
Note: This package filters out crawlers by default. Be aware of this when testing, because Postman is for example also a crawler.
You may use the delayInSession
method on the Views
instance to add a delay between view records. When you set a delay, you need to specify the number of minutes.
views($post)
->delayInSession($minutes)
->record();
Instead of passing the number of minutes as an integer, you can also pass a DateTime
instance.
$expiresAt = now()->addHours(3);
views($post)
->delayInSession($expiresAt)
->record();
When recording a view with a session delay, this package will also save a snapshot of the view in the visitor's session with an expiration datetime. Whenever the visitor views the item again, this package will checks his session and decide if the view should be saved in the database or not.
views($post)->count();
use CyrildeWit\EloquentViewable\Support\Period;
// Example: get views count since 2017 upto 2018
views($post)
->period(Period::create('2017', '2018'))
->count();
The Period
class that comes with this package provides many handy features. The API of the Period
class looks as follows:
$startDateTime = Carbon::createFromDate(2017, 4, 12);
$endDateTime = '2017-06-12';
Period::create($startDateTime, $endDateTime);
Period::since(Carbon::create(2017));
Period::upto(Carbon::createFromDate(2018, 6, 1));
Uses Carbon::today()
as start datetime minus the given unit.
Period::pastDays(int $days);
Period::pastWeeks(int $weeks);
Period::pastMonths(int $months);
Period::pastYears(int $years);
Uses Carbon::now()
as start datetime minus the given unit.
Period::subSeconds(int $seconds);
Period::subMinutes(int $minutes);
Period::subHours(int $hours);
Period::subDays(int $days);
Period::subWeeks(int $weeks);
Period::subMonths(int $months);
Period::subYears(int $years);
If you only want to retrieve the unique views count, you can simply add the unique
method to the chain.
views($post)
->unique()
->count();
The Viewable
trait adds two scopes to your model: orderByViews
and orderByUniqueViews
.
Post::orderByViews()->get(); // descending
Post::orderByViews('asc')->get(); // ascending
Post::orderByUniqueViews()->get(); // descending
Post::orderByUniqueViews('asc')->get(); // ascending
Post::orderByViews('asc', Period::pastDays(3))->get(); // descending
Post::orderByViews('desc', Period::pastDays(3))->get(); // ascending
And of course, it's also possible with the unique views variant:
Post::orderByUniqueViews('asc', Period::pastDays(3))->get(); // descending
Post::orderByUniqueViews('desc', Period::pastDays(3))->get(); // ascending
If you want to know how many views a specific viewable type has, you can use the getViewsCountByType
method on the Views
class.
views()->countByType(Post::class);
views()->countByType('App\Post');
You can also pass an instance of an Eloquent model. It will get the fully qualified class name by calling the getMorphClass
method on the model.
views()->countByType($post);
If you have different types of views for the same viewable type, you may want to store them in their own collection.
views($post)
->collection('customCollection')
->record();
To retrieve the views count in a specific collection, you can reuse the same collection()
method.
views($post)
->collection('customCollection')
->count();
To automatically delete all views of an viewable Eloquent model on delete, you can enable it by setting the removeViewsOnDelete
property to true
in your model definition.
protected $removeViewsOnDelete = true;
If you are using this package via a RESTful API, you might want to supply your own visitor's ID and IP Address, otherwise this package will use the visitor ID that's stored in a cookie and use IP Address of the requester.
// Override IP Address (this would be supplied by your client)
views($post)
->overrideIpAddress('Your IP Address')
->record();
// Override visitor ID (this would be supplied by your client)
views($post)
->overrideVisitor('Your unique visitor ID')
->record();
If you have a ton of visitors who are viewing pages where you are recording views, it might be a good idea to offload this task using Laravel's queue.
An easy job that simply records a view for the given viewable model, would look like:
namespace App\Jobs\ProcessView;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class ProcessView implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public $viewable;
public function __construct($viewable)
{
$this->viewable = $viewable;
}
public function handle()
{
views($this->viewable)->record();
}
}
You can now dispatch this job:
ProcessView::dispatch($post)
->delay(now()->addMinutes(30));
Note: it's unnecessary if you are using the database as queue driver!
If you want to cache for example the total number of views of a post, you could do the following:
// unique key that contains the post id and period to avoid collisions with other queries
$key = 'views.post'.$post->id.'.2018-01-24|2018-05-22';
cache()->remember($key, now()->addHours(2), function () use ($post) {
return views($post)->period(Period::create('2018-01-24', '2018-05-22'))->count();
});
This solution is perfectly fine for the example where we are counting the views statically. But what about dynamic views counts? For example: views($post)->period(Period::subDays(3))->count();
. The subDays
method uses Carbon::now()
as starting point. In this case we can't generalize the since datetime to a string, because Carbon::now()
will always be different! To be able to do this, we need to know if the period is static of dynamic.
Thanks to the Period
class that comes with this package we can know if it's static of dynamic, because it has the hasFixedDateTimes()
method that returns a boolean value. You're now able to properly generalize the dates.
Now of course, you can wrap all your views counts statements with this solution, but luckily this package provides an easy way of dealing with this. You can simply add the remember()
method on the chain. It will do all the hard work under the hood!
Examples:
views($post)->remember()->count();
views($post)->period(Period::create('2018-01-24', '2018-05-22'))->remember()->count();
views($post)->period(Period::upto('2018-11-10'))->unique()->remember()->count();
views($post)->period(Period::pastMonths(2))->remember()->count();
views($post)->period(Period::subHours(6))->remember()->count();
The default lifetime is configurable through the config file. Alternatively, you can pass a custom lifetime to the remember
method.
views($post)
->remember(now()->addHours(6))
->count();
If you want to extend or replace one of the core classes with your own implementations, you can override them:
CyrildeWit\EloquentViewable\View
CyrildeWit\EloquentViewable\Resolvers\IpAddressResolver
CyrildeWit\EloquentViewable\Resolvers\HeaderResolver
CyrildeWit\EloquentViewable\CrawlerDetectAdapter
Note: Don't forget that all custom classes must implement their original interfaces
View
Eloquent model$this->app->bind(
\CyrildeWit\EloquentViewable\Contracts\View::class,
\App\CustomView::class
);
$this->app->singleton(
\CyrildeWit\EloquentViewable\Contracts\IpAddressResolver::class,
\App\Resolvers\IpAddressResolver::class
);
$this->app->singleton(
\CyrildeWit\EloquentViewable\Contracts\HeaderResolver::class,
\App\Resolvers\HeaderResolver::class
);
$this->app->singleton(
\CyrildeWit\EloquentViewable\Contracts\CrawlerDetector::class,
\App\Services\CrawlerDetector\CustomAdapter::class
);
use CyrildeWit\EloquentViewable\Views;
Views::macro('countAndCache', function () {
return $this->cache()->count();
});
Now you're able to use this shorthand like this:
views($post)->countAndCache();
Views::forViewable($post)->countAndCache();
Please see UPGRADING for detailed upgrade guide.
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
See also the list of contributors who participated in this project.
Helpful Resources:
Feel free to add more alternatives!
This project is licensed under the MIT License - see the LICENSE.md file for details.