PHP code example of xterr / php-espd

1. Go to this page and download the library: Download xterr/php-espd library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

xterr / php-espd example snippets


use Xterr\UBL\Xml\XmlDeserializer;
use Xterr\Espd\Doc\QualificationApplicationRequest;

$xml = file_get_contents('espd-request.xml');

$deserializer = new XmlDeserializer();
$request = $deserializer->deserialize($xml, QualificationApplicationRequest::class);

echo $request->getId()->getValue();                    // "ESPDREQ-..."
echo $request->getProfileExecutionID()->getValue();    // "ESPD-EDMv4.1.0"
echo count($request->getTenderingCriterions());        // 62

use Xterr\UBL\Xml\XmlSerializer;

$serializer = new XmlSerializer();
$xml = $serializer->serialize($request);

use Xterr\Espd\Validation\EspdValidator;

$validator = EspdValidator::create();
$result = $validator->validate($request);

if (!$result->isValid()) {
    foreach ($result->getFailures() as $violation) {
        echo $violation . PHP_EOL;
        // [fatal] BR-OTH-04-01: The element '/cbc:UBLVersionID' is mandatory. (at /*)
    }
}

// Filter by severity
$result->getFatals();    // Severity::Fatal only
$result->getErrors();    // Severity::Error only
$result->getWarnings();  // Severity::Warning only
$result->getFailures();  // Fatal + Error combined

use Xterr\Espd\Validation\DocumentType;

$xml = file_get_contents('espd-response.xml');
$result = $validator->validateXml($xml, DocumentType::Response);

use Xterr\Espd\Codelist\CriterionCode;
use Xterr\Espd\Codelist\CriterionElement;
use Xterr\Espd\Codelist\ResponseData;

$criterion = $request->getTenderingCriterions()[0];

// CriterionCode enum — not a raw string
$typeCode = $criterion->getCriterionTypeCode();        // CriterionCode::CRIME_ORG
echo $typeCode->value;                                  // "crime-org"

$group = $criterion->getTenderingCriterionPropertyGroups()[0];
$prop = $group->getTenderingCriterionProperties()[0];

$prop->getTypeCode();                                   // CriterionElement::QUESTION
$prop->getValueDataTypeCode();                          // ResponseData::INDICATOR

// V2 document — long-form codes resolve to V2_ prefixed enum cases
$v2Request = $deserializer->deserialize($v2Xml, QualificationApplicationRequest::class);
$code = $v2Request->getTenderingCriterions()[0]->getCriterionTypeCode();
// CriterionCode::V2_CRITERION_EXCLUSION_CONVICTIONS_CORRUPTION

$code->isLegacy();        // true — it's a v2 long-form code
$code->toV4Equivalent();  // CriterionCode::CORRUPTION — the v4 equivalent

// V3/V4 documents — short-form codes work as before
$v4Request = $deserializer->deserialize($v4Xml, QualificationApplicationRequest::class);
$code = $v4Request->getTenderingCriterions()[0]->getCriterionTypeCode();
// CriterionCode::CRIME_ORG

$code->isLegacy();        // false
$code->toV4Equivalent();  // CriterionCode::CRIME_ORG (returns self)

use Xterr\Espd\Codelist\CriterionCode;
use Xterr\Espd\Codelist\EspdPart;

$code = CriterionCode::CORRUPTION;

$code->getPart();      // EspdPart::III
$code->getPart()->label(); // "Exclusion grounds"
$code->getSection();   // "A" — Criminal convictions (Directive 2014/24/EU Art. 57(1))

// Works for all codes — v4 short-form and v2 legacy
CriterionCode::PROF_REGIST->getPart();    // EspdPart::IV (Selection criteria)
CriterionCode::PROF_REGIST->getSection(); // "A" (Suitability)

CriterionCode::SME->getPart();            // EspdPart::II (Economic operator info)
CriterionCode::SME->getSection();         // "A"

CriterionCode::STAFF_RED->getPart();      // EspdPart::V (Reduction of candidates)

// V2 codes inherit Part/Section from their v4 equivalent
CriterionCode::V2_CRITERION_EXCLUSION_CONVICTIONS_CORRUPTION->getPart();    // EspdPart::III
CriterionCode::V2_CRITERION_EXCLUSION_CONVICTIONS_CORRUPTION->getSection(); // "A"

