juststeveking/gtin-php
Validate and work with GTIN barcodes in PHP. juststeveking/gtin-php offers a clean API for checking GTIN-8, GTIN-12, GTIN-13, and GTIN-14 codes, including check digit verification, so you can trust product identifiers across your Laravel or PHP applications.
Architecture fit. The package is a stateless, dependency-free-at-runtime arithmetic utility: it takes a string, runs the GS1 Modulo-10 check-digit algorithm, and returns a boolean. It ships no service provider, no config, no facade, no migrations, and no facades — which means it imposes no architectural opinion on our application. That is the right shape for what it does. It belongs at the boundary of the catalogue domain, not inside it: form requests, CSV import handlers, scan-ingest endpoints, and seeder/factory fixtures. It should not be called from models, repositories, or anywhere that would make the domain layer depend on a third-party package for what is fundamentally a published standard. The architectural decision the TPM owns is therefore not "where does this class live" but "where is the validation gate in the product pipeline, and what is the contract above it." Wrap it behind an owned GtinValidator interface from day one; that single seam converts a five-star, single-maintainer package from a dependency risk into an implementation detail.
Integration feasibility. High for a discovery phase or an MVP, moderate for a long-lived catalogue-critical path. Installation is a one-line Composer require, the API surface is small enough to audit in under an hour, and the v1.0.1 patch correctly moved illuminate/support to require-dev, which means it now resolves cleanly into Laravel applications and slim CLI/queue-runner images alike. The main feasibility caveats are: (a) the last release was January 2021, so PHP 8.2/8.3 compatibility is undeclared even if the code executes fine; (b) zero dependents and five stars means no meaningful production feedback loop — we are effectively the first serious adopter; and (c) we must verify on a bare PHP install that no Illuminate\* references survive at runtime, because the manifest fix is a metadata change, not a code guarantee.
Technical risk. Contained, but real, and the containment depends entirely on discipline.
012345678905 is a valid GTIN-12; 12345678905 is a different, invalid value. Any int cast, bigint column, or Excel round-trip destroys identity and can produce a false pass against a different product. The package accepts integers, which is convenient in a REPL and dangerous in application code. Mitigation is architectural, not package-level: string columns, string casts, string form rules, and a wrapper that rejects non-digit input before delegating.Key questions to resolve before commitment.
GtinValidator contract, and is there a documented policy that no code outside the adapter may reference JustSteveKing\Gtin\*?string?Stack fit. Strong on paper and strong in practice for Laravel. Framework-agnostic at runtime since v1.0.1, no service provider to register, no publishable config, no facade alias — it drops into composer require and is callable immediately. It is a natural fit for FormRequest rules, CSV/feed import pipelines, barcode-scan ingest endpoints, and seeder/factory fixtures. It is a poor fit for anything requiring registry lookups, prefix-ownership assertions, or catalogue-level uniqueness — those are adjacent capabilities, not extensions of this one.
Migration path (greenfield). There is nothing to migrate, only a sequence to follow.
^1.0 and run composer why illuminate/support against every deployment image to confirm no runtime Illuminate coupling survives.src/ in full and confirm the actual method names and namespace before writing a single call site — the README and the source have diverged on smaller packages before.php artisan tinker against a corpus of real supplier codes, deliberately including leading-zero GTIN-12 and a known-bad check digit.GtinValidator interface (isValid(string), generate(int)) and a PackageGtinValidator adapter that trims, runs ctype_digit, enforces the 8/12/13/14 length whitelist, and catches throwables so a malformed scan payload returns false rather than a 500 mid-import.AppServiceProvider::register().ValidationRule object (or Validator::extend('gtin', ...) if rules are assembled dynamically) and the FormRequest that pairs it with bail, string, and max:14.Compatibility. Verify require.php against our runtime baseline; expect PHP 8.2/8.3 to be undeclared and confirm by execution rather than by manifest. Laravel 8.x consumers need Illuminate\Contracts\Validation\Rule with passes()/message() rather than the ValidationRule object form. The package's own test suite doubles as the canonical example set for GTIN-8/12/13/14 including leading-zero cases — use it as the acceptance corpus rather than inventing one.
Sequencing across the roadmap. Phase 1: ingest-form validation and the adapter seam. Phase 2: bulk CSV/feed import with per-row error accumulation and a structured reject log (supplier id, raw value, reason) that doubles as a supplier data-quality report. Phase 3: generated fixtures for seeders and factories, plus negative-path tests proving the rule rejects rather than silently passes. Phase 4: backfill/repair artisan command — the write path everyone forgets, which runs with withoutEvents() and raw queries where mutators and FormRequests are both bypassed. Phase 5 (separate roadmap, not this package): GS1 registry lookup, company-prefix ownership, and catalogue dedupe.
What not to do. Do not call Gtin::make() from a controller "just for now." Do not store GTINs in a bigint. Do not let a model accessor stand in for validation — an accessor normalises, a rule validates, and both are needed. Do not treat the package's verdict as proof of product-data authenticity.
Maintenance. Low effort, elevated attention. The package has been unchanged since January 2021, which for a frozen arithmetic algorithm is a feature, not a defect — Modulo-10 has not changed either. The ongoing cost is not patching the package but watching it: periodic PHP-version compatibility checks against a maintainer who may no longer be active, and a standing decision in the dependency register that vendoring the ~100 lines of MIT code is the documented fallback. Because we wrapped it behind GtinValidator, executing that fallback is a one-class change plus a container binding — but only if the wrapper discipline held.
Support. We are the support organisation. Five stars, zero dependents, single maintainer: there is no community to escalate to, no issue-tracker momentum to rely on, and no realistic expectation that a bug report filed today gets a release this quarter. Escalation path is internal: reproduce, inspect src/, and if necessary vendor and patch. That is acceptable for a check-digit calculator and would be unacceptable for anything stateful.
Scaling. Effectively free. The work is CPU-bound string arithmetic over at most 14 characters, allocation-light, with no IO, no external calls, and no caching requirement. For a 40,000-row supplier feed it will not be the bottleneck; CSV parsing and database writes will be. No connection pooling, quota, rate limit, or cold-start concerns. The scaling risk is organisational rather than computational: validating on ingest but not on the backfill command or the internal admin edit path means bad data still enters through the side doors.
Failure modes to design for.
bigint column). Symptom: false failures, or worse, false passes against a different product. Detection: assert string typing end-to-end and test explicitly with GTIN-12 values beginning in zero.try/catch in the adapter plus per-row error accumulation so the supplier receives a complete rejection report rather than a fail-fast abort.Illuminate\* reference surviving the v1.0.1 metadata fix converts a version conflict into a production error. Detection: bare-PHP smoke test in CI without Illuminate installed.Ramp-up. Negligible for any PHP developer — the API is one or two methods and the algorithm is a published standard. Realistic estimate is half a day for the adapter, rule, binding, and first call site, plus a day for the import path with error accumulation and logging. The genuine learning curve is not the package but the domain: leading-zero identity, canonical GTIN-14 normalisation, the GTIN-12/13/14 equivalence, and the ITF-14 packaging-indicator distinction. Those are onboarding items for the team, and getting them wrong costs far more than the package ever will. Plan for a short internal note or brown-bag covering "GTINs are strings, not numbers; format validation is not registry validation" so the knowledge does not live only in the reviewer who read the source.
How can I help you explore Laravel packages today?