Radioactivity
This Laravel package gives your Eloquent models "energy" so the most active items are easy to find, with extra weighting given to recently active items.
Energy decays exponentially over time, in the same way as a radioactive isotope. Assuming a half life of 24 hours, an item given 1000 energy will be down to 500 energy a day later, and will keep halving until it falls below your minimum threshold and is pruned. Content that keeps receiving hits keeps topping up its energy and stays near the top of your trending list.
Decay is applied in steps every 5 minutes rather than continuously, so that is the effective granularity of the system.
Requirements
- PHP 8.2 or higher
- Laravel 11 or higher
Prerequisite
This package uses queues and the scheduler to apply decay, so both need to be running in your project.
Installation
Require the package via Composer.
composer require eighteen73/laravel-radioactivityThen publish the config file to your project.
php artisan vendor:publish --provider="Eighteen73\Radioactivity\RadioactivityServiceProvider"And run the migrations to create the energies table.
php artisan migrateThe package's migration is loaded automatically, so there's no need to publish it. If you do want to customise it, publish it first with --tag=radioactivity_migrations.
Scheduler
The package registers its own decay job, which runs every five minutes. You only need to make sure Laravel's scheduler is running via cron.
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1Config
All settings live in config/radioactivity.php.
| Option | Env var | Default | Description |
|---|---|---|---|
half_life | RADIOACTIVITY_HALF_LIFE | 24 | Time, in hours, for a model's energy to fall to 50% of its value. |
min_energy | RADIOACTIVITY_MIN_ENERGY | 1 | Energy records below this value are pruned to keep the table small. |
ip_blacklist | - | [] | Requests from these IP addresses will not add energy to a model. |
models | - | [] | The models to decay automatically on a schedule. |
queue | - | default | The queue the decay job is dispatched onto. |
Any model you want to decay must be listed in the models array. A model that is missing from here will still accept energy, but that energy will never decay.
'models' => [
\App\Models\Post::class,
],Preparing your model
Add the HasEnergy trait to your model. Appending energy_amount to the model's serialisation is optional, but useful if the current energy value needs to reach your frontend.
use Eighteen73\Radioactivity\Traits\HasEnergy;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasEnergy;
protected $appends = ['energy_amount'];
}Usage
Adding energy
Call addEnergy() whenever the model is viewed, or whenever any other action happens that you consider a signal of popularity.
$post->addEnergy(); // Adds 1000 energy
$post->addEnergy(100); // Adds 100 energyThe default of 1000 is deliberately large to avoid working with lots of small floating point values. Requests from an IP in the ip_blacklist config are ignored.
Reading energy
Use the energy_amount attribute. It returns 0 for a model that has never been given energy.
$post->energy_amount;Using the facade
A Radioactivity facade is available if you prefer it.
use Radioactivity;
Radioactivity::add($post); // Adds 1000 energy
Radioactivity::add($post, 100); // Adds 100 energy
Radioactivity::getEnergy($post); // null if the model has no energy recordOrdering by energy
The trait adds an orderByEnergy() scope to your queries, which is all you need for a trending list.
// Most active posts first
$trending = Post::orderByEnergy()->limit(10)->get();
// Ascending order
$quietest = Post::orderByEnergy('asc')->get();It also works on hasMany relationships.
$trending = $user->posts()->orderByEnergy()->get();Models with no energy record are included in the results, sorted as though they have no energy.
Credits
This package is forked from Laravel Trends by Hacklabs. All due credit to the authors of that package.