Skip to content

Commit 3ed9af8

Browse files
authored
Merge pull request #501 from KnpLabs/proto/v2-dompdf
2 parents 9f6a146 + b0194ce commit 3ed9af8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1496
-468
lines changed

.github/workflows/tests.yaml

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Tests
2+
3+
on:
4+
pull_request: ~
5+
push: ~
6+
7+
jobs:
8+
packages:
9+
runs-on: ubuntu-20.04
10+
outputs:
11+
packages: ${{ steps.script.outputs.result }}
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/github-script@v7
15+
id: script
16+
with:
17+
script: |
18+
const fs = require('fs');
19+
20+
const composer = JSON.parse(
21+
fs.readFileSync('./composer.json')
22+
);
23+
24+
const packages = Object.keys(composer.autoload['psr-4']).map(
25+
(namespace) => {
26+
const path = composer.autoload['psr-4'][namespace];
27+
const name = JSON.parse(fs.readFileSync(path + 'composer.json')).name;
28+
29+
return {
30+
name: name,
31+
path: './' + path,
32+
};
33+
}
34+
);
35+
36+
console.log(packages);
37+
38+
return packages;
39+
40+
package:
41+
runs-on: ubuntu-20.04
42+
needs: packages
43+
strategy:
44+
matrix:
45+
name:
46+
- knplabs/snappy
47+
path:
48+
- ./
49+
# include: ${{ fromJson(needs.packages.outputs.packages) }}
50+
defaults:
51+
run:
52+
working-directory: ${{ matrix.path }}
53+
steps:
54+
- uses: actions/checkout@v4
55+
with:
56+
sparse-checkout: |
57+
src/Core/
58+
${{ matrix.path }}
59+
- uses: shivammathur/setup-php@v2
60+
- name: composer install
61+
run: |
62+
composer install
63+
- name: vendor/bin/phpunit
64+
run: |
65+
vendor/bin/phpunit

.phpunit.result.cache

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":1,"defects":{"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testLoadEmptyConfiguration":8,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testConfigure":5,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testConfigureTmpDirectory":7,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testDompdfBackendConfiguration":8,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileIsAutomaticalyRemoved":8},"times":{"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testLoadEmptyConfiguration":0.008,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testConfigure":0,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testConfigureTmpDirectory":0,"KNPLabs\\Snappy\\Framework\\Symfony\\Tests\\DependencyInjection\\SnappyExtensionTest::testDompdfBackendConfiguration":0.015,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStream":0.005,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStreamCreateTemporaryFile":0.003,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStreamReadTheFile":0.004,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileIsAutomaticalyRemoved":0.003}}

bin/sync-composer.php

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
$global = json_decode(
4+
(string) file_get_contents(__DIR__ . '/../composer.json'),
5+
true,
6+
flags: JSON_THROW_ON_ERROR,
7+
);
8+
9+
$dependencies = [
10+
...$global['require'],
11+
...$global['require-dev'],
12+
];
13+
14+
$replace = $global['replace'];
15+
16+
foreach($global['autoload']['psr-4'] as $path) {
17+
$content = file_get_contents($path . '/composer.json');
18+
19+
if (false === $content) {
20+
throw new \Exception("File $path/composer.json not found.");
21+
}
22+
23+
$json = json_decode(
24+
$content,
25+
true,
26+
flags: JSON_THROW_ON_ERROR,
27+
);
28+
29+
foreach (['require', 'require-dev'] as $part) {
30+
foreach ($json[$part] ?? [] as $name => $constraint) {
31+
if (isset($replace[$name])) {
32+
continue;
33+
}
34+
35+
if (false === isset($dependencies[$name])) {
36+
throw new \Exception(
37+
sprintf(
38+
'Dependency "%s" not found in %s/composer.json.',
39+
$name,
40+
__DIR__,
41+
)
42+
);
43+
}
44+
45+
$json[$part][$name] = $dependencies[$name];
46+
}
47+
}
48+
49+
$content = file_put_contents(
50+
$path . '/composer.json',
51+
json_encode(
52+
$json,
53+
flags: JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR|JSON_UNESCAPED_SLASHES,
54+
),
55+
);
56+
}

composer.json

