loafer/laravel-likeable
A Laravel package for adding like and dislike reactions to Eloquent models. Use traits to make models likeable, attach reactions polymorphically, toggle likes, and query counts or liked items with a clean API.
Architecture fit. loafer/laravel-likeable implements the standard polymorphic-toggle pattern: a Likeable trait on any Eloquent model, two side tables (likeable_likes, likeable_dislikes), and like() / dislike() / unlike() / undislike() methods with accompanying query scopes (whereLikedBy, orderByLikesCount). It fits Laravel's Eloquent idiom cleanly and requires no external services, queues, or infrastructure. Conceptually it is a good fit for a Laravel-first stack — but the architecture is that of Laravel 5.1–5.5, and the package is archived, with the maintainer redirecting users to cybercog/laravel-love. This is a reference implementation, not an adoption candidate.
Integration feasibility. Low for any current Laravel application. Composer constraints pin illuminate/support to the 5.x line, so installation on Laravel 8+ will fail dependency resolution outright; on Laravel 9/10 it is effectively impossible without forking and rewriting constraints. Because the source is small and MIT-licensed, a fork is technically feasible, but we would then own a fork of an unmaintained package indefinitely — strictly worse than either adopting the successor or writing the ~200 lines ourselves.
Technical risk. High and concentrated:
ReturnTypeWillChange requirements; the trait and migrations will need auditing for deprecations before they run cleanly on 8.1+.Key questions. (1) Is this evaluation for greenfield adoption or for a legacy service already running it? The answer flips the recommendation entirely. (2) What reaction semantics are required — binary like/dislike, or an extensible reaction set? (3) Is a per-model counter cache needed for feed rendering at scale, and does the package maintain one reliably? (4) Who owns the maintenance burden if we fork? (5) Does the product need reaction data to survive a future model/namespace rename (polymorphic morphMap hygiene)?
Stack fit. Only viable on Laravel ≤5.5 / PHP ≤7.x. On anything newer, treat this package as a design reference rather than a dependency: it documents a clean, conventional schema and trait surface we can reproduce in-house in under a day, with full control over indexing and uniqueness.
Migration path. Do not migrate to this package. Migrate off it, to cybercog/laravel-love, the maintainer's successor. That path is:
laravel-love, publish its config and migrations (love_reactants, love_reactions).likeable_likes → reaction rows with reaction_type = Like, and likeable_dislikes → Dislike. Map the old polymorphic columns onto the new reactant/reaction shape.Likeable → HasReactions on reactable models, Reacts on the user model) and rewrite call sites (like() → react(Like::class), likes → likes, scopes whereLikedBy → whereReactedBy).Compatibility. Verify the chosen laravel-love major version against our Laravel and PHP versions first; that version matrix is the real gating constraint. Also confirm behavior around duplicate reactions — the successor enforces uniqueness where the old package relied on application-level toggles, which will surface pre-existing duplicate rows during backfill and require a dedupe pass.
Sequencing. (a) Decide adopt-vs-replace and lock a framework/PHP version target; (b) prototype on a non-critical model (comments, not posts); (c) backfill in a maintenance window with a dry-run row-count diff; (d) dual-write/dual-read validation; (e) cut over, then delete legacy code. Budget one sprint including the data reconciliation.
Maintenance. Adopting this package as-is means accepting a permanently frozen dependency and a hard framework ceiling. Any Laravel upgrade becomes blocked on a community fork. The successor package has active maintenance and a real release cadence; that is the only sustainable operating posture.
Support. No vendor, no SLA, archived issues, single historical maintainer. Internal escalation path is "read the source" — acceptable for a 200-line trait, not acceptable for anything customer-facing without a documented in-house owner.
Scaling. Two-table design doubles the write and index footprint for what is logically one fact. Hot-row contention on popular models is real: toggling like/unlike on a viral post produces concurrent INSERT/DELETE on the same narrow key space and will deadlock under load without retry logic or a uniqueness constraint to absorb races. Reads for feeds are the bigger cost — withCount over polymorphic relations does not index well; if the product shows like counts in lists, plan a denormalized counter column or a cache layer in front, independent of the package.
Failure modes to instrument for. (1) Duplicate reactions from double-taps or client retries — enforce a unique index, don't trust the toggle. (2) Counter drift if a cached count is introduced. (3) Orphaned reaction rows after hard-deleting a parent model — confirm ON DELETE CASCADE or a cleanup job. (4) Morph-map breakage on class rename silently orphaning all historical rows. (5) Unbounded growth of the reactions table with no archival strategy; reactions have long tails and are rarely pruned.
Ramp-up. Trivial for any Laravel developer — the trait surface is self-documenting and the successors preserve the mental model. The ramp-up cost is not learning this package; it is unlearning it during the migration to laravel-love and re-validating every call site and scope. Estimate half a day to read and prototype, one sprint to migrate safely with data reconciliation.
Recommendation. Do not adopt. Treat as a schema/API reference; implement the ~200 lines natively or adopt cybercog/laravel-love if a maintained dependency is preferred. Re-score only if the evaluation is retroactively scoped to maintaining a Laravel 5.x application already running it, in which case the deliverable is a migration plan off it, not an integration plan onto it.
How can I help you explore Laravel packages today?