Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ean Validation Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install anything, internalize what this is: runcom/ean-validation-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config file, no facade, no Laravel auto-discovery. What it actually ships is a Symfony Validator Constraint + ConstraintValidator pair that checks an EAN string's digit checksum. That single isValid() method is the entire value proposition — treat the bundle as reference source code, not a dependency you'll wire into your app.

Where to look first: open the constraint class (likely Runcom\EanValidationBundle\Validator\Constraints\Ean or similar) and its paired validator. Read the checksum loop. That's ~20 lines of arithmetic you can lift wholesale. Everything else in the bundle exists to register it with Symfony's validator service container — irrelevant to you.

Minimal install (for reference reading only):

composer require --dev runcom/ean-validation-bundle

Or just git clone the repo and read it — you don't need it in composer.json if you're only copying logic.

First use case: a product/catalog form where staff type barcodes by hand. You want to reject typos like a transposed digit before the record hits the DB. That's exactly the job this handles. Known-good smoke test value: 4006381333931 (valid EAN-13). Known-bad: 4006381333930.

Implementation Patterns

Pattern 1 — lift the logic into a Laravel Rule object. This is what you'll actually do 90% of the time. Take the checksum method, drop it into app/Rules/Ean.php:

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Ean implements ValidationRule
{
    public function __construct(private int $length = 13) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (!is_string($value) || !preg_match('/^\d{13}$/', $value) || !$this->checksum($value)) {
            $fail("The {$attribute} is not a valid EAN-13.");
        }
    }

    private function checksum(string $ean): bool
    {
        $sum = 0;
        for ($i = 0; $i < 12; $i++) {
            $sum += (int) $ean[$i] * ($i % 2 === 0 ? 1 : 3);
        }
        return ((10 - $sum % 10) % 10) === (int) $ean[12];
    }
}

Pattern 2 — FormRequest integration. Once it's a Rule, it composes like any other Laravel rule. Use it in ProductRequest::rules():

return [
    'name' => ['required', 'string', 'max:255'],
    'ean'  => ['required', 'string', new \App\Rules\Ean()],
];

Pattern 3 — bulk import validation. The highest-value day-to-day scenario. Supplier CSV with thousands of barcodes. Run each row through the rule inside a Rule::forEach() on the array, or in a chunked Bus::batch validator. Because the rule is pure (no I/O, no container lookups), you can instantiate it inside a queue worker for a million rows without breaking a sweat.

Pattern 4 — model-level guard. If you want the domain invariant enforced below the HTTP layer, add an assertEan() helper on the model or a saving observer. Keep the checksum in a single App\Support\Ean static class so both the rule and the model call the same code — don't duplicate the loop.

Pattern 5 — if you insist on keeping the dependency wired in. You'd have to bootstrap Symfony's ValidatorBuilder manually, load the bundle's constraint mapping, and register the validator factory as a Laravel singleton. This pulls symfony/validator, symfony/translation-contracts, and a few others into your composer.json. It works, but you're carrying a framework you don't use to validate 13 digits. Don't.

Gotchas and Tips

  • License is the biggest one. GPL-3.0 is a strong copyleft license. For a proprietary Laravel SaaS, linking this into your codebase is a legal problem. Copying the checksum algorithm (facts/math) is generally fine, but copying the class verbatim is not. Reimplement the arithmetic yourself from the spec — it's a public standard (ISO/IEC 15420) and the algorithm is trivial. Keep the bundle out of composer.json in production entirely.
  • Laravel auto-discovery will not find this. php artisan vendor:publish and config/bundles.php conventions don't apply. If you add it as a runtime dependency expecting it to "just work," you'll get a class-not-found or an unregistered validator.
  • EAN is a family, not one format. EAN-8, EAN-13, UPC-A (12-digit), and ISBN-13 all use the same mod-10 checksum but different digit counts and weight patterns. A naive copy of the loop that hardcodes 13 will silently accept valid checksums on the wrong length. Validate length first, then checksum.
  • Leading zeros and integer types. EANs are strings, never integers. 0075678164125 becomes 75678164125 if cast to int and the checksum shifts. Guard against JSON/CSV importers that coerce numeric strings — this is the #1 real-world failure. Enforce string in your rule and cast on the way in.
  • UPC-A ↔ EAN-13 compatibility. A 12-digit UPC-A is a valid EAN-13 with a leading zero prepended, and the check digit stays the same. If supplier data is mixed, normalize UPC-A → EAN-13 by prefixing 0 rather than rejecting it, or your import reports explode with false negatives.
  • Debugging failed validations. Dump the weighted sum and the expected check digit rather than the boolean. 90% of "valid barcode rejected" tickets are whitespace (" 4006381333931"), leading-apostrophe Excel artifacts ('4006381333931), or a stray check digit from a mis-scanned label. trim() before validating and in the rule itself.
  • Don't trust the input. The Symfony validator's isValid() may not guard against non-string input (arrays, nulls) depending on version. In Laravel you always get a mixed value — bail early with is_string() and a regex before touching indices, or PHP 8 will throw on offset access.
  • Extension point worth keeping: expose the length as a constructor arg (new Ean(8), new Ean(13)) so the same rule serves EAN-8 for small products and EAN-13 for retail. One rule class, two use sites, no drift.
  • Test with a fixture set. Store 5–10 known-valid and deliberately-invalid EANs in a tests/Fixtures/ean.php and assert both directions in a Pest/PHPUnit data provider. This is cheap insurance that a future refactor of the loop doesn't quietly flip a weight multiplier.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib