roundly-consulting/likes-for-laravel
A lightweight Laravel package for adding like and unlike functionality to Eloquent models. Supports polymorphic relationships, toggle helpers, like counts, and eager loading so you can build reactions, favorites, or upvotes with minimal setup.
Scope of this release. 1.1.2 is not a maintenance release. It contains a consumer-visible behaviour change to the broadcast payload in three events — Liked, Unliked, and ReactionChanged — plus two maintenance items (dev testing dependency to ^1.6, and CI running the PostgreSQL/MySQL legs on tmpfs). The change: actor_type and likeable_type now carry the model's class basename (User, Post) and never the PHP class name. Without a morph map this replaces App\Models\User; with a morph map it replaces the configured alias with the basename. The changelog explicitly states that listeners matching on the old value need updating, and that the channel name is unchanged.
This is a breaking change shipped in a patch release. That is the headline finding. Any consumer that compares actor_type/likeable_type against User::class, App\Models\User, or a morph alias will silently stop matching. The package has not been versioned for it (no 2.0.0, no deprecation window, no config toggle mentioned). Two consequences for us: (1) an immediate correctness risk for anyone upgrading on a caret constraint, and (2) a governance signal — patch releases in this family may carry behaviour changes, so ^1.1.0 is not a safe default constraint for us.
Capability discovery. The release notes at last describe the package's function: it emits broadcast events for likes, unlikes, and reaction changes against a polymorphic likeable (and an actor), with per-likeable channels. That answers the largest open question from the 1.1.1 assessment. It also tells us the public surface is event/broadcast payloads and channels — i.e. the contract is a wire format consumed by clients we do not necessarily control (Laravel Echo / JS, mobile apps, external subscribers, queue-serialized payloads). Wire formats are the highest-cost thing to change.
Architecture fit. Unchanged from 1.1.1: a Composer-installed Laravel library in the roundly vendor namespace, hard-dependent on roundly/package-toolkit, best suited to an application already running other roundly/* packages. New consideration: this package sits on the boundary between the app and its real-time clients, so its fit depends on whether we accept vendor-controlled wire formats. If we have external or mobile subscribers with independent release cycles, vendor-driven payload changes are expensive for us.
Integration feasibility. Mechanically still a composer require/composer update. But 1.1.2 introduces required work: an audit of every consumer of these three events, plus a coordinated listener/client update. The audit is cheap in a single codebase (grep for actor_type, likeable_type, class_basename, ::class comparisons in listeners, and any stored/queued payloads) and expensive across client apps, partner integrations, or anything that persisted historical payloads. Note also that the change partially defeats the purpose of a morph map: teams use aliases specifically to keep internal class names off the wire and to decouple wire format from class names — 1.1.2 replaces the alias with the basename, so the wire value is now derived from the class name again even for morph-mapped models.
Technical risk. Moderate, concentrated on consumers rather than on the framework. Specific risks: (1) silent behavioural mismatch — listeners fail to match and no exception is raised, so likes appear to work while reactions stop propagating; (2) rolling-deploy skew — during a canary or blue/green, new publishers emit basenames while old subscribers still expect FQCNs; (3) mixed-version fleets — two app instances on 1.1.1 and 1.1.2 publishing to the same channel produce two different payload shapes; (4) historical data — any table, queue, log, or analytics store holding the old values needs a backfill or a compatibility read; (5) the SemVer discipline risk above. Positives: the channel name is unchanged (so subscriptions and authorization are unaffected), the change is uniform and reversible, and the CI/tooling updates are evidence of active maintenance and multi-database test coverage (PostgreSQL and MySQL legs) — which partly answers the 1.1.1 open question on test breadth.
Key questions for the maintainer/vendor.
actor_type/likeable_type fields documented anywhere as a public contract, with an upgrade guide and a deprecation path?^1.6.Stack fit. Unchanged: Composer-based Laravel app on a supported PHP version; strongest where other roundly/* packages are already present (shared toolkit version and upgrade window). The new fit criterion is client topology. Single-app, single-deploy, in-repo listeners: straightforward. Multi-client (web plus mobile plus partner subscribers) or anything with independent release cadence: plan for a compatibility window rather than a clean cut.
Migration path. Do not treat 1.1.2 as a drop-in patch. Recommended path:
actor_type and likeable_type: event listeners, broadcast subscribers, JS/Echo handlers, mobile clients, partner integrations, queue or event-log tables, dashboards, and alert rules.['User','App\\Models\\User','user']). Deploy readers before publishers.composer.lock; record the exact version in the dependency policy.If the audit finds unupdatable consumers (external subscribers, shipped mobile binaries), hold at 1.1.1 and escalate to the vendor for a compatibility option, or plan the change into the next mobile release train.
Compatibility. Verify explicitly: PHP and Laravel majors; the toolkit constraint (^1.3.0) still resolving against the rest of the roundly/* family; DB support if the CI matrix is a guide (PostgreSQL and MySQL are tested — confirm nothing else is claimed); and, critically, the payload contract against every subscriber. Also confirm whether a morph map is in use: if it is, the before/after values are alias → basename, not FQCN → basename, and the diff is different from what a naive reading of the changelog implies.
Sequencing. Readers before publishers; publishers before removal of legacy tolerance; single coordinated change across all roundly/* packages rather than package-by-package. Avoid deploying mid-flight of an unrelated broadcast change so that any anomaly is attributable. Roll out to one environment with live subscribers before production and inspect actual received payloads rather than trusting the changelog.
Maintenance. The cadence remains healthy in the "actively maintained" sense — dependency floors current, dev toolchain current, CI improved (tmpfs for DB legs, which shortens runs). But the maintenance burden steps up: this family changes wire formats in patch releases, so every dependency refresh is a potential consumer-code change, not just a Composer update. Budget an audit pass per upgrade rather than per quarter, and treat the changelog as required reading before any constraint bump.
Support. Still unknown and now more important. The questions that matter have shifted from "is there a support policy" to "is there a versioning and deprecation policy, and will breaking payload changes be signalled in advance". A patch-level breaking change with a changelog note but no deprecation window suggests versioning is not treated as a contract. Confirm the disclosure and deprecation policy before committing to production dependency on the payload format.
Scaling. Runtime scaling is unchanged — the library adds no infrastructure; characteristics follow the underlying broadcast path (queue, websocket server, fan-out width). Two scaling notes specific to this release: (1) broadcast payloads scale with subscriber count, so a payload contract change is a fan-out-wide event whose rollback cost grows with the size of the subscriber fleet; (2) dependency-graph cost still grows superlinearly with each additional roundly/* package, and now also carries a versioning-risk premium.
Failure modes.
User::class or a morph alias stop firing while the like/unlike itself succeeds. No error surface; detect via monitoring on reaction-change event volume, not on exceptions.package-toolkit below 1.3.0, resolution fails at build time.Ramp-up. Still low for the mechanics, slightly higher for the semantics. Engineers need ~half a day to read the event classes and confirm the payload contract, plus the audit time described above (scoped by how many consumers exist). The conceptual learning curve is now explicit: understand that the channel name is stable but the type fields are not, and that a morph map no longer protects the wire format. Document that in the integration notes so the next upgrade does not re-litigate it.
How can I help you explore Laravel packages today?