runcom/ean-validation-bundle
A Symfony bundle for validating EAN and GTIN barcodes. It provides validation constraints and services to check product codes such as EAN-8, EAN-13, UPC, and GTIN, helping ensure barcode data is correctly formatted and checksum-valid in your applications.
Architecture fit — poor as packaged. Despite the "Laravel/PHP package" framing, runcom/ean-validation-bundle is a Symfony bundle, not a Laravel package. Its name, RuncomEanValidationBundle, and the "Bundle" suffix indicate it registers a Symfony Bundle class, ships a DependencyInjection extension, and exposes validation through symfony/validator Constraint + ConstraintValidator pairs. Laravel's validator has no concept of bundles or the Symfony DI container, so composer require + $validator->validate() will not work out of the box. You would have to either (a) pull in symfony/validator and a Laravel bridge and manually instantiate the constraint validator, or (b) extract the underlying checksum logic and re-wrap it as a Laravel Rule object / Validator::extend() closure. Option (b) is almost certainly the right call.
What it actually contains. Functionally, EAN validation is a small, well-specified problem: strip separators, confirm the string is 8, 13, or 14 digits (EAN-8 / EAN-13 / GTIN-14), and compute the GS1 mod-10 check digit with alternating ×3/×1 weights. That is roughly 20–40 lines of deterministic arithmetic plus a regex. The bundle's total value-add over a hand-written implementation is therefore low; you are paying an integration tax for a checksum you can write in an afternoon and fully unit-test.
Integration feasibility — low. Three blockers stack up:
Technical risk — high, but bounded. The risk is not that the package is subtly broken; it is that you would be adopting an unmaintained, copyleft-licensed, framework-mismatched dependency to solve a problem whose entire domain is a check-digit algorithm you can fully specify and test in isolation. The risk is concentrated in process and legal exposure rather than runtime complexity.
Key questions to resolve before proceeding:
0123456789012 silently becomes 123456789012)?Stack fit — do not install the bundle. The correct integration is a reimplementation, not an adoption. Extract the specification (not the code) — GS1 mod-10 check digit, length rules for EAN-8/EAN-13/GTIN-14 — and implement a first-party EanRule implements \Illuminate\Contracts\Validation\Rule (or a closure via Validator::extend()), registered in a service provider. This avoids the GPL-3.0 copyleft question entirely, removes the Symfony DI dependency, and gives you a testable, ~40-line artifact you own.
Migration path. Since there is nothing installed, "migration" is really a build path:
isValidEan(string $value): bool; thin Laravel Rule wrapper; no I/O, no container coupling.If a licensing exception is later negotiated and there is some non-obvious feature we missed, the fallback path is to consume only the Symfony ConstraintValidator class behind an adapter interface, keeping the rest of the app unaware. Treat this as a contingency, not the plan.
Compatibility. A hand-written Rule has zero framework-version exposure: it works identically on Laravel 8 through 12 and on PHP 8.0+. It also composes cleanly with bail, required, and conditional rules, and can be reused verbatim in a queue worker or console import command where the Validator facade is available.
Sequencing. Do the reimplementation before any feature depends on EAN validation, so there is no intermediate state where a third-party package is load-bearing. If validation already exists somewhere as an inline regex, replace it in the same PR that adds the Rule, and add the test vectors at the same time so the regression surface is covered.
Maintenance — near zero, which is the point. A first-party checksum Rule has no dependency graph, no CVE surface, and no upstream abandonment risk. By contrast, adopting the bundle imports an unmaintained GPL dependency into your composer.lock and your legal surface simultaneously; even a trivial transitive CVE or a PHP minor-version break becomes your incident, with no maintainer to escalate to and no fork community to lean on.
Support. With the bundle, support is self-support: 6 stars and 0 dependents means essentially nobody has ever run this in production, so any bug you hit is yours alone. With a first-party Rule, support is internal and the code is small enough that any engineer on the team can read and fix it in minutes — a genuine bus-factor improvement over a black-box dependency.
Scaling. Validation is CPU-trivial: O(n) over an 8–14 character string, no allocation pressure, no I/O. It will not be a bottleneck at any realistic throughput (bulk product imports of 10⁵–10⁶ rows are still sub-second per 10k on the check-digit step). The only scaling-adjacent concern is input normalization discipline: validating inside a queue job after data has already been coerced to integers will silently pass garbage. Normalize at the boundary.
Failure modes to design against.
int drops leading zeros and produces false negatives (or false positives against the wrong length). Enforce string typing end-to-end, including the database column (varchar, not bigint).required on mandatory SKU fields and log rejections with the offending value and source row.Ramp-up. Engineering ramp-up is under a day for the implementation and tests. The real lead time is a short legal/compliance confirmation that GPL-3.0 code will not be incorporated — worth a 15-minute check with whoever owns licensing, and worth doing early so it does not become a late-stage blocker. Documentation burden is a single paragraph in the validation rules doc plus the test file, which doubles as the spec.
Bottom line for the product decision: the package is a low-signal, abandoned, copyleft, Symfony-only artifact solving a small deterministic problem. Do not adopt it. Reimplement the GS1 check digit as a first-party Laravel Rule with test vectors, and reserve the decision to revisit only if a maintained, permissively licensed GS1 library emerges that covers broader barcode/SKU needs.
How can I help you explore Laravel packages today?