Skip to content

Commit 991a618

Browse files
committed
feat(pdfengines): add embed metadata
1 parent 8084147 commit 991a618

8 files changed

Lines changed: 297 additions & 5 deletions

File tree

src/EmbedMetadata.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gotenberg;
6+
7+
use JsonSerializable;
8+
9+
class EmbedMetadata implements JsonSerializable
10+
{
11+
public const FIELD_MIME_TYPE = 'mimeType';
12+
public const FIELD_RELATIONSHIP = 'relationship';
13+
14+
public const RELATIONSHIP_SOURCE = 'Source';
15+
public const RELATIONSHIP_DATA = 'Data';
16+
public const RELATIONSHIP_ALTERNATIVE = 'Alternative';
17+
public const RELATIONSHIP_SUPPLEMENT = 'Supplement';
18+
public const RELATIONSHIP_UNSPECIFIED = 'Unspecified';
19+
20+
public function __construct(
21+
public readonly string $filename,
22+
public readonly string|null $mimeType = null,
23+
public readonly string|null $relationship = null,
24+
) {
25+
}
26+
27+
/** @return array<string,string> */
28+
public function jsonSerialize(): array
29+
{
30+
$serialized = [];
31+
32+
if ($this->mimeType !== null) {
33+
$serialized[self::FIELD_MIME_TYPE] = $this->mimeType;
34+
}
35+
36+
if ($this->relationship !== null) {
37+
$serialized[self::FIELD_RELATIONSHIP] = $this->relationship;
38+
}
39+
40+
return $serialized;
41+
}
42+
}

src/Modules/ChromiumPdf.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Gotenberg\Modules;
66

7+
use Gotenberg\EmbedMetadata;
78
use Gotenberg\Exceptions\NativeFunctionErrored;
89
use Gotenberg\SplitMode;
910
use Gotenberg\Stream;
@@ -248,6 +249,29 @@ public function embeds(Stream ...$embeds): self
248249
return $this;
249250
}
250251

252+
/**
253+
* Sets metadata on embedded files in the resulting PDF, required for
254+
* Factur-X / ZUGFeRD compliance.
255+
*
256+
* @throws NativeFunctionErrored
257+
*/
258+
public function embedsMetadata(EmbedMetadata ...$metadata): self
259+
{
260+
$map = [];
261+
foreach ($metadata as $entry) {
262+
$map[$entry->filename] = $entry;
263+
}
264+
265+
$json = json_encode($map);
266+
if ($json === false) {
267+
throw NativeFunctionErrored::createFromLastPhpError();
268+
}
269+
270+
$this->formValue('embedsMetadata', $json);
271+
272+
return $this;
273+
}
274+
251275
/**
252276
* Converts a target URL to PDF.
253277
*

src/Modules/LibreOffice.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Gotenberg\Modules;
66

7+
use Gotenberg\EmbedMetadata;
78
use Gotenberg\Exceptions\NativeFunctionErrored;
89
use Gotenberg\HrtimeIndex;
910
use Gotenberg\Index;
@@ -601,6 +602,29 @@ public function embeds(Stream ...$embeds): self
601602
return $this;
602603
}
603604

605+
/**
606+
* Sets metadata on embedded files in the resulting PDF, required for
607+
* Factur-X / ZUGFeRD compliance.
608+
*
609+
* @throws NativeFunctionErrored
610+
*/
611+
public function embedsMetadata(EmbedMetadata ...$metadata): self
612+
{
613+
$map = [];
614+
foreach ($metadata as $entry) {
615+
$map[$entry->filename] = $entry;
616+
}
617+
618+
$json = json_encode($map);
619+
if ($json === false) {
620+
throw NativeFunctionErrored::createFromLastPhpError();
621+
}
622+
623+
$this->formValue('embedsMetadata', $json);
624+
625+
return $this;
626+
}
627+
604628
/**
605629
* Converts the given document(s) to PDF(s). Gotenberg will return either
606630
* a unique PDF if you request a merge or a ZIP archive with the PDFs.

src/Modules/PdfEngines.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Gotenberg\Modules;
66

7+
use Gotenberg\EmbedMetadata;
78
use Gotenberg\Exceptions\NativeFunctionErrored;
89
use Gotenberg\HrtimeIndex;
910
use Gotenberg\Index;
@@ -105,6 +106,29 @@ public function embeds(Stream ...$embeds): self
105106
return $this;
106107
}
107108

109+
/**
110+
* Sets metadata on embedded files in the resulting PDF, required for
111+
* Factur-X / ZUGFeRD compliance.
112+
*
113+
* @throws NativeFunctionErrored
114+
*/
115+
public function embedsMetadata(EmbedMetadata ...$metadata): self
116+
{
117+
$map = [];
118+
foreach ($metadata as $entry) {
119+
$map[$entry->filename] = $entry;
120+
}
121+
122+
$json = json_encode($map);
123+
if ($json === false) {
124+
throw NativeFunctionErrored::createFromLastPhpError();
125+
}
126+
127+
$this->formValue('embedsMetadata', $json);
128+
129+
return $this;
130+
}
131+
108132
/**
109133
* Merges PDFs into a unique PDF.
110134
*

tests/EmbedMetadataTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gotenberg\Test;
6+
7+
use Gotenberg\EmbedMetadata;
8+
use PHPUnit\Framework\Attributes\Test;
9+
10+
use function json_encode;
11+
12+
final class EmbedMetadataTest extends TestCase
13+
{
14+
#[Test]
15+
public function it_serializes_all_fields(): void
16+
{
17+
$metadata = new EmbedMetadata(
18+
'embed_1.xml',
19+
'text/xml',
20+
EmbedMetadata::RELATIONSHIP_DATA,
21+
);
22+
23+
$this->assertSame(
24+
'{"mimeType":"text\/xml","relationship":"Data"}',
25+
json_encode($metadata),
26+
);
27+
}
28+
29+
#[Test]
30+
public function it_serializes_only_mime_type(): void
31+
{
32+
$metadata = new EmbedMetadata('embed_1.xml', 'text/xml');
33+
34+
$this->assertSame('{"mimeType":"text\/xml"}', json_encode($metadata));
35+
}
36+
37+
#[Test]
38+
public function it_serializes_only_relationship(): void
39+
{
40+
$metadata = new EmbedMetadata(
41+
'embed_1.xml',
42+
null,
43+
EmbedMetadata::RELATIONSHIP_ALTERNATIVE,
44+
);
45+
46+
$this->assertSame('{"relationship":"Alternative"}', json_encode($metadata));
47+
}
48+
49+
#[Test]
50+
public function it_serializes_to_empty_when_no_optional_fields(): void
51+
{
52+
$metadata = new EmbedMetadata('embed_1.xml');
53+
54+
$this->assertSame('[]', json_encode($metadata));
55+
}
56+
57+
#[Test]
58+
public function it_exposes_filename_as_a_public_property(): void
59+
{
60+
$metadata = new EmbedMetadata('embed_1.xml', 'text/xml');
61+
62+
$this->assertSame('embed_1.xml', $metadata->filename);
63+
}
64+
}

0 commit comments

Comments
 (0)