VAVANG INVOICE / DOCS / EN

Service decoration

Use Symfony service decoration when you need to add behavior around a single Vavang service without replacing the complete implementation.

Example: decorate Factur-X generation

FacturXGeneratorInterface is aliased by the plugin to its default generator. A host application can decorate that interface service id:

<?php

declare(strict_types=1);

namespace App\Invoice;

use SyliusInvoicePlugin\ElectronicInvoice\ElectronicInvoice;
use SyliusInvoicePlugin\FacturX\FacturXGeneratorInterface;
use SyliusInvoicePlugin\FacturX\GeneratedFacturXDocument;

final readonly class AuditingFacturXGenerator implements FacturXGeneratorInterface
{
    public function __construct(private FacturXGeneratorInterface $inner)
    {
    }

    public function generate(ElectronicInvoice $invoice, string $sourcePdfContent): GeneratedFacturXDocument
    {
        $document = $this->inner->generate($invoice, $sourcePdfContent);

        // Observe or record application-specific information here.
        // Do not mutate the generated fiscal payload after validation.

        return $document;
    }
}
# config/services.yaml
services:
    App\Invoice\AuditingFacturXGenerator:
        decorates: SyliusInvoicePlugin\FacturX\FacturXGeneratorInterface
        arguments:
            $inner: '@App\Invoice\AuditingFacturXGenerator.inner'

This keeps the plugin implementation behind the public interface and avoids depending on the concrete HorstoekoFacturXGenerator constructor.

Example: add a business rule

ElectronicInvoiceBusinessRuleInterface is a collection extension point consumed through the sylius_invoice.business_rule tag. The bundle’s _instanceof rule applies to services loaded by the plugin itself; it does not globally tag business-rule services declared by the host application.

Register the tag explicitly:

<?php

declare(strict_types=1);

namespace App\Invoice;

use SyliusInvoicePlugin\ElectronicInvoice\ElectronicInvoice;
use SyliusInvoicePlugin\Validation\BusinessRule\ElectronicInvoiceBusinessRuleInterface;

final class ProjectBusinessRule implements ElectronicInvoiceBusinessRuleInterface
{
    public function validate(ElectronicInvoice $invoice): array
    {
        return [];
    }
}
services:
    App\Invoice\ProjectBusinessRule:
        tags: ['sylius_invoice.business_rule']

The same explicit-tag rule applies to host implementations of the transmission, payment-reporting and webhook extension families documented on Extension points. Platform connectors and platform operations are different: those interfaces are registered for autoconfiguration by the bundle extension.

Replace only when decoration is insufficient

Replacing an alias is possible for contracts such as SellerCompanyProviderInterface, VariantProductNatureResolverInterface, ElectronicDocumentValidatorInterface or ComplianceDocumentStoreInterface. A replacement owns the full contract and must preserve every invariant expected by the compliance pipeline.

Prefer decoration for logging, metrics, mirroring or additional checks. Prefer replacement only when the default behavior fundamentally cannot satisfy the project.

BC risk

Do not decorate concrete classes simply because they are currently public services. Concrete constructor dependencies can evolve. The documented interface service id is the safer boundary.