Installation Add the package via Composer:
composer require atm/badgebundle
Register the bundle in config/app.php under providers:
Atm\BadgeBundle\BadgeBundle::class,
Publish Config & Migrations Run:
php artisan vendor:publish --provider="Atm\BadgeBundle\BadgeBundle" --tag="config"
php artisan vendor:publish --provider="Atm\BadgeBundle\BadgeBundle" --tag="migrations"
Then migrate:
php artisan migrate
First Use Case: Creating a Badge Define a badge in a migration or via a seeder:
use Atm\BadgeBundle\Entity\Badge;
$badge = new Badge();
$badge->setName('Developer');
$badge->setDescription('Active contributor');
$badge->setImagePath('/images/badges/dev.png');
$badge->setCriteria('{"points": 100}'); // JSON criteria
$badge->setActive(true);
$em->persist($badge);
$em->flush();
Assigning a Badge to a User
Use the BadgeService to assign badges programmatically:
$badgeService = $this->get('badge.service');
$user = $this->getUser(); // Symfony User object
$badge = $em->getRepository(Badge::class)->find(1);
$badgeService->assignBadge($user, $badge);
Badge Criteria Evaluation
Use the BadgeCriteriaEvaluator to check if a user qualifies for a badge:
$evaluator = $this->get('badge.criteria_evaluator');
$badge = $em->getRepository(Badge::class)->find(1);
$user = $this->getUser();
if ($evaluator->evaluate($user, $badge)) {
$badgeService->assignBadge($user, $badge);
}
Dynamic Badge Assignment via Events
Listen for user actions (e.g., UserPointsUpdatedEvent) and trigger badge checks:
// In a service or event subscriber
$badgeService = $this->get('badge.service');
$badgeService->checkAndAssignBadges($user);
Badge Display in Templates Fetch a user’s badges in a Twig template:
{% for badge in app.user.badges %}
<div class="badge">
<img src="{{ asset(badge.imagePath) }}" alt="{{ badge.name }}">
<p>{{ badge.description }}</p>
</div>
{% endfor %}
Bulk Badge Assignment
Use the BadgeService to assign badges to multiple users:
$users = $em->getRepository(User::class)->findBy(['role' => 'admin']);
$badge = $em->getRepository(Badge::class)->find(2);
foreach ($users as $user) {
$badgeService->assignBadge($user, $badge);
}
Extend Badge Criteria
Create custom criteria evaluators by implementing Atm\BadgeBundle\Criteria\BadgeCriteriaInterface:
class CustomCriteria implements BadgeCriteriaInterface
{
public function evaluate(User $user, Badge $badge): bool
{
// Custom logic (e.g., check for API usage)
return $user->getApiRequestsCount() > 50;
}
}
Register the service in services.yml:
services:
app.custom_badge_criteria:
class: App\Criteria\CustomCriteria
tags:
- { name: badge.criteria, alias: custom }
Badge Tiers
Use badge categories or tags to group badges (e.g., ['tier' => 'gold']) and filter them in queries:
$badges = $em->getRepository(Badge::class)
->createQueryBuilder('b')
->where('b.tags LIKE :tag')
->setParameter('tag', '%"tier": "gold"%')
->getQuery()
->getResult();
Badge Expiry
Add an expiresAt field to the Badge entity and filter active badges in queries:
$activeBadges = $em->getRepository(Badge::class)
->createQueryBuilder('b')
->where('b.expiresAt IS NULL OR b.expiresAt > :now')
->setParameter('now', new \DateTime())
->getQuery()
->getResult();
Badge Notifications Trigger notifications when a badge is assigned (e.g., using Symfony Messenger):
$badgeService->assignBadge($user, $badge, function ($user, $badge) {
$this->get('messenger')->dispatch(
new BadgeAssignedNotification($user, $badge)
);
});
Criteria JSON Parsing
criteria field is stored as JSON. Ensure your criteria are valid JSON and handle parsing errors:
$criteria = json_decode($badge->getCriteria(), true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException('Invalid badge criteria JSON');
}
Duplicate Badge Assignment
if ($user->getBadges()->contains($badge)) {
return false; // Already assigned
}
Image Paths
/images/badges/dev.png) may break in production. Use asset() in Twig or configure a base path in the bundle’s config.Performance with Large User Bases
// Fetch only active badges for a user
$userBadges = $em->getRepository(Badge::class)
->findBadgesForUser($user, ['active' => true]);
Enable SQL Logging
Add this to config/packages/dev/doctrine.yaml to debug queries:
dbal:
logging: true
logging_format: "%%SQL%% %%TIME%%"
logging_connection: true
Check Criteria Evaluation Log criteria evaluation results for debugging:
$evaluator->evaluate($user, $badge); // Add a debug log before returning
Badge Assignment Events
Listen for badge.assigned events to debug assignments:
$eventDispatcher->addListener('badge.assigned', function ($event) {
\Log::debug('Badge assigned', [
'user' => $event->getUser()->getId(),
'badge' => $event->getBadge()->getName(),
]);
});
Custom Badge Types
Extend the Badge entity to add custom fields (e.g., maxUses, color):
/**
* @ORM\Column(type="string", nullable=true)
*/
private $color;
Badge Validation Add validation rules for badge creation (e.g., unique names):
use Symfony\Component\Validator\Constraints as Assert;
class Badge
{
/**
* @Assert\NotBlank
* @Assert\Unique(entityClass="Atm\BadgeBundle\Entity\Badge", propertyPath="name")
*/
private $name;
}
Badge API Endpoints
Expose badge-related endpoints using Symfony’s AbstractController:
use Symfony\Component\HttpFoundation\JsonResponse;
class BadgeController extends AbstractController
{
public function index(BadgeService $badgeService): JsonResponse
{
$badges = $badgeService->getAllBadges();
return $this->json($badges);
}
}
Badge Import/Export Add CLI commands for bulk badge management:
php artisan badge:import /path/to/badges.csv
php artisan badge:export --format=json
Implement the commands by extending Symfony\Component\Console\Command\Command.
How can I help you explore Laravel packages today?