Skip to content

Commit

Permalink
feat: full prototype with dompdf integration
Browse files Browse the repository at this point in the history
  • Loading branch information
PedroTroller committed Oct 14, 2024
1 parent 9f6a146 commit a47421c
Show file tree
Hide file tree
Showing 49 changed files with 1,502 additions and 467 deletions.
77 changes: 77 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Tests

on:
pull_request: ~
push: ~

jobs:
packages:
runs-on: ubuntu-20.04
outputs:
packages: ${{ steps.script.outputs.result }}
steps:
- uses: actions/checkout@v4
- uses: actions/github-script@v7
id: script
with:
script: |
const fs = require('fs');
const composer = JSON.parse(
fs.readFileSync('./composer.json')
);
const packages = Object.keys(composer.autoload['psr-4']).map(
(namespace) => {
const path = composer.autoload['psr-4'][namespace];
const name = JSON.parse(fs.readFileSync(path + 'composer.json')).name;
return {
name: name,
path: './' + path,
};
}
);
packages.push({name: "knplabs/snappy", path: './'})
console.log(packages);
return packages;
package:
runs-on: ubuntu-20.04
needs: packages
strategy:
matrix:
includes: ${{ needs.packages.outputs.packages }}
steps:
- uses: actions/checkout@v4
- uses: actions/github-script@v7
id: packages
with:
script: |
const fs = require('fs');
const composer = JSON.parse(
fs.readFileSync('./composer.json')
);
const packages = Object.keys(composer.autoload['psr-4']).map(
(namespace) => {
const path = composer.autoload['psr-4'][namespace];
const name = JSON.parse(fs.readFileSync(path + 'composer.json')).name;
return {
name: name,
path: './' + path,
};
}
);
packages.push({name: "knplabs/snappy", path: './'})
console.log(packages);
return packages;
1 change: 1 addition & 0 deletions .phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -0,0 +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.003,"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.001,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStream":0.005,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStreamCreateTemporaryFile":0,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileStreamReadTheFile":0,"KNPLabs\\Snappy\\Core\\Tests\\Stream\\FileStreamTest::testTmpFileIsAutomaticalyRemoved":0}}
56 changes: 56 additions & 0 deletions bin/sync-composer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

$global = json_decode(
(string) file_get_contents(__DIR__ . '/../composer.json'),
true,
flags: JSON_THROW_ON_ERROR,
);

$dependencies = [
...$global['require'],
...$global['require-dev'],
];

$replace = $global['replace'];

