Skip to content

Commit

Permalink
Add KnpSnappyWriter
Browse files Browse the repository at this point in the history
  • Loading branch information
chalasr authored and greg0ire committed May 19, 2016
1 parent e8e2774 commit 7319fe2
Show file tree
Hide file tree
Showing 6 changed files with 513 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [1.x]
### Added
- Add `KnpSnappyWriter` that introduces PDF export format.

## [1.4.0](https://github.com/sonata-project/exporter/compare/1.3.4...1.4.0) - 2015-06-09
### Added
Expand Down
16 changes: 10 additions & 6 deletions composer.json
Expand Up @@ -16,18 +16,22 @@
"php": "^5.3 || ^7.0"
},
"require-dev": {
"symfony/routing": "^2.3 || ^3.0",
"symfony/property-access": "^2.3 || ^3.0",
"symfony/phpunit-bridge": "^2.7 || ^3.0",
"propel/propel1": "^1.6",
"fabpot/php-cs-fixer": "~0.1 || ^1.0",
"sllh/php-cs-fixer-styleci-bridge": "^2.0"
"h4cc/wkhtmltopdf-amd64": "^0.12",
"knplabs/knp-snappy": "^0.4",
"mikey179/vfsStream": "^1.6",
"propel/propel1": "^1.6",
"sllh/php-cs-fixer-styleci-bridge": "^2.0",
"symfony/phpunit-bridge": "^2.7 || ^3.0",
"symfony/property-access": "^2.3 || ^3.0",
"symfony/routing": "^2.3 || ^3.0"
},
"suggest": {
"ext-curl": "*",
"symfony/routing": "^2.3 || ^3.0",
"symfony/property-access": "^2.3 || ^3.0",
"propel/propel1": "^1.6"
"propel/propel1": "^1.6",
"knplabs/knp-snappy": "For using the KnpSnappyWriter to export data in PDF format"
},
"autoload": {
"psr-0": {
Expand Down
30 changes: 29 additions & 1 deletion docs/reference/outputs.rst
Expand Up @@ -12,5 +12,33 @@ Several output formatters are supported:
* XML
* Excel XML
* XLS (MS Excel)
* PDF

You may also create your own. To do so, simply create a class that implements the ``Exporter\Writer\WriterInterface``.
You may also create your own. To do so, simply create a class that implements the ``Exporter\Writer\WriterInterface``.

The knplabs/knp-snappy writer
=============================

If you want to generate a pdf output, you can use the ``knplabs/knp-snappy`` writer.
You will have to `install the library and its dependencies <https://github.com/KnpLabs/snappy>`_
(including ``wkhtmltopdf``).

The instanciation of the writer goes like this:

.. code-block:: php
<?php
use Exporter\Writer\KnpSnappyWriter;
use Knp\Snappy\Pdf;
$writer = new KnpSnappyWriter(
new Pdf(),
'output.pdf',
'/absolute/path/to/the/wkhtmltopdf/binary',
true, // include a header
true, // add borders
array(
'any_supported_snappy_option' => 'and its value',
)
);
245 changes: 245 additions & 0 deletions lib/Exporter/Writer/KnpSnappyWriter.php
@@ -0,0 +1,245 @@
<?php

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Exporter\Writer;

use Knp\Snappy\Pdf;

/**
* Export data in PDF format.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
final class KnpSnappyWriter implements WriterInterface
{
/**
* @var Pdf
*/
private $pdfGenerator;

/**
* @var string
*/
private $filename;

/**
* @var string
*/
private $wkhtmltopdf;

/**
* @var bool
*/
private $showHeaders;

/**
* @var bool
*/
private $showBorders;

/**
* @var array
*
* @see http://wkhtmltopdf.org/usage/wkhtmltopdf.txt
*/
private $snappyOptions;

/**
* @var resource
*/
private $file;

/**
* @var string
*/
private $html = '
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name=ProgId content=Pdf.Document>
<meta name=Generator content="https://github.com/sonata-project/exporter">
<style></style>
</head>
<body>
[header-html]
<table>[content]</table>
[footer-html]
</body>
</html>';

/**
* @throws \RuntimeException
* @throws \InvalidArgumentException
*
* @param Pdf $pdfGenerator
* @param string $filename
* @param bool $showHeaders
* @param bool $showBorders
* @param array $snappyOptions KnpSnappy options (wkhtmltopdf)
* @param string $wkhtmltopdf Path of the wkhtmltopdf binary
*/
public function __construct(
Pdf $pdfGenerator,
$filename,
$wkhtmltopdf,
$showHeaders = true,
$showBorders = true,
array $snappyOptions = array()
) {
if (!is_bool($showHeaders)) {
throw new \InvalidArgumentException(sprintf(
'The second argument of "%s::__construct()" must be of type boolean, %s given',
__CLASS__,
gettype($showHeaders)
));
}

if (!is_bool($showBorders)) {
throw new \InvalidArgumentException(sprintf(
'The third argument of "%s::__construct()" must be of type boolean, %s given',
__CLASS__,
gettype($showBorders)
));
}

if (is_file($filename)) {
throw new \RuntimeException(sprintf('The file "%s" already exists', $filename));
}

if (!is_executable($wkhtmltopdf)) {
throw new \RuntimeException(sprintf('The file "%s" does not exist or is not executable', $wkhtmltopdf));
}

$this->pdfGenerator = $pdfGenerator;
$this->filename = $filename;
$this->showHeaders = $showHeaders;
$this->showBorders = $showBorders;
$this->snappyOptions = $snappyOptions;
$this->wkhtmltopdf = $wkhtmltopdf;
}

/**
* {@inheritdoc}
*/
public function open()
{
$this->file = fopen($this->filename, 'w', false);
}

/**
* {@inheritdoc}
*/
public function write(array $data)
{
$tmpFile = tmpfile();

if ($this->showBorders) {
$this->addBorders();
}

$this->addMarkupFromOptions();

if ($this->showHeaders) {
fwrite($tmpFile, $this->getHeaders(array_keys($data)));
}

fwrite($tmpFile, '<tr>');

foreach ($data as $value) {
fwrite($tmpFile, sprintf('<td>%s</td>', $value));
}

fwrite($tmpFile, '</tr>');

$tmpFileMetaData = stream_get_meta_data($tmpFile);
$tmpFilePath = $tmpFileMetaData['uri'];

fwrite($this->file, $this->generatePdf($tmpFilePath));

fclose($tmpFile);
}

/**
* {@inheritdoc}
*/
public function close()
{
fclose($this->file);
}

/**
* Generates a PDF using KnpSnappy.
*
* @param string $htmlFilename.
*
* @return string The generated PDF content.
*/
private function generatePdf($htmlFilename)
{
$this->pdfGenerator->setBinary($this->wkhtmltopdf);

foreach ($this->snappyOptions as $key => $value) {
$this->pdfGenerator->setOption($key, $value);
}

$this->html = str_replace('[content]', file_get_contents($htmlFilename), $this->html);

return $this->pdfGenerator->getOutputFromHtml($this->html);
}

/**
* Add style for bordered table.
*/
private function addBorders()
{
$borderedStyle = '<style>table{border-collapse:collapse;width:90%;}th,td{border:1px solid black;}</style>';

$this->html = str_replace('<style></style>', $borderedStyle, $this->html);
}

/**
* @param array $columnNames
*
* @return string
*/
private function getHeaders(array $columnNames)
{
$row = '';

foreach ($columnNames as $name) {
$row .= sprintf('<th>%s</th>', $name);
}

return sprintf('<tr>%s</tr>', $row);
}

/**
* Handles header-html/footer-html wkhtmltopdf options.
*/
private function addMarkupFromOptions()
{
$markupOptions = array('header-html', 'footer-html');

foreach ($markupOptions as $key) {
if (!isset($this->snappyOptions[$key])) {
$this->snappyOptions[$key] = '';
}

$this->html = str_replace(
sprintf('[%s]', $key),
$this->snappyOptions[$key],
$this->html
);

unset($this->snappyOptions[$key]);
}
}
}

0 comments on commit 7319fe2

Please sign in to comment.