Estructura de datos Elements
El espacio de nombres CfdiUtils\Elements
es una especialización de CfdiUtils\Nodes
.
Se trata solo de una estructura de datos, no caigas en la tentación de insertar lógica más allá de la propia estructura.
Todo elemento es un nodo, entonces todos los métodos y propiedades de NodeInterface
están presentes.
Entonces, para escribir atributos se recomienda usar la forma de arreglo, por ejemplo:
$comprobante['Descuento'] = '1234.56'
para establecer el atributo "Descuento" a "1234.56".
Cualquier elemento debe cumplir con la interfaz CfdiUtils\Elements\Common\ElementInterface
que es una extensión de CfdiUtils\Nodes\NodeInterface
y agrega:
getElementName(): string
: Devuelve el nombre del elemento, comocfdi:Complemento
getFixedAttributes(): array
: Establece la lista de nodos predefinidos al crearse (útil para Complementos y Comprobante)getChildrenOrder(): array
: establece el orden de los nodos hijos
En última instancia, un elemento (ElementInterface
) es un nodo (NodeInterface
)
por lo que puedes utilizar a bajo nivel todo el poder de los nodos para trabajar con esta estructura de datos.
Nomenclatura genérica
Los elementos deberían seguir esta nomenclatura genérica para nombrar sus métodos.
Prefijo get*
La nomenclatura con el prefijo get*
se escribe en la forma ElementoPadre::getElementoHijo(): ElementoHijo
y se espera devolver una única instancia de ElementoHijo
. Si la instancia no existe entonces se crea.
Prefijo add*
La nomenclatura con el prefijo add*
se escribe la forma ElementoPadre::addElementoHijo($attributes): ElementoHijo
y se espera crear una instancia de ElementoHijo
con los atributos datos, agregarla a los hijos de ElementoPadre
y la instancia de ElementoHijo
creada.
Cuando se utiliza add*
hay dos comportamientos esperados:
- Si solo debe haber un hijo de un determinado tipo, entonces no se crea uno nuevo y se ocupa el existente.
- Si puede haber más de un hijo de un determinado tipo, entonces se crea uno nuevo y se agrega a los hijos.
Por eso, como solo debe haber un nodo emisor dentro de un comprobante,
entonces Comprobante::addEmisor(['RegimenFiscal' => '601'])
tiene este comportamiento:
- Se obtiene el elemento
Emisor
, si no existe se crea uno vacío. - Se escriben los atributos pasados al elemento obtenido.
- Se devuelve el elemento creado
Emisor
.
Por el contrario, como puede haber varios conceptos, entonces
Conceptos::addConcepto([/* attributes */])
tiene este comportamiento:
- Se crea un elemento de tipo
Concepto
con los atributos pasados. - Se agrega el elemento recién creado a los hijos de
Conceptos
. - Se devuelve el elemento creado
Concepto
.
Existe algunos casos donde, lo que se espera entregar como argumento al prefijo add*
, es en realidad un hijo.
Esto sucede en addComplemento
y addAddenda
.
Prefijo multi*
La nomenclatura con el prefijo multi*
se escribe la forma ElementoPadre::multiElementoHijo(...$attributes): ElementoPadre
y se espera crear múltiples una instancia de ElementoHijo
con los atributos datos, agregarla a los hijos de ElementoPadre
y la instancia de ElementoPadre
creada.
Otra forma de decirlo: es como los métodos add*
pero se le pueden mandar varios arreglos de atributos y
se creará un elemento para cada parámetro enviado.
Por lo anterior, CfdiRelacionados::multiCfdiRelacionado([ ['UUID' => $uuid1], ['UUID' => $uuid2] ])
agregará dos hijos
y devolverá la misma instancia del objeto CfdiRelacionados
llamado.