Installation:
composer require qirolab/laravel-reactions
No manual service provider registration needed (Laravel 5.5+ auto-discovers).
Publish Config (Optional):
php artisan vendor:publish --provider="Qirolab\LaravelReactions\LaravelReactionsServiceProvider" --tag="config"
Defaults are sensible, but customize via config/reactions.php if needed.
First Use Case:
Add reactions to a model (e.g., Post):
use Qirolab\LaravelReactions\Traits\Reacts;
class Post extends Model
{
use Reacts;
}
Run migrations:
php artisan migrate
Define Reactions:
In config/reactions.php, set your reaction types (e.g., like, love, dislike):
'reactions' => ['like', 'love', 'dislike'],
Basic Usage:
// Add a reaction
$post->reaction()->create(['type' => 'like', 'user_id' => auth()->id()]);
// Check if user reacted
$post->isReactedBy(auth()->id(), 'like');
// Get reaction count
$post->reactionsCount('like');
Model Integration:
Reacts trait on Eloquent models to enable reactions.Comment model:
class Comment extends Model
{
use Reacts;
}
Reaction Types:
config/reactions.php:
'reactions' => ['upvote', 'downvote', 'bookmark', 'share'],
Common CRUD Operations:
// Create a reaction
$model->reaction()->create(['type' => 'like', 'user_id' => 1]);
// Delete a reaction
$model->reaction()->where('user_id', 1)->delete();
// Toggle reaction (e.g., like/dislike)
$model->toggleReaction('like', auth()->id());
Querying Reactions:
$post->reactions()->get();
$post->reactions()->where('type', 'like')->get();
$post->reactions()->where('user_id', 1)->get();
Real-Time Updates:
$post->reaction()->create(['type' => 'like', 'user_id' => auth()->id()]);
broadcast(new ReactionBroadcast($post, 'like', auth()->id()));
API Endpoints:
Route::post('/posts/{post}/react', [ReactionController::class, 'store']);
public function store(Post $post, Request $request) {
$post->toggleReaction($request->type, auth()->id());
return response()->json(['success' => true]);
}
Frontend Integration:
fetch(`/posts/${postId}/reactions/count?type=like`)
.then(res => res.json())
.then(count => console.log(count));
@reactionButton($post, 'like', auth()->id())
Migration Conflicts:
reactions table and a pivot table (model_has_reactions). Ensure no naming collisions with existing tables.Caching Issues:
reactionsCount('type', true) to force refresh.User Authentication:
user_id in reactions to prevent abuse. Use middleware or policies:
public function store(Request $request) {
$this->authorize('react', $post);
$post->toggleReaction($request->type, auth()->id());
}
Performance with Large Datasets:
withCount('reactions') on models with millions of reactions. Use raw SQL or aggregate queries:
DB::table('reactions')->where('reactable_id', $post->id)->where('type', 'like')->count();
Soft Deletes:
SoftDeletes, reactions will also soft-delete. Override the trait to handle this:
use Qirolab\LaravelReactions\Traits\Reacts as BaseReacts;
class Post extends Model {
use BaseReacts {
BaseReacts::boot as private bootReactions;
}
protected static function bootReactions() {
static::deleted(function ($model) {
$model->reactions()->delete();
});
}
}
Reaction Not Saving:
reactable_type and reactable_id are correctly set (default: class and id of the model).dd($model->getTable(), $model->getKey()) to verify.Count Mismatches:
$rawCount = DB::table('reactions')->where('reactable_id', $post->id)->where('type', 'like')->count();
$packageCount = $post->reactionsCount('like');
Duplicate Reactions:
user_id + type is unique in the pivot table. The package handles this by default, but custom logic may override it.Custom Reaction Logic:
Reacts trait methods (e.g., toggleReaction):
class Post extends Model {
use Reacts;
public function toggleReaction($type, $userId) {
// Custom logic (e.g., rate limiting)
if ($this->hasReactedToday($userId, $type)) {
return false;
}
return parent::toggleReaction($type, $userId);
}
}
Additional Reaction Metadata:
Schema::table('model_has_reactions', function (Blueprint $table) {
$table->json('metadata')->nullable();
});
Reacts trait to use the new column.Reaction Events:
ReactionCreated):
use Qirolab\LaravelReactions\Events\ReactionCreated;
ReactionCreated::listen(function ($reaction) {
// Send notification, log, etc.
});
Custom Reaction Types:
$this->addReactionType('custom_type');
Multi-Tenant Support:
tenant_id to the pivot table for multi-tenancy:
Schema::table('model_has_reactions', function (Blueprint $table) {
$table->unsignedBigInteger('tenant_id')->after('id');
});
$post->reactions()->where('tenant_id', auth()->tenant()->id)->get();
Bulk Reactions:
Post::chunk(100, function ($posts) {
foreach ($posts as $post) {
$post->toggleReaction('like', $userId);
}
});
Reaction Analytics:
DB::view('reaction_analytics', function ($query) {
$query->select('type', DB::raw('count(*) as count'))
->from('reactions')
->groupBy('type');
});
Localization:
@reactionButton($post, 'like', auth()->id(), __('Like'))
Testing:
$post = Post::factory()->create();
Reaction::factory()->create(['
How can I help you explore Laravel packages today?