This package lets you easily add badge mechanics to your application.
You can install the package via composer:
composer require maize-tech/laravel-badges
You can publish the config and migration files and run the migrations with:
php artisan badges:install
This is the contents of the published config file:
return [
/*
|--------------------------------------------------------------------------
| Badge model
|--------------------------------------------------------------------------
|
| Here you may specify the fully qualified class name of the badge model.
|
*/
'model' => Maize\Badges\Models\BadgeModel::class,
/*
|--------------------------------------------------------------------------
| Badges
|--------------------------------------------------------------------------
|
| Here you may specify the list of fully qualified class name of badges.
|
*/
'badges' => [
// App\Badges\FirstLogin::class,
],
];
To use the package, firstly you should implement the Maize\Badges\HasBadges
interface and apply the Maize\Badges\InteractsWithBadges
trait to all models who can have badges:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Maize\Badges\HasBadges;
use Maize\Badges\InteractsWithBadges;
class User extends Authenticatable implements HasBadges
{
use InteractsWithBadges;
}
Once done, all you have to do is define a class for each badge, extend the Maize\Badges\Badge
class and implement the isAwarded
abstract method:
<?php
namespace App\Badges;
use Illuminate\Database\Eloquent\Model;
use Maize\Badges\Badge;
class FirstLogin extends Badge
{
public static function isAwarded(Model $model): bool
{
return $model->logins()->exists();
}
}
Once done, don't forget to list the newly created badge within the badges
list under config/badges.php
:
'badges' => [
App\Badges\FirstLogin::class,
],
If your badge can have progress, you should extend the Maize\Badges\ProgressableBadge
class and implement both the getTotal
and getCurrent
abstract methods:
<?php
namespace App\Badges;
use Illuminate\Database\Eloquent\Model;
use Maize\Badges\ProgressableBadge;
class FiveLogins extends ProgressableBadge
{
public static function getTotal(): int
{
return 5;
}
public static function getCurrent(Model $model): bool
{
return $model->logins()->count();
}
}
Under the hoods, the isAwarded
method checks if getCurrent
is equals or greater than getTotal
.
What is a badge without a name or description?
To accomplish this, you can override the metadata
method within all badge classes.
Here is an example implementation using Laravel built-in translation method and the badge slug:
<?php
namespace App\Badges;
use Illuminate\Database\Eloquent\Model;
use Maize\Badges\Badge;
class FirstLogin extends Badge
{
public static function isAwarded(Model $model): bool
{
return $model->logins()->exists();
}
public static function metadata(): array
{
$slug = static::slug();
return [
'name' => __("badges.{$slug}.name"),
'description' => __("badges.{$slug}.name"),
];
}
}
Once done, you can retrieve the metadata using both the badge class and the BadgeModel
entities:
use App\Badges\FirstLogin;
use Maize\Badges\Models\BadgeModel;
$user->giveBadge(FirstLogin::class);
$user->badges()->first()->metadata; // returns the list of metadata attributes
$user->badges()->first()->getMetadata('description'); // returns the attribute with key 'description'
FirstLogin::metadata(); // returns the list of metadata attributes
FirstLogin::getMetadata('description'); // returns the metadata attribute with key 'description'
All badges have a default slug used when storing a badge awarded event into the database.
The default slug is the badge's fully qualified class name.
For example, FirstLogin
badge's slug would be App\Badges\FirstLogin
.
You can however customize the default behaviour overriding the slug
method.
Here is an example using the badge's class basename in kebab case:
<?php
namespace App\Badges;
use Illuminate\Database\Eloquent\Model;
use Maize\Badges\Badge;
class FirstLogin extends Badge
{
public static function slug(): string
{
return str(static::class)
->classBasename()
->kebab()
->toString(); // returns 'first-login'
}
public static function isAwarded(Model $model): bool
{
return $model->logins()->exists();
}
}
Beware that all badge classes should have a unique slug to prevent inconsistencies.
You can give a badge to any entity implementing the HasBadges
interface using one of the following methods:
use App\Badges\FirstLogin;
$user->giveBadge(FirstLogin::class);
FirstLogin::giveTo($user);
When giving a badge, the isAwarded
method will be evaluated to make sure the entity meets the conditions.
Every time a badge is given, a BadgeAwarded
event will also be fired.
To check if an entity has a badge, you can use the hasBadge
method:
use App\Badges\FirstLogin;
$user->hasBadge(FirstLogin::class)
To retrieve all badges awarded by an entity, you can use the badges
relationship which returns a list of BadgeModel
entities.
use Maize\Badges\Models\BadgeModel;
$user->badges->map->badge; // returns the list of awarded badges slug
To sync all badges for a given entity, you can use the syncBadges
method, which retrieves all badges within the badges
list under config/badges.php
and checks whether it can be awarded or not.
$user->syncBadges();
The package also comes with the badges:clear
command, which automatically deletes all stored badges which are not anymore listed within the badges
list under config/badges.php
:
You may schedule the command using the schedule
method of the console kernel (usually located under the App\Console
directory):
use Maize\Badges\Commands\ClearBadgesCommand;
$schedule->command(ClearBadgesCommand::class)->daily();
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.