Documentation Index
Fetch the complete documentation index at: https://mintlify.com/josemmo/Verifactu-PHP/llms.txt
Use this file to discover all available pages before exploring further.
Verifactu-PHP uses three exception classes, all extending PHP’s built-in RuntimeException, to signal different failure modes at different stages of the billing workflow. Understanding which class is thrown — and when — lets you write targeted catch blocks and present meaningful error information to operators.
InvalidModelException
Fully qualified name: josemmo\Verifactu\Exceptions\InvalidModelException
InvalidModelException is thrown by Model::validate() when one or more Symfony Validator constraints fail. Every model class (RegistrationRecord, CancellationRecord, AeatResponse, etc.) inherits validate() from the abstract josemmo\Verifactu\Models\Model base class, so this exception can be raised anywhere validate() is called.
Properties
violations
ConstraintViolationListInterface
The complete list of Symfony Validator constraint violations that caused validation to fail.
Declared as public readonly — iterate over it to extract property paths and messages.
Type: Symfony\Component\Validator\ConstraintViolationListInterface.
Code example
use josemmo\Verifactu\Exceptions\InvalidModelException;
use josemmo\Verifactu\Models\Records\RegistrationRecord;
$record = new RegistrationRecord();
// (populate $record fields …)
try {
$record->validate();
} catch (InvalidModelException $e) {
echo "Validation failed with " . count($e->violations) . " error(s):\n";
foreach ($e->violations as $violation) {
printf(
" • %s: %s\n",
$violation->getPropertyPath(), // e.g. "totalTaxAmount"
$violation->getMessage() // e.g. "This value should not be blank."
);
}
}
InvalidModelException::__construct() also calls parent::__construct() with a pre-formatted
human-readable summary, so $e->getMessage() provides a quick overview of all violations
without needing to iterate $e->violations.
AeatException
Fully qualified name: josemmo\Verifactu\Exceptions\AeatException
AeatException is thrown by AeatClient::send() when the AEAT server returns a SOAP fault or when the response body cannot be parsed into a valid AeatResponse object. It extends RuntimeException directly with no additional properties — use $e->getMessage() to retrieve the fault string or parse-error description.
AeatException can be thrown even when the HTTP call returns a 200 OK status code. The AEAT
VERI*FACTU web service embeds SOAP faults inside a standard HTTP 200 body. Always wrap
send()->wait() in a try/catch regardless of HTTP status.
Code example
use josemmo\Verifactu\Exceptions\AeatException;
try {
$response = $client->send($records)->wait();
} catch (AeatException $e) {
// Could be a SOAP fault string from AEAT, or a missing/invalid XML element
echo 'AEAT communication error: ' . $e->getMessage();
}
ImportException
Fully qualified name: josemmo\Verifactu\Exceptions\ImportException
ImportException is thrown by Record::fromXml() (and by extension RegistrationRecord::fromXml() and CancellationRecord::fromXml()) as well as ComputerSystem::fromXml() when a required XML element is absent or contains a value that cannot be mapped to the expected PHP type or enum. It extends RuntimeException with no additional properties — $e->getMessage() returns a description of the missing or invalid element.
Code example
use josemmo\Verifactu\Exceptions\ImportException;
use josemmo\Verifactu\Models\Records\Record;
use UXML\UXML;
$xml = UXML::fromString($rawXmlString);
try {
$record = Record::fromXml($xml->get('sum1:RegistroAlta'));
} catch (ImportException $e) {
echo 'Failed to parse record XML: ' . $e->getMessage();
// e.g. "Missing <sum1:TipoFactura /> element"
// "Invalid value for <sum1:RechazoPrevio /> element"
}
Comprehensive catch block
The following pattern handles all three exception types in a single try block, appropriate for end-to-end send workflows:
use josemmo\Verifactu\Exceptions\AeatException;
use josemmo\Verifactu\Exceptions\ImportException;
use josemmo\Verifactu\Exceptions\InvalidModelException;
use josemmo\Verifactu\Models\Responses\ItemStatus;
use josemmo\Verifactu\Models\Responses\ResponseStatus;
try {
// 1. Validate the record before sending
$record->validate();
// 2. Send and wait for the AEAT response
$response = $client->send([$record])->wait();
// 3. Check global status
if ($response->status === ResponseStatus::Incorrect) {
echo "Submission rejected by AEAT\n";
}
// 4. Check per-record status
foreach ($response->items as $item) {
if ($item->status === ItemStatus::Incorrect) {
printf(
"Record %s rejected: [%s] %s\n",
$item->invoiceId->invoiceNumber,
$item->errorCode,
$item->errorDescription
);
}
}
} catch (InvalidModelException $e) {
// Validation failed locally — do not send to AEAT
echo "Record validation errors:\n";
foreach ($e->violations as $violation) {
printf(" • %s: %s\n", $violation->getPropertyPath(), $violation->getMessage());
}
} catch (AeatException $e) {
// SOAP fault or unparseable response from AEAT
// Note: this can occur even on HTTP 200 responses
echo "AEAT server error: " . $e->getMessage() . "\n";
} catch (ImportException $e) {
// Malformed XML when importing records from an external source
echo "XML import error: " . $e->getMessage() . "\n";
}