Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eclipxe13/CfdiUtils/llms.txt

Use this file to discover all available pages before exploring further.

The CfdiUtils\Elements namespace contains a set of typed PHP classes — called elements — that wrap the generic Node data structure with named, version-aware methods for building valid CFDI documents. Instead of manually creating child nodes and remembering element names, you call methods like addEmisor(), addConcepto(), or addTraslado() and the element manages the XML hierarchy for you. Every element is a node. All methods and properties of NodeInterface — array-style attribute access, child iteration, search helpers — are available on every element. The Elements layer simply adds a typed API on top.

Difference Between Nodes and Elements

AspectCfdiUtils\Nodes\NodeCfdiUtils\Elements\*
PurposeGeneric in-memory XML treeTyped structure matching the CFDI specification
Child creationaddChild(new Node(...))addEmisor([...]), addConcepto([...]) etc.
Attribute access$node['Attr']$element['Attr'] (same — it’s still a Node)
Element orderingManual setOrder()Defined in getChildrenOrder() automatically
Fixed attributesNonegetFixedAttributes() pre-populates namespace declarations
Version awarenessNoneSeparate class tree per CFDI version
Every element class implements CfdiUtils\Elements\Common\ElementInterface, which extends NodeInterface with:
getElementName()
string
Returns the qualified XML element name, e.g. cfdi:Comprobante.
getFixedAttributes()
array
Returns attributes that are always pre-set when the element is constructed, such as xmlns:cfdi namespace declarations on the root Comprobante.
getChildrenOrder()
array
Returns the ordered list of child element names that the SAT specification requires, used to automatically sort children when they are added.

CFDI 4.0 Elements

Namespace: CfdiUtils\Elements\Cfdi40 The CFDI 4.0 element tree mirrors the structure defined in the SAT Anexo 20 for version 4.0.
ClassElement nameRole
Comprobantecfdi:ComprobanteRoot element; provides addEmisor, addReceptor, addConcepto, addImpuestos, addComplemento, addAddenda
Emisorcfdi:EmisorIssuer information
Receptorcfdi:ReceptorRecipient information
InformacionGlobalcfdi:InformacionGlobalGlobal information for simplified invoices
CfdiRelacionadoscfdi:CfdiRelacionadosContainer for related CFDI references
CfdiRelacionadocfdi:CfdiRelacionadoA single related CFDI UUID
Conceptoscfdi:ConceptosContainer for line items
Conceptocfdi:ConceptoA single invoice line item
Impuestoscfdi:ImpuestosTax summary at comprobante or concepto level
Trasladocfdi:TrasladoTransferred tax (IVA, IEPS, etc.)
Retencioncfdi:RetencionWithheld tax (ISR, IVA)
Complementocfdi:ComplementoContainer for SAT-defined complements
Addendacfdi:AddendaContainer for free-form addenda

CFDI 3.3 Elements

Namespace: CfdiUtils\Elements\Cfdi33 The CFDI 3.3 element tree provides the same structural pattern as 4.0 but targeting the prior version of the specification. The class names are identical (Comprobante, Emisor, Receptor, Conceptos, Concepto, etc.) — only the namespace and getFixedAttributes() differ. Switch from Cfdi33 to Cfdi40 by changing the import namespace.

Complement Elements

CfdiUtils ships typed element classes for many SAT-defined complements. Each complement namespace follows the same get* / add* / multi* pattern.
ComplementNamespaceRoot class
Nómina 1.2CfdiUtils\Elements\Nomina12Nomina
Carta Porte 3.0CfdiUtils\Elements\CartaPorte30CartaPorte
Carta Porte 3.1CfdiUtils\Elements\CartaPorte31CartaPorte
Comercio Exterior 2.0CfdiUtils\Elements\Cce20ComercioExterior
Pagos 2.0CfdiUtils\Elements\Pagos20Pagos
Pagos 1.0CfdiUtils\Elements\Pagos10Pagos
Retenciones 2.0CfdiUtils\Elements\Retenciones20Retenciones
Timbre Fiscal Digital 1.1CfdiUtils\Elements\Tfd11TimbreFiscalDigital

Naming Conventions

