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

Amukana Plvalidator Bundle Laravel Package

nysander/amukana-plvalidator-bundle

Symfony bundle that wraps Polish validation rules (PESEL, NIP, REGON and similar) as constraints for the Validator component, so you can validate forms and entities via annotations, attributes or YAML. Installs with Composer and registers its services automatically, keeping Polish-specific checks ou...

View on GitHub
Deep Wiki
Context7

Getting Started

First, the framing problem: despite the "Bundle" suffix and Symfony conventions, this package targets the Symfony Validator component, not Laravel's Validator. There is no Laravel service provider, no facade, no Rule objects. A Laravel developer adopting it is really adopting Symfony's constraint classes and wiring them in by hand. Plan for that from hour one.

Minimal steps:

  1. Install from source, not Packagist-first. The repo is archived; verify a tagged release still resolves against your PHP version. If composer require nysander/amukana-plvalidator-bundle fails on platform constraints, clone it and composer require via a path or VCS repository. Pin the commit hash.
  2. Read src/ before anything else. Symfony bundles follow a rigid layout: each validator is a pair of a Constraint subclass (the annotation/attribute + message) and a ConstraintValidator (the algorithm). The checksum logic lives in the *Validator classes and is your real asset — the bundle plumbing around it is nearly worthless in Laravel.
  3. Ignore the DependencyInjection/, Resources/config/, and bundle registration files. They exist to register services into Symfony's container. In Laravel you will not load the bundle; you will instantiate the validator classes directly or port them.
  4. Pick your first use case: PESEL on a registration or checkout form. It is the highest-value one because the number is self-describing (encodes birth date, century, and sex), which lets you cross-check user-entered data for free.

Concrete first step in a Laravel app:

use Symfony\Component\Validator\Validation;
use Amukana\...\Constraint\Pesel;   // confirm the exact namespace in src/

$validator = Validation::createValidator();
$violations = $validator->validate($request->input('pesel'), [new Pesel()]);

if (count($violations) > 0) {
    // (string) $violations[0]->getMessage()
}

That is the whole integration. Everything else is ergonomics.

Implementation Patterns

Pattern 1 — Wrap constraints as Laravel Rule objects. This is the pattern you will actually live in. One thin adapter per document type keeps controllers and form requests clean, and lets you swap the underlying implementation later without touching call sites.

class PolishDocument implements Rule
{
    public function __construct(private string $type) {}   // pesel|nip|regon|idcard|iban

    public function passes($attribute, $value): bool
    {
        $value = $this->normalize($value);

        $constraint = match ($this->type) {
            'pesel'  => new Pesel(),
            'nip'    => new Nip(),
            'regon'  => new Regon(),
            'idcard' => new IdentityCard(),
            'iban'   => new Iban(),
        };

        return Validation::createValidator()
            ->validate($value, [$constraint])
            ->count() === 0;
    }

    public function message(): string
    {
        return "The :attribute is not a valid Polish {$this->type}.";
    }

    private function normalize(?string $v): string
    {
        return strtoupper(preg_replace('/[\s\-]/', '', (string) $v));
    }
}

Pattern 2 — Normalize before validating, store normalized. Users type NIPs as 123-456-32-18, PESELs with spaces, IBANs in groups of four, and lowercase ID-card letters. Strip separators and uppercase in a prepareForValidation() hook or a model mutator, not inside the rule, so the same normalized value is what hits the database and what later comparisons use. Never store the raw typed string and validate the cleaned one — you will get mismatches on update.

Pattern 3 — Cross-validate derived PESEL data. After a PESEL passes, decode it rather than trusting the form: digits 1–6 are the birth date, digit 7–10 encode century/month and sex. Compare the decoded date to the user's date_of_birth field and flag mismatches. This catches both typos and shared/stolen numbers. Do this in a form request withValidator() closure, not in the Rule.

