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.

SAT publishes three types of XML resources that CfdiUtils needs at runtime: XSD schema files for structural validation, XSLT transform files for generating the Cadena de Origen, and CER certificate files for signature verification. These resources are large (the SAT catalogue XSD alone is over 6 MB), change infrequently, and live at remote URLs. Fetching them from the internet on every operation would be slow, unreliable, and wasteful. CfdiUtils\XmlResolver\XmlResolver solves this by maintaining a local file-system cache: the first time a resource is needed it is downloaded and stored; subsequent requests use the local copy. A secondary problem is that SAT resources reference each other using absolute URLs, not relative paths. XmlResolver handles this transparently through the underlying eclipxe/xml-resource-retriever library, which rewrites embedded references to point at the local copies as it downloads each file.

How It Works

When resolve(string $resource, string $type) is called:
  1. No local path configured → the original remote URL is returned unchanged.
  2. Local path configured, file exists → the local file path is returned immediately, no network request.
  3. Local path configured, file missing → the resource is downloaded (along with its dependencies), stored under the local path, and the local file path is returned.
The resource type (XSD, XSLT, or CER) determines which retriever is used. The type is inferred automatically from the file extension when not specified explicitly.

Default Local Path

When no path is provided, XmlResolver stores resources at:
<library-install-dir>/build/resources/
When installed via Composer, this resolves to:
<composer-json-folder>/vendor/eclipxe/cfdiutils/build/resources/
You can find the computed default at runtime with:
<?php
echo \CfdiUtils\XmlResolver\XmlResolver::defaultLocalPath();

Configure the Local Path

Pass the local path to the constructor, or call setLocalPath() on an existing instance. Both accept the same three-case logic:
localPath
string|null
default:"null"
  • null — use the default path (<library>/build/resources/)
  • '' (empty string) — disable local caching entirely; all resources resolve to their remote URLs
  • any other string — use that directory as the cache root (e.g. '/tmp/sat/')
<?php
use CfdiUtils\XmlResolver\XmlResolver;

// Use the default local path (vendor/.../build/resources/)
$resolverDefault = new XmlResolver();

// Use a custom path
$resolverCustom = new XmlResolver('/var/cache/sat-resources/');

// Disable local caching — always use remote URLs
$resolverRemote = new XmlResolver('');

// Update path after construction
$resolver = new XmlResolver();
$resolver->setLocalPath('/tmp/sat/');

// Reset to default
$resolver->setLocalPath(null);

// Disable caching after construction
$resolver->setLocalPath('');
Check the current configuration with:
<?php
$resolver->getLocalPath();    // returns the configured path, or '' if disabled
$resolver->hasLocalPath();    // returns true if a local path is set

Using XmlResolver with Creators and Validators

Pass your configured XmlResolver instance to any CfdiUtils object that needs it via setXmlResolver() or its constructor.
<?php
use CfdiUtils\XmlResolver\XmlResolver;
use CfdiUtils\CfdiCreator40;
use CfdiUtils\CfdiValidator40;

$myResolver = new XmlResolver('/var/cache/sat/');

// Inject via setter
$creator = new CfdiCreator40();
$creator->setXmlResolver($myResolver);

// Inject via constructor
$validator = new CfdiValidator40($myResolver);
If you use CfdiCreator40 or CfdiCreator33 without providing a resolver, a default one is created automatically. You can retrieve and configure it in place:
<?php
$creator = new \CfdiUtils\CfdiCreator40();

// Get the auto-created resolver and configure a custom downloader
$creator->getXmlResolver()->setLocalPath('/my/resource/cache/');
If your application is deployed to multiple servers or containers, configure a shared NFS mount or a pre-warmed volume as the local path so all instances share one cache and resources are not downloaded repeatedly.

Custom Downloader

The default downloader uses PHP’s built-in file_get_contents(). If your server is behind a corporate proxy or needs special HTTP headers, implement Eclipxe\XmlResourceRetriever\Downloader\DownloaderInterface and pass your implementation to the resolver.
<?php
use Eclipxe\XmlResourceRetriever\Downloader\DownloaderInterface;
use CfdiUtils\XmlResolver\XmlResolver;

class MyProxyDownloader implements DownloaderInterface
{
    public function downloadTo(string $source, string $destination): void
    {
        // Custom download logic using curl, Guzzle, wget, etc.
    }
}

$resolver = new XmlResolver(null, new MyProxyDownloader());

// Or set the downloader after construction
$resolver->setDownloader(new MyProxyDownloader());

// Reset to the default PHP downloader
$resolver->setDownloader(null);

Invalidating the Cache

There is no TTL or expiry mechanism — the local cache is valid until you delete it. When SAT publishes updated XSD or XSLT files, delete the affected files from the cache directory and they will be re-downloaded on the next request. To refresh all SAT schema files:
# Remove all XSD files under the SAT subdirectory
find vendor/eclipxe/cfdiutils/build/resources/www.sat.gob.mx -name "*.xsd" -delete

# Or wipe the entire cache
rm -rf vendor/eclipxe/cfdiutils/build/resources/
During the download phase, network access is required. If the SAT servers are unavailable — which happens occasionally — CfdiUtils will throw an exception. The PHPCfdi project provides a pre-packaged mirror of the most common SAT resources at phpcfdi/resources-sat-xml that you can copy into your local path to avoid depending on SAT availability.

Resolving the Cadena de Origen XSLT Location

XmlResolver exposes a convenience method that looks up the correct XSLT file for a given CFDI version:
<?php
use CfdiUtils\XmlResolver\XmlResolver;
use CfdiUtils\CadenaOrigen\DOMBuilder;

$resolver = new XmlResolver();

// Resolves (and downloads if needed) the XSLT for CFDI 4.0
$xsltLocation = $resolver->resolveCadenaOrigenLocation('4.0');

$builder = new DOMBuilder();
$cadenaOrigen = $builder->build(
    file_get_contents('/facturas/invoice.xml'),
    $xsltLocation
);
Supported version strings: '3.3', '4.0'.

Build docs developers (and LLMs) love