foreach($global['autoload']['psr-4'] as $path) {
$content = file_get_contents($path . '/composer.json');

if (false === $content) {
throw new \Exception("File $path/composer.json not found.");
}

$json = json_decode(
$content,
true,
flags: JSON_THROW_ON_ERROR,
);

foreach (['require', 'require-dev'] as $part) {
foreach ($json[$part] ?? [] as $name => $constraint) {
if (isset($replace[$name])) {
continue;
}

if (false === isset($dependencies[$name])) {
throw new \Exception(
sprintf(
'Dependency "%s" not found in %s/composer.json.',
$name,
__DIR__,
)
);
}

$json[$part][$name] = $dependencies[$name];
}
}

$content = file_put_contents(
$path . '/composer.json',
json_encode(
$json,
flags: JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR|JSON_UNESCAPED_SLASHES,
),
);
}
50 changes: 42 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
{
"name": "knplabs/knp-snappy",
"type": "library",
"description": "PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.",
"keywords": ["pdf", "thumbnail", "snapshot", "knplabs", "knp", "wkhtmltopdf"],
"homepage": "http://github.com/KnpLabs/snappy",
"license": "MIT",
"type": "library",
"keywords": [
"pdf",
"thumbnail",
"snapshot",
"knplabs",
"knp",
"wkhtmltopdf"
],
"authors": [
{
"name": "KNP Labs Team",
Expand All @@ -15,18 +21,46 @@
"homepage": "http://github.com/KnpLabs/snappy/contributors"
}
],
"homepage": "http://github.com/KnpLabs/snappy",
"require": {
"php": ">=8.1",
"symfony/process": "~5.0||~6.0",
"psr/log": "^2.0||^3.0",
"symfony/http-client": "^6.2",
"psr/http-message": "^2.0"
"dompdf/dompdf": "^3.0",
"psr/http-factory": "^1.1",
"psr/http-message": "^2.0",
"psr/log": "^2.0|^3.0",
"symfony/config": "^5.4|^6.4|^7.1",
"symfony/dependency-injection": "^5.4|^6.4|^7.1",
"symfony/http-client": "^5.4|^6.4|^7.1",
"symfony/http-kernel": "^5.4|^6.4|^7.1",
"symfony/process": "^5.4|^6.4|^7.1"
},
"require-dev": {
"nyholm/psr7": "^1.8",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^1.12",
"phpstan/phpstan-phpunit": "^1.4",
"phpunit/phpunit": "^11.4"
},
"replace": {
"knplabs/snappy-bundle": "self.version",
"knplabs/snappy-core": "self.version",
"knplabs/snappy-dompdf": "self.version",
"knplabs/snappy-wkhtmltopdf": "self.version"
},
"autoload": {
"psr-4": {
"KnpLabs\\Snappy\\": "src/"
"KNPLabs\\Snappy\\Backend\\Dompdf\\": "src/Backend/Dompdf/",
"KNPLabs\\Snappy\\Backend\\WkHtmlToPdf\\": "src/Backend/WkHtmlToPdf/",
"KNPLabs\\Snappy\\Core\\": "src/Core/",
"KNPLabs\\Snappy\\Framework\\Symfony\\": "src/Framework/Symfony/"
}
},
"config": {
"allow-plugins": {
"phpstan/extension-installer": true
},
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
Expand Down
4 changes: 4 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parameters:
level: max
paths:
- src
29 changes: 29 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>

<testsuites>
<testsuite name="Snappy Dompdf backend">
<directory>./src/Backend/Dompdf</directory>
</testsuite>
<testsuite name="Snappy WkHtmlToPdf backend">
<directory>./src/Backend/WkHtmlToPdf</directory>
</testsuite>
<testsuite name="Snappy core">
<directory>./src/Core/</directory>
</testsuite>
<testsuite name="Snappy Symfony framework integration">
<directory>./src/Framework/Symfony/</directory>
</testsuite>
</testsuites>
</phpunit>
104 changes: 104 additions & 0 deletions src/Backend/Dompdf/DompdfAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

declare(strict_types=1);

namespace KNPLabs\Snappy\Backend\Dompdf;

use ArrayAccess;
use DOMDocument;
use Dompdf;
use KNPLabs\Snappy\Core\Backend\Adapter\DOMDocumentToPdf;
use KNPLabs\Snappy\Core\Backend\Adapter\HtmlFileToPdf;
use KNPLabs\Snappy\Core\Backend\Adapter\HtmlToPdf;
use KNPLabs\Snappy\Core\Backend\Adapter\Reconfigurable;
use KNPLabs\Snappy\Core\Backend\Options;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;
use SplFileInfo;

final readonly class DompdfAdapter implements DOMDocumentToPdf, HtmlFileToPdf, HtmlToPdf
{
/**
* @use Reconfigurable<self>
*/
use Reconfigurable;

public function __construct(
DompdfFactory $factory,
Options $options,
private readonly StreamFactoryInterface $streamFactory
) {
$this->factory = $factory;
$this->options = $options;
}

public function generateFromDOMDocument(DOMDocument $DOMDocument): StreamInterface
{
$dompdf = $this->buildDompdf();
$dompdf->loadDOM($DOMDocument);

return $this->createStream($dompdf);
}

public function generateFromHtmlFile(SplFileInfo $file): StreamInterface
{
$dompdf = $this->buildDompdf();
$dompdf->loadHtmlFile($file->getPath());

return $this->createStream($dompdf);
}

public function generateFromHtml(string $html): StreamInterface
{
$dompdf = $this->buildDompdf();
$dompdf->loadHtml($html);

return $this->createStream($dompdf);
}

private function buildDompdf(): Dompdf\Dompdf
{
return new Dompdf\Dompdf( $this->compileInitOptions());
}

private function compileInitOptions(): Dompdf\Options
{
$options = new Dompdf\Options(
is_array($this->options->extraOptions['initOptions'])
? $this->options->extraOptions['initOptions']
: null
);

if (null !== $this->options->pageOrientation) {
$options->setDefaultPaperOrientation(
$this->options->pageOrientation->value
);
}

return $options;
}

/**
* @return array<mixed, mixed>
*/
private function compileOutputOptions(): array
{
$options = $this->options->extraOptions['outputOptions'];

if (false === is_array($options)) {
$options = [];
}

return $options;
}

private function createStream(Dompdf\Dompdf $dompdf): StreamInterface
{
$output = $dompdf->output($this->compileOutputOptions());

return $this
->streamFactory
->createStream($output ?: '')
;
}
}
30 changes: 30 additions & 0 deletions src/Backend/Dompdf/DompdfFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace KNPLabs\Snappy\Backend\Dompdf;

use KNPLabs\Snappy\Core\Backend\Adapter;
use KNPLabs\Snappy\Core\Backend\Factory;
use KNPLabs\Snappy\Core\Backend\Option;
use KNPLabs\Snappy\Core\Backend\Options;
use Psr\Http\Message\StreamFactoryInterface;

/**
* @implements Factory<DompdfAdapter>
*/
final readonly class DompdfFactory implements Factory
{
public function __construct(private readonly StreamFactoryInterface $streamFactory)
{
}

public function create(Options $options): DompdfAdapter
{
return new DompdfAdapter(
factory: $this,
options: $options,
streamFactory: $this->streamFactory,
);
}
}
Loading

0 comments on commit a47421c

Please sign in to comment.