Pattern 4 — Conditional constraints by entity type. A B2B checkout needs NIP validated and REGON optional; a B2C checkout needs neither but needs PESEL. Rather than baking document type into the request class, use Laravel's Rule::when() or a $type field to select which rules apply. The bundle has no notion of "when is this document required" — that is your domain logic.

Pattern 5 — Use standalone Symfony Validator, not the bridge. Do not install symfony/validator and attempt to use illuminate/validation with Symfony constraints — Laravel's validator expects its own Rule contract. The Validation::createValidator() factory plus a Rule adapter (Pattern 1) is less machinery and easier to test. Cache the validator instance if you validate in a loop over imported rows; constructing it per-call is wasteful.

Pattern 6 — If the package is unusable, port the algorithm. Because it is archived, treat the ConstraintValidator classes as reference implementations, not dependencies. The checksum algorithms are short and public-domain: PESEL weights 1,3,7,9,1,3,7,9,1,3 mod 10; NIP weights 6,5,7,2,3,4,5,6,7 mod 11 (result 10 ⇒ invalid); REGON has 9- and 14-digit variants with their own weight vectors; IBAN is the standard mod-97 check on rearranged digits. Copying ~40 lines per document type into your own app/Support/Validators/ folder permanently removes the archived-dependency risk and the Symfony plumbing.

Pattern 7 — Bulk imports. For CSV imports of customer or contractor lists, validate through the adapter in a queued job or a streamed import, and collect violations into a per-row error report rather than throwing on the first bad NIP. This is where the low dependency footprint helps: no framework coupling means it runs fine inside a queue worker.

Gotchas and Tips

  • Archived status is the headline risk. No security fixes, no PHP 8.3/8.4 support guarantees, no Symfony 7 compatibility. Check composer.json for the symfony/validator constraint — if it caps below what Laravel's ecosystem pulls in, you will get a resolver conflict. The pragmatic answer is Pattern 6: extract the algorithms and delete the dependency.
  • The bundle's service registration is inert in Laravel. Do not try to make Laravel boot it. Copy the validation logic out; leave the container config behind.
  • Checksum ≠ existence. These validate format only. A perfectly well-formed PESEL for a person who does not exist will pass. For anything regulated (KYC, invoicing), you still need the official REGON/VIES lookup APIs — the bundle does not do that.
  • REGON length ambiguity. Polish REGON is 9 digits for small entities and 14 for large ones, and the 14-digit value embeds the 9-digit one. Make sure the constraint you use accepts both if your domain needs both; a validator wired only for the 9-digit case will silently reject legitimate corporate numbers.
  • NIP mod-11 edge case. A checksum of exactly 10 is invalid, not valid. If you port the algorithm yourself, this is the bug people write most often — do not accept result === 10.
  • Identity card letter mapping. Letters map A=10 … Z=35, with weights 7,3,1,9,7,3,1,7,3 and a final sum % 10 === 0. Uppercase before mapping or a will produce a nonsense value and a confusing pass/fail.
  • Normalization belongs outside the validator. The constraint validators assume clean input. Feed one a string with a hyphen and it will either fail cryptically or, worse, treat the hyphen as part of the checksum input. Normalize first, always.
  • Error messages are likely Polish-only. The Constraint classes hardcode messages and the bundle's translation resources are Symfony-format (Resources/translations/validators.pl.xlf), not Laravel's lang/ files. If your UI is English, override the message in your Rule::message() — it is simpler than wiring a Symfony translator.
  • Test with real-format fixtures, not random digits. A random 11-digit string fails PESEL 90% of the time for the wrong reason. Collect known-valid samples per document type and assert both positive and negative cases; also assert the mod-11-equals-10 NIP edge case explicitly.
  • Extension point to know: the only genuinely reusable seam is the Constraint/ConstraintValidator pair itself. Subclass the Constraint if you need a custom message or payload, but do not subclass the validator — the algorithms are not written for extension.
  • Versioning: if you do depend on it, commit the archive ref and add a README-level note in your repo explaining why an archived dependency exists and what replaces it. Future maintainers will otherwise remove it and break Polish checkout silently.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator