fdisotto/partita-iva
Laravel/PHP package to validate EU VAT numbers via the EU VIES service (checkVatService). Performs a remote lookup against the official EC endpoint to confirm whether a VAT number exists across EU Member States.
Installation
composer require fdisotto/partita-iva:^3.0
Basic Usage Validate an Italian VAT number (Partita IVA) or EU VAT number:
use Fdisotto\PartitaIva\PartitaIva;
$validator = new PartitaIva();
$isValid = $validator->isValid('12345678901'); // Italian Partita IVA (bool)
$isEuValid = $validator->isValid('IT12345678901'); // EU VAT (bool, remote check)
First Use Case
use Illuminate\Support\Facades\Validator;
$validator = Validator::make(['vat' => 'IT12345678901'], [
'vat' => ['required', function ($attribute, $value, $fail) {
if (!app(\Fdisotto\PartitaIva\PartitaIva::class)->isValid($value)) {
$fail('The :attribute is invalid.');
}
}]
]);
Validation in Requests
Extend Laravel’s FormRequest for both local and remote validation:
use Fdisotto\PartitaIva\PartitaIva;
public function rules()
{
return [
'vat_number' => ['required', 'string', function ($attribute, $value, $fail) {
if (!app(PartitaIva::class)->isValid($value)) {
$fail('Invalid VAT number.');
}
}]
];
}
Service Layer Integration Create a dedicated service for VAT logic (now supporting EU checks):
namespace App\Services;
use Fdisotto\PartitaIva\PartitaIva;
class VatService {
protected $validator;
public function __construct(PartitaIva $validator) {
$this->validator = $validator;
}
public function validateVat(string $vat): bool {
return $this->validator->isValid($vat);
}
public function isEuVat(string $vat): bool {
return $this->validator->isEuVat($vat); // New method for EU-specific checks
}
}
Register the service in AppServiceProvider:
$this->app->bind(VatService::class, function ($app) {
return new VatService(new PartitaIva());
});
API Responses Return validation results with metadata (e.g., country code for EU VATs):
$result = app(PartitaIva::class)->validateWithDetails($request->vat);
return response()->json($result);
Batch Validation (EU + Italian) Validate multiple VAT numbers with mixed formats:
$vatNumbers = ['12345678901', 'IT12345678901', 'DE123456789'];
$results = collect($vatNumbers)->map(fn($vat) => [
'vat' => $vat,
'valid' => app(PartitaIva::class)->isValid($vat),
'is_eu' => app(PartitaIva::class)->isEuVat($vat),
]);
Custom Error Messages for EU VATs Differentiate between Italian and EU validation errors:
'vat' => ['required', function ($attribute, $value, $fail) {
$validator = app(PartitaIva::class);
if (!$validator->isValid($value)) {
if ($validator->isEuVat($value)) {
$fail('The :attribute is not a valid EU VAT number.');
} else {
$fail('The :attribute is not a valid Italian Partita IVA.');
}
}
}]
Caching Remote EU Checks Cache EU VAT responses to reduce API calls (e.g., using Laravel Cache):
$validator = new PartitaIva();
$validator->setCacheEnabled(true); // Enable caching (default: false)
$validator->setCacheTTL(3600); // Cache for 1 hour
Remote API Dependencies
setCacheEnabled(true)) to avoid repeated requests.try {
$isValid = $validator->isValid('IT12345678901');
} catch (\Exception $e) {
\Log::error("EU VAT check failed: " . $e->getMessage());
// Fallback to local validation or manual review
}
EU VAT Format Variations
XX123456789 (country code + digits).123456789 instead of IT123456789).US123456789).isEuVat() to pre-check format before remote validation.Rate Limiting
Deprecated Methods
isItalianVat() are deprecated in v3.0. Use isValid() for both Italian and EU checks.$validator->isItalianVat('12345678901'); // Deprecated
with:
$validator->isValid('12345678901'); // Works for both
Log Remote API Responses Enable debug mode to log EU VAT API responses:
$validator = new PartitaIva();
$validator->setDebugMode(true); // Logs API calls/responses
Test EU VAT Formats
Validate known EU VAT numbers (e.g., DE123456789, FR123456789012):
$validator = new PartitaIva();
$validator->isValid('DE123456789'); // Should return true/false
Fallback for Offline Mode Implement a fallback for when remote checks fail:
public function safeValidate(string $vat): bool {
try {
return app(PartitaIva::class)->isValid($vat);
} catch (\Exception $e) {
// Fallback: Validate as Italian Partita IVA only
return app(PartitaIva::class)->isItalianVat($vat);
}
}
Custom EU VAT Whitelisting Override EU validation logic to whitelist specific VATs:
class CustomPartitaIva extends PartitaIva {
protected $whitelist = ['IT12345678901', 'DE987654321'];
public function isValid(string $vat): bool {
if (in_array($vat, $this->whitelist)) {
return true;
}
return parent::isValid($vat);
}
}
Integration with Laravel Notifications Notify users of invalid VATs via email:
if (!$validator->isValid($request->vat)) {
$user->notify(new InvalidVatNotification($request->vat));
}
Testing Remote Calls Mock the EU VAT API in tests:
$validator = Mockery::mock(PartitaIva::class);
$validator->shouldReceive('isEuVat')
->with('IT12345678901')
->andReturn(true);
$this->app->instance(PartitaIva::class, $validator);
New Method: validateWithDetails()
Retrieve structured validation results (country code, validity, etc.):
$details = $validator->validateWithDetails('IT12345678901');
// Returns:
// [
// 'valid' => true,
// 'country_code' => 'IT',
// 'vat_number
How can I help you explore Laravel packages today?