// The property type is: BooleanGUIControl|FinancialRatio|OccupationCode|null
$expectedCode = $prop->getExpectedCode();

if ($expectedCode instanceof \Xterr\Espd\Codelist\BooleanGUIControl) {
    // e.g. BooleanGUIControl::CHECKBOX_TRUE
}

$taxonomyXml = file_get_contents('vendor/xterr/php-espd/resources/criterion/v4.1.0/ESPD-criterion.xml');
$taxonomy = $deserializer->deserialize($taxonomyXml, QualificationApplicationRequest::class);

// 62 criteria with their property groups, questions, and response types
foreach ($taxonomy->getTenderingCriterions() as $criterion) {
    echo $criterion->getCriterionTypeCode()->value . "\n";
}

use Xterr\Espd\Validation\EspdValidator;

$validator = EspdValidator::create();

// Version is auto-detected from the document's ProfileExecutionID
$result = $validator->validate($request);
$result = $validator->validateXml($xml, DocumentType::Request);

use Xterr\Espd\Validation\VersionFamily;

$result = $validator->validate($request, VersionFamily::V2);
$result = $validator->validateXml($xml, DocumentType::Response, VersionFamily::V3);

$result->isValid();      // true if no Fatal or Error violations
$result->hasWarnings();  // true if any Warning violations
$result->getFatals();    // list<Violation> — Fatal only
$result->getErrors();    // list<Violation> — Error only
$result->getFailures();  // list<Violation> — Fatal + Error
$result->getWarnings();  // list<Violation> — Warning only
$result->violations;     // list<Violation> — all violations
count($result);          // total violation count

$code = CriterionCode::V2_CRITERION_EXCLUSION_CONVICTIONS_CORRUPTION;

$code->isLegacy();        // true
$code->toV4Equivalent();  // CriterionCode::CORRUPTION
bash
composer 

src/
├── Cbc/           8 leaf value types (Amount, Code, Identifier, Text, ...)
├── Cac/         290 aggregate types (TenderingCriterion, Party, Address, ...)
├── Doc/           2 document roots
│   ├── QualificationApplicationRequest.php
│   └── QualificationApplicationResponse.php
├── Codelist/     16 codelist enums from Genericode files
├── Enum/          5 XSD-defined enums
├── Validation/    8 hand-written validation classes
│   ├── EspdValidator.php
│   ├── ValidationResult.php
│   ├── Violation.php
│   ├── Severity.php
│   ├── DocumentType.php
│   ├── SvrlParser.php
│   └── Exception/
└── Xml/           2 registries (DocumentRegistry, TypeMap)
dockerfile
FROM php:8.2-fpm

COPY --from=ghcr.io/mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/

RUN IPE_SAXON_EDITION=HE install-php-extensions saxon
bash
curl -LO https://downloads.saxonica.com/SaxonC/HE/12/SaxonCHE-macos-arm64-12-9-0.zip
unzip SaxonCHE-macos-arm64-12-9-0.zip
xattr -dr com.apple.quarantine SaxonCHE-macos-arm64-12-9-0

sudo cp -P SaxonCHE-macos-arm64-12-9-0/SaxonCHE/lib/libsaxonc-*.dylib /usr/local/lib/

cd SaxonCHE-macos-arm64-12-9-0/php/src
phpize && ./configure --with-saxon=../../SaxonCHE && make -j$(nproc) && sudo make install
sudo install_name_tool -add_rpath /usr/local/lib $(php -r "echo ini_get('extension_dir');")/saxon.so

echo "extension=saxon.so" > $(php --ini | grep "Scan for" | awk -F: '{print $2}' | xargs)/50-saxon.ini
bash
php -r "echo (new Saxon\SaxonProcessor())->version() . PHP_EOL;"
# SaxonC-HE 12.9 from Saxonica
bash
php php-espd espd:generate --force
bash
# Install dependencies
composer install

# Run tests
composer test

# Run static analysis
composer analyze

# Regenerate all classes and codelists
php php-espd espd:generate --force

# Regenerate only codelist enums (faster)
php php-espd espd:generate --force --codelists-only