Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.88% covered (success)
98.88%
88 / 89
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProfileConstraintRegistry
98.88% covered (success)
98.88%
88 / 89
88.89% covered (warning)
88.89%
8 / 9
21
0.00% covered (danger)
0.00%
0 / 1
 getConstraints
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
9.02
 getPdfAConstraints
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
3
 getPdfUaConstraints
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 getPdfXConstraints
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 getPdfVtConstraints
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 getPdfEConstraints
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 getPdfRConstraints
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getZugferdConstraints
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getPdfMailConstraints
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Conformance\Validator;
6
7use Phpdftk\Pdf\Conformance\Constraint\ActionConstraint;
8use Phpdftk\Pdf\Conformance\Constraint\AnnotationConstraint;
9use Phpdftk\Pdf\Conformance\Constraint\DPartRootConstraint;
10use Phpdftk\Pdf\Conformance\Constraint\ColorSpaceConstraint;
11use Phpdftk\Pdf\Conformance\Constraint\ConformanceConstraint;
12use Phpdftk\Pdf\Conformance\Constraint\DisplayDocTitleConstraint;
13use Phpdftk\Pdf\Conformance\Constraint\EmbeddedFileConstraint;
14use Phpdftk\Pdf\Conformance\Constraint\EncryptionConstraint;
15use Phpdftk\Pdf\Conformance\Constraint\FilterConstraint;
16use Phpdftk\Pdf\Conformance\Constraint\FontEmbeddingConstraint;
17use Phpdftk\Pdf\Conformance\Constraint\FormConstraint;
18use Phpdftk\Pdf\Conformance\Constraint\MetadataConstraint;
19use Phpdftk\Pdf\Conformance\Constraint\MultimediaConstraint;
20use Phpdftk\Pdf\Conformance\Constraint\OutputIntentConstraint;
21use Phpdftk\Pdf\Conformance\Constraint\PdfEActionConstraint;
22use Phpdftk\Pdf\Conformance\Constraint\PdfEColorSpaceConstraint;
23use Phpdftk\Pdf\Conformance\Constraint\PdfRActionConstraint;
24use Phpdftk\Pdf\Conformance\Constraint\PdfRFontConstraint;
25use Phpdftk\Pdf\Conformance\Constraint\RasterContentConstraint;
26use Phpdftk\Pdf\Conformance\Constraint\ReferenceXObjectConstraint;
27use Phpdftk\Pdf\Conformance\Constraint\ZugferdInvoiceConstraint;
28use Phpdftk\Pdf\Conformance\Constraint\ZugferdXmpConstraint;
29use Phpdftk\Pdf\Conformance\Constraint\TabOrderConstraint;
30use Phpdftk\Pdf\Conformance\Constraint\TaggedStructureConstraint;
31use Phpdftk\Pdf\Conformance\Constraint\ThreeDContentConstraint;
32use Phpdftk\Pdf\Conformance\Constraint\TrappedConstraint;
33use Phpdftk\Pdf\Conformance\Constraint\TransparencyConstraint;
34use Phpdftk\Pdf\Conformance\Constraint\TrimBoxConstraint;
35use Phpdftk\Pdf\Conformance\Profile\ConformanceProfile;
36use Phpdftk\Pdf\Conformance\Profile\PdfAProfile;
37use Phpdftk\Pdf\Conformance\Profile\PdfEProfile;
38use Phpdftk\Pdf\Conformance\Profile\PdfRProfile;
39use Phpdftk\Pdf\Conformance\Profile\PdfUaProfile;
40use Phpdftk\Pdf\Conformance\Profile\PdfVtProfile;
41use Phpdftk\Pdf\Conformance\Profile\PdfMailProfile;
42use Phpdftk\Pdf\Conformance\Profile\PdfXProfile;
43use Phpdftk\Pdf\Conformance\Profile\ZugferdProfile;
44
45/**
46 * Maps each conformance profile to its set of applicable constraints.
47 */
48final class ProfileConstraintRegistry
49{
50    /**
51     * Get the constraints applicable to the given profile.
52     *
53     * @return list<ConformanceConstraint>
54     */
55    public function getConstraints(ConformanceProfile $profile): array
56    {
57        if ($profile instanceof PdfAProfile) {
58            return $this->getPdfAConstraints($profile);
59        }
60
61        if ($profile instanceof PdfUaProfile) {
62            return $this->getPdfUaConstraints($profile);
63        }
64
65        if ($profile instanceof PdfXProfile) {
66            return $this->getPdfXConstraints($profile);
67        }
68
69        if ($profile instanceof PdfVtProfile) {
70            return $this->getPdfVtConstraints($profile);
71        }
72
73        if ($profile instanceof PdfEProfile) {
74            return $this->getPdfEConstraints();
75        }
76
77        if ($profile instanceof PdfRProfile) {
78            return $this->getPdfRConstraints();
79        }
80
81        if ($profile instanceof ZugferdProfile) {
82            return $this->getZugferdConstraints($profile);
83        }
84
85        if ($profile instanceof PdfMailProfile) {
86            return $this->getPdfMailConstraints();
87        }
88
89        return [];
90    }
91
92    /** @return list<ConformanceConstraint> */
93    private function getPdfAConstraints(PdfAProfile $profile): array
94    {
95        // Core constraints shared by all PDF/A levels
96        $constraints = [
97            new FontEmbeddingConstraint(),
98            new EncryptionConstraint(),
99            new MetadataConstraint(),
100            new OutputIntentConstraint(),
101            new ColorSpaceConstraint(),
102            new ActionConstraint(),
103            new EmbeddedFileConstraint(),
104        ];
105
106        // PDF/A-1 only: no transparency, no LZWDecode
107        if ($profile->getPart() === 1) {
108            $constraints[] = new TransparencyConstraint();
109            $constraints[] = new FilterConstraint();
110        }
111
112        // Level A requires tagged structure
113        if ($profile->requiresTaggedStructure()) {
114            $constraints[] = new TaggedStructureConstraint();
115        }
116
117        return $constraints;
118    }
119
120    /** @return list<ConformanceConstraint> */
121    private function getPdfUaConstraints(PdfUaProfile $profile): array
122    {
123        return [
124            new TaggedStructureConstraint(),
125            new MetadataConstraint(),
126            new FontEmbeddingConstraint(),
127            new DisplayDocTitleConstraint(),
128            new TabOrderConstraint(),
129            new AnnotationConstraint(),
130        ];
131    }
132
133    /** @return list<ConformanceConstraint> */
134    private function getPdfXConstraints(PdfXProfile $profile): array
135    {
136        $constraints = [
137            new OutputIntentConstraint(),
138            new MetadataConstraint(),
139            new EncryptionConstraint(),
140            new FontEmbeddingConstraint(),
141            new TrimBoxConstraint(),
142            new TrappedConstraint(),
143        ];
144
145        // PDF/X-1a and X-3 prohibit transparency; X-4+ allows it
146        if ($profile->prohibitsTransparency()) {
147            $constraints[] = new TransparencyConstraint();
148        }
149
150        // PDF/X-5 profiles validate reference XObjects
151        if ($profile->supportsReferenceXObjects()) {
152            $constraints[] = new ReferenceXObjectConstraint();
153        }
154
155        return $constraints;
156    }
157
158    /**
159     * PDF/VT builds on PDF/X-4 and adds DPartRoot requirement.
160     *
161     * @return list<ConformanceConstraint>
162     */
163    private function getPdfVtConstraints(PdfVtProfile $profile): array
164    {
165        return [
166            new OutputIntentConstraint(),
167            new MetadataConstraint(),
168            new EncryptionConstraint(),
169            new FontEmbeddingConstraint(),
170            new TrimBoxConstraint(),
171            new TrappedConstraint(),
172            new DPartRootConstraint(),
173        ];
174    }
175
176    /**
177     * PDF/E-1: embedded fonts, XMP metadata, no encryption,
178     * 3D content validation, action restrictions, color space anchoring.
179     *
180     * @return list<ConformanceConstraint>
181     */
182    private function getPdfEConstraints(): array
183    {
184        return [
185            new FontEmbeddingConstraint(),
186            new MetadataConstraint(),
187            new EncryptionConstraint(),
188            new ThreeDContentConstraint(),
189            new PdfEActionConstraint(),
190            new PdfEColorSpaceConstraint(),
191        ];
192    }
193
194    /**
195     * PDF/R-1: XMP metadata, no encryption, raster-only content,
196     * action restrictions, font presence warning.
197     *
198     * @return list<ConformanceConstraint>
199     */
200    private function getPdfRConstraints(): array
201    {
202        return [
203            new MetadataConstraint(),
204            new EncryptionConstraint(),
205            new RasterContentConstraint(),
206            new PdfRActionConstraint(),
207            new PdfRFontConstraint(),
208        ];
209    }
210
211    /**
212     * ZUGFeRD / Factur-X: PDF/A-3b base constraints plus invoice-specific
213     * XMP and embedded file validation.
214     *
215     * @return list<ConformanceConstraint>
216     */
217    private function getZugferdConstraints(ZugferdProfile $profile): array
218    {
219        // Start with all PDF/A-3b constraints
220        $constraints = $this->getPdfAConstraints($profile->getBaseProfile());
221
222        // Add ZUGFeRD-specific constraints
223        $constraints[] = new ZugferdXmpConstraint();
224        $constraints[] = new ZugferdInvoiceConstraint();
225
226        return $constraints;
227    }
228
229    /**
230     * PDF/mail-1: no encryption, no JavaScript, fonts embedded,
231     * no interactive forms, no multimedia.
232     *
233     * @return list<ConformanceConstraint>
234     */
235    private function getPdfMailConstraints(): array
236    {
237        return [
238            new EncryptionConstraint(),
239            new MetadataConstraint(),
240            new FontEmbeddingConstraint(),
241            new ActionConstraint(),
242            new FormConstraint(),
243            new MultimediaConstraint(),
244        ];
245    }
246}