carloschininin/facturax-contracts
DTOs versionados (Api\V1\Dto) para contratos de la API Facturax. Permite construir y validar localmente payloads JSON antes de enviarlos o persistirlos. Incluye bundle Symfony opcional con servicios de validación y normalización.
Install the package:
composer require carloschininin/facturax-contracts
Ensure your project uses PHP 8.5+ and Symfony 8.x (or Laravel 10+ with Symfony compatibility).
Register the Symfony bundle (optional but recommended for validation services):
In config/bundles.php:
return [
CarlosChininin\FacturaxContracts\CarlosChinininFacturaxContractsBundle::class => ['all' => true],
];
First use case: Validate a Facturax invoice payload
Use the ContractValidator service to validate a JSON payload before submission:
use CarlosChininin\FacturaxContracts\Service\ContractValidator;
$validator = app(ContractValidator::class);
$isValid = $validator->validate(
json_decode(file_get_contents('path/to/comprobante-factura.json'), true),
'Api\V1\Dto\Comprobante\ComprobanteRequestDto'
);
Normalize a payload (optional)
Use the ContractNormalizer to standardize data:
use CarlosChininin\FacturaxContracts\Service\ContractNormalizer;
$normalizer = app(ContractNormalizer::class);
$normalizedData = $normalizer->normalize(
$rawPayload,
'Api\V1\Dto\Comprobante\ComprobanteRequestDto'
);
Reference JSON examples
Clone the package’s docs/examples/v1/ directory for validated JSON schemas:
git clone https://github.com/carloschininin/facturax-contracts.git
cp facturax-contracts/docs/examples/v1/comprobante-factura.json resources/json/
DTO-Driven Validation
Use the package’s DTOs (e.g., ComprobanteRequestDto) to enforce schema validation:
$validator = app(ContractValidator::class);
$errors = $validator->validate($payload, ComprobanteRequestDto::class);
if ($errors->count() > 0) {
// Handle validation errors
}
Symfony Bundle Integration
Register the bundle in config/bundles.php to auto-register services:
return [
CarlosChinininFacturaxContractsBundle::class => ['all' => true],
];
Access services via dependency injection:
public function __construct(
private ContractValidator $validator,
private ContractNormalizer $normalizer
) {}
Laravel Service Wrapper Create a Laravel-specific service to abstract Symfony dependencies:
namespace App\Services;
use CarlosChininin\FacturaxContracts\Service\ContractValidator;
class FacturaxValidatorService {
public function __construct(private ContractValidator $validator) {}
public function validateInvoice(array $payload): bool {
return $this->validator->validate($payload, ComprobanteRequestDto::class)->isEmpty();
}
}
Request Validation in Controllers Use the validator in Laravel controllers or form requests:
use App\Services\FacturaxValidatorService;
public function store(Request $request, FacturaxValidatorService $validator) {
$payload = $request->validate([
'invoice_data' => 'required|array',
]);
if (!$validator->validateInvoice($payload['invoice_data'])) {
return response()->json(['error' => 'Invalid invoice data'], 422);
}
// Proceed with invoice processing
}
Normalization Pipeline Chain normalization with validation for data consistency:
$normalizer = app(ContractNormalizer::class);
$normalized = $normalizer->normalize($rawData, ComprobanteRequestDto::class);
$validator = app(ContractValidator::class);
$validator->validate($normalized, ComprobanteRequestDto::class);
Invoice Submission Workflow
ComprobanteRequestDto.Batch Processing Use Laravel queues to process invoices asynchronously:
Invoice::where('status', 'pending')->each(function ($invoice) {
dispatch(new ProcessFacturaxInvoice($invoice->data))->onQueue('facturax');
});
Testing Validate JSON schemas in PHPUnit tests:
public function testInvoiceValidation() {
$validator = app(ContractValidator::class);
$errors = $validator->validate(
json_decode(file_get_contents('tests/json/invalid-invoice.json'), true),
ComprobanteRequestDto::class
);
$this->assertNotEmpty($errors);
}
Laravel Form Requests
Extend FormRequest to integrate validation:
use CarlosChininin\FacturaxContracts\Service\ContractValidator;
class StoreInvoiceRequest extends FormRequest {
public function rules() {
return [
'invoice_data' => 'required|array',
];
}
public function withValidator($validator) {
$validator->after(function ($validator) {
$validator->validator->extend('facturax_valid', function ($attribute, $value, $parameters) {
$validator = app(ContractValidator::class);
$errors = $validator->validate($value, ComprobanteRequestDto::class);
if ($errors->count() > 0) {
$validator->errorBag->add('facturax', $errors->toArray());
}
return $errors->isEmpty();
});
});
}
}
API Resource Transformation Use Laravel API Resources to format responses:
namespace App\Http\Resources;
use CarlosChininin\FacturaxContracts\Service\ContractNormalizer;
use Illuminate\Http\Resources\Json\JsonResource;
class InvoiceResource extends JsonResource {
public function __construct($resource, private ContractNormalizer $normalizer) {
parent::__construct($resource);
}
public function toArray($request) {
$normalized = $this->normalizer->normalize(
$this->resource,
ComprobanteRequestDto::class
);
return [
'data' => $normalized,
'metadata' => $this->whenLoaded('metadata'),
];
}
}
Symfony Dependency Isolation If avoiding Symfony, manually instantiate services:
$validator = new ContractValidator(
new OptionsResolver(),
new ConstraintValidator()
);
Custom DTOs Extend existing DTOs for project-specific fields:
namespace App\Dto;
use CarlosChininin\FacturaxContracts\Api\V1\Dto\Comprobante\ComprobanteRequestDto;
class CustomComprobanteRequestDto extends ComprobanteRequestDto {
public ?string $customField = null;
}
Symfony Dependency Conflicts
symfony/console).composer require symfony/options-resolver:^6.4 symfony/http-foundation:^6.4
composer why symfony/* to diagnose conflicts.PHP Version Mismatch
Validation Overhead
ContractNormalizer to standardize data before validation.Namespace Versioning
Api\V1\Dto\...). Future updates may break backward compatibility.composer.json:
"carloschininin/facturax-contracts": "^0.0.2"
Missing XML Generation
heynemann/laravel-facturae for XML generation.How can I help you explore Laravel packages today?