Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
ZugferdXmpConstraint
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
1 / 1
 check
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Conformance\Constraint;
6
7use Phpdftk\Pdf\Conformance\Inspection\DocumentInspector;
8use Phpdftk\Pdf\Conformance\Profile\ConformanceProfile;
9use Phpdftk\Pdf\Conformance\Profile\ZugferdProfile;
10use Phpdftk\Pdf\Conformance\Result\ConformanceViolation;
11use Phpdftk\Pdf\Conformance\Result\ViolationSeverity;
12use Phpdftk\Xmp\XmpReader;
13
14/**
15 * ZUGFeRD / Factur-X: XMP metadata validation.
16 *
17 * Verifies that the document's XMP metadata contains the required Factur-X
18 * identification properties: fx:ConformanceLevel, fx:DocumentType,
19 * fx:DocumentFileName.
20 */
21final class ZugferdXmpConstraint implements ConformanceConstraint
22{
23    public function check(DocumentInspector $inspector, ConformanceProfile $profile): array
24    {
25        if (!$profile instanceof ZugferdProfile) {
26            return [];
27        }
28
29        $xmpBytes = $inspector->getXmpBytes();
30        if ($xmpBytes === null) {
31            return [
32                new ConformanceViolation(
33                    clause: 'A.1',
34                    message: 'Factur-X requires XMP metadata with fx: identification properties',
35                    severity: ViolationSeverity::Error,
36                    objectPath: 'Catalog.Metadata',
37                ),
38            ];
39        }
40
41        $violations = [];
42        $expectedProps = $profile->getXmpProperties();
43        $prefix = $profile->getXmpPrefix();
44
45        foreach ($expectedProps as $localName => $expectedValue) {
46            $fullKey = $prefix . ':' . $localName;
47            if (!str_contains($xmpBytes, $fullKey)) {
48                $violations[] = new ConformanceViolation(
49                    clause: 'A.1',
50                    message: sprintf(
51                        'Factur-X XMP metadata is missing required property %s (expected value: %s)',
52                        $fullKey,
53                        $expectedValue,
54                    ),
55                    severity: ViolationSeverity::Error,
56                    objectPath: 'Catalog.Metadata',
57                );
58            }
59        }
60
61        return $violations;
62    }
63}