+42-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
{
22
"name": "knplabs/knp-snappy",
3-
"type": "library",
43
"description": "PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.",
5-
"keywords": ["pdf", "thumbnail", "snapshot", "knplabs", "knp", "wkhtmltopdf"],
6-
"homepage": "http://github.com/KnpLabs/snappy",
74
"license": "MIT",
5+
"type": "library",
6+
"keywords": [
7+
"pdf",
8+
"thumbnail",
9+
"snapshot",
10+
"knplabs",
11+
"knp",
12+
"wkhtmltopdf"
13+
],
814
"authors": [
915
{
1016
"name": "KNP Labs Team",
@@ -15,18 +21,46 @@
1521
"homepage": "http://github.com/KnpLabs/snappy/contributors"
1622
}
1723
],
24+
"homepage": "http://github.com/KnpLabs/snappy",
1825
"require": {
1926
"php": ">=8.1",
20-
"symfony/process": "~5.0||~6.0",
21-
"psr/log": "^2.0||^3.0",
22-
"symfony/http-client": "^6.2",
23-
"psr/http-message": "^2.0"
27+
"dompdf/dompdf": "^3.0",
28+
"psr/http-factory": "^1.1",
29+
"psr/http-message": "^2.0",
30+
"psr/log": "^2.0|^3.0",
31+
"symfony/config": "^5.4|^6.4|^7.1",
32+
"symfony/dependency-injection": "^5.4|^6.4|^7.1",
33+
"symfony/http-client": "^5.4|^6.4|^7.1",
34+
"symfony/http-kernel": "^5.4|^6.4|^7.1",
35+
"symfony/process": "^5.4|^6.4|^7.1"
36+
},
37+
"require-dev": {
38+
"nyholm/psr7": "^1.8",
39+
"phpstan/extension-installer": "^1.4",
40+
"phpstan/phpstan": "^1.12",
41+
"phpstan/phpstan-phpunit": "^1.4",
42+
"phpunit/phpunit": "^11.4"
43+
},
44+
"replace": {
45+
"knplabs/snappy-bundle": "self.version",
46+
"knplabs/snappy-core": "self.version",
47+
"knplabs/snappy-dompdf": "self.version",
48+
"knplabs/snappy-wkhtmltopdf": "self.version"
2449
},
2550
"autoload": {
2651
"psr-4": {
27-
"KnpLabs\\Snappy\\": "src/"
52+
"KNPLabs\\Snappy\\Backend\\Dompdf\\": "src/Backend/Dompdf/",
53+
"KNPLabs\\Snappy\\Backend\\WkHtmlToPdf\\": "src/Backend/WkHtmlToPdf/",
54+
"KNPLabs\\Snappy\\Core\\": "src/Core/",
55+
"KNPLabs\\Snappy\\Framework\\Symfony\\": "src/Framework/Symfony/"
2856
}
2957
},
58+
"config": {
59+
"allow-plugins": {
60+
"phpstan/extension-installer": true
61+
},
62+
"sort-packages": true
63+
},
3064
"extra": {
3165
"branch-alias": {
3266
"dev-master": "2.x-dev"

phpstan.neon.dist

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
parameters:
2+
level: max
3+
paths:
4+
- src

phpunit.xml.dist

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/9.3/phpunit.xsd"
5+
backupGlobals="false"
6+
colors="true"
7+
bootstrap="vendor/autoload.php"
8+
failOnRisky="true"
9+
failOnWarning="true"
10+
>
11+
<php>
12+
<ini name="error_reporting" value="-1" />
13+
</php>
14+
15+
<testsuites>
16+
<testsuite name="Snappy Dompdf backend">
17+
<directory>./src/Backend/Dompdf</directory>
18+
</testsuite>
19+
<testsuite name="Snappy WkHtmlToPdf backend">
20+
<directory>./src/Backend/WkHtmlToPdf</directory>
21+
</testsuite>
22+
<testsuite name="Snappy core">
23+
<directory>./src/Core/</directory>
24+
</testsuite>
25+
<testsuite name="Snappy Symfony framework integration">
26+
<directory>./src/Framework/Symfony/</directory>
27+
</testsuite>
28+
</testsuites>
29+
</phpunit>

src/Backend/Dompdf/DompdfAdapter.php

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KNPLabs\Snappy\Backend\Dompdf;
6+
7+
use ArrayAccess;
8+
use DOMDocument;
9+
use Dompdf;
10+
use KNPLabs\Snappy\Core\Backend\Adapter\DOMDocumentToPdf;
11+
use KNPLabs\Snappy\Core\Backend\Adapter\HtmlFileToPdf;
12+
use KNPLabs\Snappy\Core\Backend\Adapter\HtmlToPdf;
13+
use KNPLabs\Snappy\Core\Backend\Adapter\Reconfigurable;
14+
use KNPLabs\Snappy\Core\Backend\Options;
15+
use Psr\Http\Message\StreamFactoryInterface;
16+
use Psr\Http\Message\StreamInterface;
17+
use SplFileInfo;
18+
19+
final readonly class DompdfAdapter implements DOMDocumentToPdf, HtmlFileToPdf, HtmlToPdf
20+
{
21+
/**
22+
* @use Reconfigurable<self>
23+
*/
24+
use Reconfigurable;
25+
26+
public function __construct(
27+
DompdfFactory $factory,
28+
Options $options,
29+
private readonly StreamFactoryInterface $streamFactory
30+
) {
31+
$this->factory = $factory;
32+
$this->options = $options;
33+
}
34+
35+
public function generateFromDOMDocument(DOMDocument $DOMDocument): StreamInterface
36+
{
37+
$dompdf = $this->buildDompdf();
38+
$dompdf->loadDOM($DOMDocument);
39+
40+
return $this->createStream($dompdf);
41+
}
42+
43+
public function generateFromHtmlFile(SplFileInfo $file): StreamInterface
44+
{
45+
$dompdf = $this->buildDompdf();
46+
$dompdf->loadHtmlFile($file->getPath());
47+
48+
return $this->createStream($dompdf);
49+
}
50+
51+
public function generateFromHtml(string $html): StreamInterface
52+
{
53+
$dompdf = $this->buildDompdf();
54+
$dompdf->loadHtml($html);
55+
56+
return $this->createStream($dompdf);
57+
}
58+
59+
private function buildDompdf(): Dompdf\Dompdf
60+
{
61+
return new Dompdf\Dompdf( $this->compileConstructOptions());
62+
}
63+
64+
private function compileConstructOptions(): Dompdf\Options
65+
{
66+
$options = new Dompdf\Options(
67+
is_array($this->options->extraOptions['construct'])
68+
? $this->options->extraOptions['construct']
69+
: null
70+
);
71+
72+
if (null !== $this->options->pageOrientation) {
73+
$options->setDefaultPaperOrientation(
74+
$this->options->pageOrientation->value
75+
);
76+
}
77+
78+
return $options;
79+
}
80+
81+
/**
82+
* @return array<mixed, mixed>
83+
*/
84+
private function compileOutputOptions(): array
85+
{
86+
$options = $this->options->extraOptions['output'];
87+
88+
if (false === is_array($options)) {
89+
$options = [];
90+
}
91+
92+
return $options;
93+
}
94+
95+
private function createStream(Dompdf\Dompdf $dompdf): StreamInterface
96+
{
97+
$output = $dompdf->output($this->compileOutputOptions());
98+
99+
return $this
100+
->streamFactory
101+
->createStream($output ?: '')
102+
;
103+
}
104+
}

src/Backend/Dompdf/DompdfFactory.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace KNPLabs\Snappy\Backend\Dompdf;
6+
7+
use KNPLabs\Snappy\Core\Backend\Adapter;
8+
use KNPLabs\Snappy\Core\Backend\Factory;
9+
use KNPLabs\Snappy\Core\Backend\Option;
10+
use KNPLabs\Snappy\Core\Backend\Options;
11+
use Psr\Http\Message\StreamFactoryInterface;
12+
13+
/**
14+
* @implements Factory<DompdfAdapter>
15+
*/
16+
final readonly class DompdfFactory implements Factory
17+
{
18+
public function __construct(private readonly StreamFactoryInterface $streamFactory)
19+
{
20+
}
21+
22+
public function create(Options $options): DompdfAdapter
23+
{
24+
return new DompdfAdapter(
25+
factory: $this,
26+
options: $options,
27+
streamFactory: $this->streamFactory,
28+
);
29+
}
30+
}

0 commit comments

Comments
 (0)