Skip to content
laravel-radioactivity
Loading repository…

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.

bash
composer require eighteen73/laravel-radioactivity

Then publish the config file to your project.

bash
php artisan vendor:publish --provider="Eighteen73\Radioactivity\RadioactivityServiceProvider"

And run the migrations to create the energies table.

bash
php artisan migrate

The 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>&1

Config

All settings live in config/radioactivity.php.

OptionEnv varDefaultDescription
half_lifeRADIOACTIVITY_HALF_LIFE24Time, in hours, for a model's energy to fall to 50% of its value.
min_energyRADIOACTIVITY_MIN_ENERGY1Energy 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-defaultThe 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.

php
'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.

php
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.

php
$post->addEnergy();    // Adds 1000 energy
$post->addEnergy(100); // Adds 100 energy

The 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.

php
$post->energy_amount;

Using the facade

A Radioactivity facade is available if you prefer it.

php
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 record

Ordering by energy

The trait adds an orderByEnergy() scope to your queries, which is all you need for a trending list.

php
// Most active posts first
$trending = Post::orderByEnergy()->limit(10)->get();

// Ascending order
$quietest = Post::orderByEnergy('asc')->get();

It also works on hasMany relationships.

php
$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.