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

Validation Laravel Package

phpviet/validation

Laravel validation rules for Vietnamese-specific data such as phone numbers, citizen ID cards, tax codes, and other local identifiers, with ready-to-use rules and localized error messages.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install: composer require phpviet/validation
  2. Register (only if needed): Laravel 5.5+ auto-discovers the service provider. On older apps, add the provider to config/app.php manually. There is usually nothing to configure to get started.
  3. Publish assets (optional): if the package ships translations/config, publish them so you can edit Vietnamese messages:
    php artisan vendor:publish --provider="PhpViet\Validation\ValidationServiceProvider"
    
  4. Where to look first:
    • The README rule table — it lists the exact rule aliases you pass as strings.
    • src/ — one class per rule; read the class if the README is ambiguous.
    • CHANGELOG.md — the 1.0.2 release note is just a link to it, so read the actual entry before upgrading.
  5. First use case — validating a Vietnamese mobile number and citizen ID at registration:
    $request->validate([
        'phone'         => ['required', 'string', 'vietnamese_phone'],
        'identity_card' => ['nullable', 'string', 'vietnamese_identity_card'],
    ]);
    
    Confirm the exact rule strings against your installed version's README; aliases are the most common source of "rule not found" confusion.

Implementation Patterns

Prefer FormRequests over inline validation. The rules are verbose in controllers and you will reuse them across register/profile/admin-edit flows.

class StoreUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'phone'         => ['required', 'string', 'bail', 'vietnamese_phone', 'unique:users,phone'],
            'identity_card' => ['nullable', 'string', 'vietnamese_identity_card', 'unique:users,identity_card'],
        ];
    }
}

Normalize input before validating, not after. Users paste +84 912 345 678, 0912.345.678, or numbers with non-breaking spaces. Strip separators in prepareForValidation() so both the rule and your unique check see the same canonical value:

protected function prepareForValidation(): void
{
    $this->merge([
        'phone' => preg_replace('/[\s.\-()]/', '', (string) $this->phone),
    ]);
}

Use rule objects for conditional/business logic. String aliases are fine for simple fields; instantiate the rule class when you need constructor arguments (e.g. restricting to mobile-only, or a specific carrier prefix) or when you want the rule unit-testable in isolation.

Pair with sometimes / nullable deliberately. A partial-update endpoint should use sometimes|..., otherwise an absent key fails validation and forces clients to resend the whole record.

Localize the messages. If the package ships vi translations, publish them and confirm the :attribute placeholder renders your field label rather than the raw column name — set attributes() in the FormRequest.

Test with data providers. Validation rules are pure functions of a string, which makes them ideal for table-driven tests:

public static function phones(): array
{
    return [
        ['0912345678', true],
        ['+84912345678', false], // if the rule expects local format
        ['0912', false],
        ['', false],
    ];
}

This is also the fastest way to pin down behaviour after a patch release like 1.0.2 — you get a regression suite that tells you immediately whether the regex tightened or loosened.

Reuse on the API and Blade side. Expose the same rule set through a shared RuleSet/rules() trait so web forms, API resources, and import jobs cannot drift apart. Import jobs especially benefit: run each row through Validator::make() with the same rules rather than hand-rolling checks.

Gotchas and Tips

  • Format expectations are strict. Most failures come from +84 vs 0 prefixes and from landline-vs-mobile distinctions. Decide once which canonical form you store, document it, and normalize at the boundary. If the rule only accepts one form, +84 input will fail silently in the sense that it returns a generic "invalid" message.
  • CMND (9 digits) vs CCCD (12 digits). If the rule accepts only one length, older records will fail profile updates. Check the rule class before assuming both are covered.
  • Empty string vs null. Laravel's ConvertEmptyStringsToNull middleware turns "" into null, so nullable works — but only for HTTP requests. Console commands, queue payloads, and Validator::make() calls bypass the middleware and will pass "" straight through. Use filled or normalize explicitly in those paths.
  • bail placement. Put bail first so a malformed number doesn't also trigger a unique database query. Cheap wins on high-traffic registration endpoints.
  • Publish translations before editing. Editing files inside vendor/ is lost on the next composer update. If there is no publish tag, override the message with the third argument to validate() or a messages() method on the FormRequest instead.
  • Patch releases like 1.0.2 can still change regexes. The release note here is a bare link to CHANGELOG.md, which is not surfaced in Composer's output. Before bumping, read the changelog entry and run your data-provider tests; a "fix" to a phone regex can silently reject numbers you already have in production.
  • Pin the constraint sensibly. "phpviet/validation": "^1.0" is safe for patch updates, but if your stored data depends on acceptance behaviour, add the validation test suite to CI so a minor bump that tightens a rule fails the build rather than rejecting real users.
  • Rule name collisions. Aliases are global in the Validator. If another package registers a similarly named rule (or you do via Validator::extend), the last registration wins. Check Validator::getRules() in Tinker if a rule behaves unexpectedly.
  • Validate, don't format. Use the package to accept/reject, then store the normalized value yourself. Don't store the user's raw pasted string and re-validate on read.
  • Debugging: if a rule "always fails", dd() the rule class's regex against your input directly, and check that the value isn't an array or object (form-array input from a misconfigured name="phone[]" will fail every string rule).
  • Extension points: when a rule is close but not exact (e.g. you also accept +84), wrap it rather than fork it — a small custom rule that normalizes and then delegates keeps you on the package's future bug fixes while adding your own leniency.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core