Installation Add the package via Composer:
composer require bitheater/rating-bundle
Bundle Registration
Register the bundle in config/bundles.php (Laravel 5.4+) or AppKernel.php (Laravel <5.4):
Bitheater\RatingBundle\BitheaterRatingBundle::class => ['all' => true],
Configuration
Define the bundle config in config/packages/bitheater_rating.yaml (or config/bitheater_rating.yml):
bitheater_rating:
driver: orm
model_class: App\Entity\Vote
Create the Vote Entity
Extend the base RatingVote class and define it as an ORM entity:
namespace App\Entity;
use Bitheater\RatingBundle\Model\Vote as RatingVote;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="Bitheater\RatingBundle\Repository\Doctrine\ORMRepository")
* @ORM\Table(name="votes")
*/
class Vote extends RatingVote
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function getId(): ?int
{
return $this->id;
}
}
Run Migrations
Generate and run the migration for the votes table:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
First Usage
Inject the ratingManager service into a controller or service:
use Bitheater\RatingBundle\Manager\RatingManager;
class RatingController extends Controller
{
public function __construct(private RatingManager $ratingManager)
{
}
public function rateItem(int $itemId, int $rating)
{
$this->ratingManager->rate($itemId, $rating);
return response()->json(['success' => true]);
}
}
Rating an Item
Use the ratingManager to record votes:
$this->ratingManager->rate($itemId, $rating); // $rating: 1-5
Fetching Ratings Retrieve ratings for an item:
$ratings = $this->ratingManager->getRatings($itemId);
$average = $this->ratingManager->getAverageRating($itemId);
Displaying Ratings in Views Use Twig (if Symfony) or Blade (if Laravel) to render ratings:
{% for rating in ratings %}
{{ rating.value }} stars
{% endfor %}
Or in Blade:
@foreach($ratings as $rating)
<div>{{ $rating->value }} stars</div>
@endforeach
Integration with Eloquent Models Attach ratings to any Eloquent model (Laravel) or Doctrine entity (Symfony):
// Example: Rating a Post model
$post = Post::find($id);
$this->ratingManager->rate($post->id, $rating);
Customizing Vote Behavior
Override the base Vote class to add custom logic:
class Vote extends RatingVote
{
public function isValid(): bool
{
// Custom validation logic
return parent::isValid() && $this->user->isActive();
}
}
Real-Time Updates Use Laravel Echo/Pusher to broadcast rating changes:
$this->ratingManager->rate($itemId, $rating);
broadcast(new RatingUpdated($itemId, $this->ratingManager->getAverageRating($itemId)));
Caching Ratings Cache frequent rating queries:
$average = Cache::remember("rating_avg_{$itemId}", now()->addHours(1), function() use ($itemId) {
return $this->ratingManager->getAverageRating($itemId);
});
API Endpoints Expose rating functionality via API:
Route::post('/items/{item}/rate', function (Request $request, int $item) {
$this->ratingManager->rate($item, $request->rating);
return response()->json(['status' => 'rated']);
});
Middleware for Authenticated Votes Restrict voting to authenticated users:
public function rateItem(Request $request, int $itemId)
{
if (!$request->user()) {
abort(403);
}
$this->ratingManager->rate($itemId, $request->rating, $request->user());
}
Bulk Rating Updates Use transactions for batch operations:
DB::transaction(function () use ($itemIds, $ratings) {
foreach ($itemIds as $index => $itemId) {
$this->ratingManager->rate($itemId, $ratings[$index]);
}
});
Bundle Maturity The package is labeled "UNDER CONSTRUCTION"—expect breaking changes or incomplete features. Test thoroughly in a staging environment.
ORM Dependency The bundle assumes Doctrine ORM. If using Eloquent (Laravel), you may need to:
RatingManager to work with Eloquent.votes table.Missing Documentation Lacks examples for:
No Built-in Frontend The bundle provides backend logic but no frontend components (e.g., star rating UI). You’ll need to implement this separately (e.g., using JavaScript libraries like Star Rating).
Configuration Overrides
The model_class in config must match the fully qualified namespace of your Vote entity. Typos here will cause runtime errors.
Check Entity Mapping If ratings aren’t saving, verify:
Vote entity is properly annotated with @ORM\Entity and @ORM\Table.repositoryClass points to Bitheater\RatingBundle\Repository\Doctrine\ORMRepository.Enable Doctrine Debugging
Add to config/packages/dev/doctrine.yaml:
doctrine:
dbal:
logging: true
profiling: true
Check logs for SQL errors during rating operations.
Validate Vote Entities
Override isValid() in your Vote class to add debug logs:
public function isValid(): bool
{
if (!$this->itemId) {
\Log::error('Vote missing itemId', ['vote' => $this->toArray()]);
}
return parent::isValid();
}
Clear Cache After Changes If extending the bundle, clear the cache:
php artisan cache:clear
php artisan config:clear
Custom Rating Drivers
Extend the RatingManager to support non-ORM drivers (e.g., Redis):
class RedisRatingManager extends RatingManager
{
public function __construct(Redis $redis) { ... }
public function rate($itemId, $rating) { ... }
}
Event Listeners
Listen for rating events (if the bundle supports them) or wrap the ratingManager:
$ratingManager->rate($itemId, $rating);
event(new RatingSubmitted($itemId, $rating));
Custom Vote Validation
Override Vote::isValid() to enforce business rules:
public function isValid(): bool
{
return parent::isValid() &&
$this->rating >= 1 &&
$this->rating <= 5 &&
!$this->hasDuplicateByUser();
}
Localization Extend the bundle to support multi-language rating labels (e.g., "Excellent," "Poor").
Testing
Mock the RatingManager in tests:
$mockManager = Mockery::mock(RatingManager::class);
$mockManager->shouldReceive('rate')->once();
$this->app->instance(RatingManager::class, $mockManager);
How can I help you explore Laravel packages today?