Elements follow a consistent three-prefix naming convention.
ElementoPadre::getElementoHijo(): ElementoHijo returns the single child instance of that type. If it does not exist yet, it is created and added automatically before being returned.Use get* when the specification allows at most one child of a given type (e.g., there can only be one Emisor inside a Comprobante).
<?php
use CfdiUtils\Elements\Cfdi40\Comprobante;

$comprobante = new Comprobante();
$emisor = $comprobante->getEmisor(); // creates it if absent, always returns same instance
$emisor['Rfc'] = 'EKU9003173C9';
ElementoPadre::addElementoHijo(array $attributes): ElementoHijoFor singleton children (e.g., Emisor): merges $attributes into the existing (or newly created) child and returns it.For repeatable children (e.g., Concepto): creates a brand-new instance with $attributes, appends it to the parent, and returns the new instance.
<?php
// Singleton: addEmisor updates the one Emisor
$comprobante->addEmisor(['Rfc' => 'EKU9003173C9', 'RegimenFiscal' => '601']);

// Repeatable: addConcepto creates a new Concepto each time
$concepto = $comprobante->addConcepto([
    'Descripcion'    => 'Desarrollo de software',
    'ValorUnitario'  => '10000.00',
    'Cantidad'       => '1',
    'ClaveUnidad'    => 'E48',
    'ClaveProdServ'  => '81112100',
]);
ElementoPadre::multiElementoHijo(array ...$elementAttributes): ElementoPadreCreates one child per argument array, adds each to the parent, and returns the parent for method chaining. This is equivalent to calling the corresponding add* method multiple times.
<?php
$cfdiRelacionados->multiCfdiRelacionado(
    ['UUID' => 'uuid-1-...'],
    ['UUID' => 'uuid-2-...'],
);

Usage Pattern: Building a CFDI 4.0 Document

The example below shows how elements chain together to build the core structure of a CFDI 4.0 invoice.
<?php
use CfdiUtils\Elements\Cfdi40\Comprobante;

$comprobante = new Comprobante([
    'Version'     => '4.0',
    'Fecha'       => '2024-01-15T10:00:00',
    'SubTotal'    => '10000.00',
    'Total'       => '11600.00',
    'Moneda'      => 'MXN',
    'TipoDeComprobante' => 'I',
]);

// Add issuer (singleton — only one Emisor allowed)
$comprobante->addEmisor([
    'Rfc'          => 'EKU9003173C9',
    'Nombre'       => 'ESCUELA KEMPER URGATE',
    'RegimenFiscal'=> '601',
]);

// Add recipient (singleton)
$comprobante->addReceptor([
    'Rfc'                    => 'COSC8001137NA',
    'Nombre'                 => 'CARLOS CORTES SOTO',
    'DomicilioFiscalReceptor'=> '06600',
    'RegimenFiscalReceptor'  => '605',
    'UsoCFDI'                => 'G03',
]);

// Add a line item (repeatable)
$concepto = $comprobante->addConcepto([
    'ClaveProdServ'  => '81112100',
    'Cantidad'       => '1',
    'ClaveUnidad'    => 'E48',
    'Descripcion'    => 'Desarrollo de software',
    'ValorUnitario'  => '10000.00',
    'Importe'        => '10000.00',
    'ObjetoImp'      => '02',
]);

// Add IVA to the line item
$concepto->addImpuestos()->addTraslados()->addTraslado([
    'Base'          => '10000.00',
    'Impuesto'      => '002',
    'TipoFactor'    => 'Tasa',
    'TasaOCuota'    => '0.160000',
    'Importe'       => '1600.00',
]);

// Add tax totals to the Comprobante
$comprobante->addImpuestos([
    'TotalImpuestosTrasladados' => '1600.00',
])->addTraslados()->addTraslado([
    'Impuesto'      => '002',
    'TipoFactor'    => 'Tasa',
    'TasaOCuota'    => '0.160000',
    'Importe'       => '1600.00',
    'Base'          => '10000.00',
]);
You rarely need to instantiate Comprobante directly. Use CfdiUtils\CfdiCreator40 instead — it creates a Comprobante for you, wires up the XmlResolver and XsltBuilder, and exposes buildCadenaDeOrigen() and addSello() convenience methods.

Build docs developers (and LLMs) love