Installation:
composer require binafy/laravel-score
Publish the config file (if needed):
php artisan vendor:publish --provider="Binafy\Score\ScoreServiceProvider"
Define a Scorable Model:
Use the HasScore trait in your Eloquent model:
use Binafy\Score\Traits\HasScore;
class User extends Model
{
use HasScore;
}
First Use Case: Define a score rule and apply it to a model:
// Define a rule (e.g., for "activity points")
$user->score()->addRule('activity', 10, 'points');
// Apply the rule (e.g., when a user logs in)
$user->score()->apply('activity');
Check the Score:
$score = $user->score; // Returns the total score
$details = $user->scoreDetails; // Returns an array of rule contributions
Dynamic Rule Application: Use rules conditionally based on business logic:
if ($user->isPremium()) {
$user->score()->addRule('premium_bonus', 50, 'points');
}
Batch Processing: Apply scores to multiple models efficiently:
User::where('last_login', '>', now()->subDays(7))
->each(function ($user) {
$user->score()->apply('activity');
});
Custom Calculations: Extend scoring logic with closures:
$user->score()->addRule('custom', function () {
return $this->posts()->count() * 2;
}, 'points');
Leaderboards: Fetch top scorers with Eloquent:
$leaderboard = User::withScore()
->orderByScore('desc')
->take(10)
->get();
Events: Trigger score updates via model events (e.g., created, updated):
class User extends Model
{
protected static function booted()
{
static::created(function ($user) {
$user->score()->apply('signup_bonus');
});
}
}
API Responses: Include scores in API responses using accessors:
public function getScoreAttribute()
{
return $this->score;
}
Testing: Mock score rules in unit tests:
$user->score()->addRule('test_rule', 100, 'points');
$this->assertEquals(100, $user->score);
Rule Naming Collisions:
Ensure rule names (e.g., 'activity') are unique across models to avoid overwrites.
Fix: Use namespaced rule names (e.g., 'user.activity').
Performance with Large Datasets:
Avoid fetching scoreDetails for models where scores are only used for ranking.
Fix: Cache scoreDetails or use a computed column.
Race Conditions: Concurrent score updates may cause inconsistencies if not handled. Fix: Use database transactions:
DB::transaction(function () use ($user) {
$user->score()->apply('rule_name');
});
Negative Scores: The package doesn’t natively support negative scores. Validate inputs if needed:
$user->score()->addRule('penalty', -5, 'points');
Log Rule Applications:
Enable debug mode in config ('debug' => true) to log score changes:
'debug' => env('SCORE_DEBUG', false),
Inspect Rules: Dump all active rules for a model:
dd($user->score()->rules());
Custom Score Types:
Extend the ScoreType class to support non-numeric scores (e.g., tiers):
class TierScoreType extends ScoreType
{
public function calculate($value)
{
return match (true) {
$value > 100 => 'platinum',
$value > 50 => 'gold',
default => 'bronze',
};
}
}
Global Rules: Define reusable rules in a service provider:
public function boot()
{
\Binafy\Score\Facades\Score::addGlobalRule('login_bonus', 1, 'points');
}
Database Optimization:
Add a score column to your table for faster queries:
Schema::table('users', function (Blueprint $table) {
$table->integer('score')->default(0);
});
Then update the HasScore trait to sync this column.
Localization: Translate rule descriptions or messages using Laravel’s translation system:
$user->score()->addRule('welcome', 10, 'points', trans('score.rules.welcome'));
How can I help you explore Laravel packages today?