Every data object in Verifactu-PHP — from a full billing record down to a single tax breakdown line — is an instance of a class that extends the abstractDocumentation 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.
josemmo\Verifactu\Models\Model base class. This shared base exposes a single public method, validate(), that runs all constraint checks for that object and any nested child objects. When a constraint fails, validate() throws an InvalidModelException whose $violations property gives you a structured list of exactly what went wrong and where. This design means you can validate any model in isolation, or call validate() on a top-level record to recursively check the entire object graph in one shot.
The Model base class
Model is a final-method abstract class in the josemmo\Verifactu\Models namespace. Its only public method is validate():
validate() builds a Symfony Validator instance with attribute mapping enabled, meaning all constraints are declared directly as PHP 8 attributes on the model properties (e.g. #[Assert\NotBlank], #[Assert\Regex(...)], #[Assert\Callback]). No separate YAML or XML validation config files are needed.
If the validator finds one or more violations it wraps them in an InvalidModelException and throws it. If validation passes, validate() returns void with no side effects.
Using validate()
Wrap anyvalidate() call in a try/catch block and catch josemmo\Verifactu\Exceptions\InvalidModelException:
__toString() method renders all violations in a human-readable bullet list, which is handy for quick debugging. For programmatic handling, iterate $e->violations directly.
Available models
The following concrete model classes ship with Verifactu-PHP:| Class | Namespace | Purpose |
|---|---|---|
ComputerSystem | josemmo\Verifactu\Models | Describes the SIF itself (software name, version, NIF, etc.) |
RegistrationRecord | josemmo\Verifactu\Models\Records | Billing record for a new or corrected invoice |
CancellationRecord | josemmo\Verifactu\Models\Records | Billing record for the cancellation of a prior record |
BreakdownDetails | josemmo\Verifactu\Models\Records | Single tax line within a registration record’s breakdown |
InvoiceIdentifier | josemmo\Verifactu\Models\Records | Tuple of issuer NIF, invoice number, and issue date |
FiscalIdentifier | josemmo\Verifactu\Models\Records | Spanish fiscal identity (name + NIF) for invoice recipients |
ForeignFiscalIdentifier | josemmo\Verifactu\Models\Records | Non-Spanish fiscal identity (name, country, ID type, ID value) |
AeatResponse | josemmo\Verifactu\Models\Responses | Parsed response from an AEAT web service call |
Model and therefore expose validate().
Validation constraints
Constraints are declared as PHP 8 attributes directly on model properties. The library uses several constraint families:Presence & length
#[Assert\NotBlank] ensures required string fields are neither null nor empty. #[Assert\Length] enforces maximum (or exact) character counts — for example, issuerName allows up to 120 characters and issuerId must be exactly 9 characters.Format (Regex)
Monetary amounts use
#[Assert\Regex(pattern: '/^-?\d{1,12}\.\d{2}$/')] to enforce the ####.## decimal format the AEAT requires. Tax rates use a similar pattern restricted to non-negative values.Nested objects (Valid)
#[Assert\Valid] on a property causes validate() to recurse into that nested model (e.g. invoiceId, breakdown[]), so a single top-level validate() call checks the entire object graph.Business rules (Callback)
#[Assert\Callback] methods implement cross-field logic that simple attribute constraints cannot express — including hash integrity, tax amount cross-checks, recipient rules by invoice type, and corrective invoice details.validateHash— verifies that$record->hash === $record->calculateHash(), catching any mismatch between the stored hash and the record’s current field values.validateTotals— sums allBreakdownDetails->taxAmountvalues and checks they equaltotalTaxAmount; also checkstotalAmountagainst the sum of base amounts and tax amounts (with ±€0.02 rounding tolerance).validateRecipients— enforces that simplified invoices (InvoiceType::Simplificada,InvoiceType::R5) must have no recipients, while all other invoice types require at least one.validateCorrectiveDetails— ensures corrective invoices carry acorrectiveTypeand that non-corrective invoices do not.validateOperationType— ensurestaxRateandtaxAmountare present for subject operations and absent for non-subject or exempt ones.
Reading violation details
InvalidModelException exposes a public readonly property $violations of type Symfony\Component\Validator\ConstraintViolationListInterface. You can iterate it to access each violation’s property path and message:
$violation is a Symfony\Component\Validator\ConstraintViolation instance. Useful methods:
| Method | Returns |
|---|---|
getPropertyPath() | Dot-notation path to the failing field, e.g. breakdown[0].taxAmount |
getMessage() | Human-readable description of the failure |
getInvalidValue() | The actual value that failed the constraint |
getRoot() | The top-level model object that validate() was called on |
Example: catching a tax amount mismatch
The followingBreakdownDetails deliberately sets taxAmount to an incorrect value. The validateTaxAmount callback detects the mismatch and validate() throws with a descriptive message:
baseAmount × taxRate / 100 (with a ±€0.02 rounding tolerance) and reports the discrepancy, pointing directly at the taxAmount property path.