cXML Response Generator
The CxmlConnectorResponseGenerator provides three methods: one for the login handshake, one for error responses, and one for the actual cart transfer.
generatePunchoutSetupResponse()
public function generatePunchoutSetupResponse(
string $cxmlString,
string $startUrl,
SalesChannelContext $context
): string
Generates the cXML response to the procurement system's PunchOutSetupRequest. It contains a StartPage URL to which the procurement system redirects the buyer's browser.
Response structure:
<cXML payloadID="..." timestamp="..." xml:lang="en-US">
<Response>
<Status code="200" text="OK"/>
<PunchOutSetupResponse>
<StartPage>
<URL>https://shop.example.com/AgiqonCxmlEntry/auth/...</URL>
</StartPage>
</PunchOutSetupResponse>
</Response>
</cXML>
generateInvalidPunchoutSetupResponse()
public function generateInvalidPunchoutSetupResponse(
SimpleXMLElement $requestXml,
int $statusCode,
string $text,
string $message
): string
Generates an error response (e.g. 400 Bad Request, 401 Unauthorized) when login fails.
generateCxmlPunchOutOrderMessage()
public function generateCxmlPunchOutOrderMessage(
ConnectorSession $session,
CxmlSystemEntity $cxmlSystem,
Cart $cart,
SalesChannelContext $context
): string
The main method for the cart transfer. It generates the full cXML PunchOutOrderMessage body.
Process
- Build the header — From and To are swapped per the cXML convention (the original
Tobecomes the responseFromand vice versa) - Insert BuyerCookie from session
additionalFields - PunchOutOrderMessageHeader with
operationAllowed,quoteStatus="final", and total price - Optionally: append shipping (when
attachShippingis enabled) - Optionally: append tax (when
attachTaxis enabled) - Iterate line items → find matching resolver for each → recursively render field tree
- Fire
CxmlResponseGenerationEvent→ XML can still be modified - Clean output (remove line breaks and whitespace between tags)
Price configuration
| System setting | Price used |
|---|---|
isTotalPriceNet() = true | Cart::getPrice()::getNetPrice() |
isTotalPriceNet() = false | Cart::getPrice()::getTotalPrice() |
The number of decimal places is controlled by the system's priceDigits setting.
Hierarchical field tree
cXML fields can be nested (parent/child relationship). The generator builds an internal field tree and renders it recursively as XML elements. The order within each level is determined by the fields' position attribute.
XML attributes
Fields can carry an XML attribute in addition to a text value:
- Standard attribute — set directly on the element
- Namespace attribute — set with the cXML namespace
http://xml.cxml.org/schemas/cXML/1.2.040/cXML.dtd
The attribute value is either resolved from a DataField or configured as a static string.
CxmlResponseGenerationEvent
Just before the XML document is serialised, the generator fires:
| Event | Event name | What can be changed? |
|---|---|---|
CxmlResponseGenerationEvent | agiqon_connector.cxml.response.generation | The complete SimpleXMLElement object |
Example:
use AgiqonConnector\Connector\System\Cxml\Event\CxmlResponseGenerationEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use SimpleXMLElement;
#[AsEventListener(event: CxmlResponseGenerationEvent::EVENT_NAME)]
final class MyCxmlResponseListener
{
public function __invoke(CxmlResponseGenerationEvent $event): void
{
$xml = $event->getCxml();
// Add custom XML elements or modify existing ones
// $event->setCxml($modifiedXml);
}
}
The event receives the fully built SimpleXMLElement. Use setCxml() to replace the entire document with a custom instance.