Initial commit
This commit is contained in:
commit
26942cdbde
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/vendor/
|
||||||
|
/composer.lock
|
26
composer.json
Normal file
26
composer.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "noccylabs/pdf-bundle",
|
||||||
|
"description": "Generate PDFs in Symfony",
|
||||||
|
"type": "bundle",
|
||||||
|
"require": {
|
||||||
|
"dompdf/dompdf": "^0.8.1"
|
||||||
|
},
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christopher Vagnetoft",
|
||||||
|
"email": "cvagnetoft@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "composer",
|
||||||
|
"url": "https://packages.noccylabs.info/composer/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"NoccyLabs\\Bundle\\PdfBundle\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/DependencyInjection/Configuration.php
Normal file
29
src/DependencyInjection/Configuration.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Bundle\PdfBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the class that validates and merges configuration from your app/config files.
|
||||||
|
*
|
||||||
|
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
|
||||||
|
*/
|
||||||
|
class Configuration implements ConfigurationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getConfigTreeBuilder()
|
||||||
|
{
|
||||||
|
$treeBuilder = new TreeBuilder();
|
||||||
|
$rootNode = $treeBuilder->root('noccy_labs_pdf_converter');
|
||||||
|
|
||||||
|
// Here you should define the parameters that are allowed to
|
||||||
|
// configure your bundle. See the documentation linked above for
|
||||||
|
// more information on that topic.
|
||||||
|
|
||||||
|
return $treeBuilder;
|
||||||
|
}
|
||||||
|
}
|
28
src/DependencyInjection/NoccyLabsPdfExtension.php
Normal file
28
src/DependencyInjection/NoccyLabsPdfExtension.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Bundle\PdfBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the class that loads and manages your bundle configuration.
|
||||||
|
*
|
||||||
|
* @link http://symfony.com/doc/current/cookbook/bundles/extension.html
|
||||||
|
*/
|
||||||
|
class NoccyLabsPdfExtension extends Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
$configuration = new Configuration();
|
||||||
|
$config = $this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||||
|
$loader->load('services.yml');
|
||||||
|
}
|
||||||
|
}
|
9
src/NoccyLabsPdfBundle.php
Normal file
9
src/NoccyLabsPdfBundle.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Bundle\PdfBundle;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
|
||||||
|
class NoccyLabsPdfBundle extends Bundle
|
||||||
|
{
|
||||||
|
}
|
49
src/Pdf/PdfGenerator.php
Normal file
49
src/Pdf/PdfGenerator.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Bundle\PdfBundle\Pdf;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
|
||||||
|
class PdfGenerator
|
||||||
|
{
|
||||||
|
protected $tempDir;
|
||||||
|
|
||||||
|
public function __construct($tempDir)
|
||||||
|
{
|
||||||
|
$this->tempDir = $tempDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate($html, array $options=[])
|
||||||
|
{
|
||||||
|
$pdf = new Dompdf();
|
||||||
|
$pdf->loadHtml($html);
|
||||||
|
$pdf->render();
|
||||||
|
|
||||||
|
$output = $pdf->output();
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateResponseFromHtml($html, array $options=[])
|
||||||
|
{
|
||||||
|
$tempFile = $this->tempDir . "/" . "pdf_" . md5(uniqid()) . ".pdf";
|
||||||
|
|
||||||
|
// Call on generate with the options provided
|
||||||
|
$output = $this->generate($html, $options);
|
||||||
|
file_put_contents($tempFile, $output);
|
||||||
|
|
||||||
|
// Prepare the response
|
||||||
|
$response = new BinaryFileResponse($tempFile);
|
||||||
|
if (array_key_exists('filename', $options)) {
|
||||||
|
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $options['filename']);
|
||||||
|
} else {
|
||||||
|
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE);
|
||||||
|
}
|
||||||
|
$response->deleteFileAfterSend(true);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
14
src/Resources/config/services.yml
Normal file
14
src/Resources/config/services.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
NoccyLabs\Bundle\PdfBundle\Controller\DefaultController:
|
||||||
|
public: true
|
||||||
|
calls:
|
||||||
|
- [ setGenerator, [ "@noccylabs.pdf.generator" ]]
|
||||||
|
|
||||||
|
noccylabs.pdf.generator:
|
||||||
|
class: NoccyLabs\Bundle\PdfBundle\Pdf\PdfGenerator
|
||||||
|
arguments: [ "%kernel.cache_dir%" ]
|
||||||
|
public: true
|
164
src/Resources/views/Example/example.html.twig
Normal file
164
src/Resources/views/Example/example.html.twig
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
{% extends "NoccyLabsPdfBundle:Pdf:document.html.twig" %}
|
||||||
|
{% import "NoccyLabsPdfBundle:Pdf:document.html.twig" as page %}
|
||||||
|
{% import _self as helpers %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
<table class="full-width">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="small">Postal address:</div>
|
||||||
|
<div>Some Company Name<br>1234 Address St.<br>12345 Somewhere</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="small">Postal address:</div>
|
||||||
|
<div>Some Company Name<br>1234 Address St.<br>12345 Somewhere</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="small">Postal address:</div>
|
||||||
|
<div>Some Company Name<br>1234 Address St.<br>12345 Somewhere</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 9pt;
|
||||||
|
}
|
||||||
|
.small {
|
||||||
|
font-size: 7pt;
|
||||||
|
}
|
||||||
|
table.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
table.bordered {
|
||||||
|
border: solid 1px #666;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table.bordered td,
|
||||||
|
table.bordered th {
|
||||||
|
padding: 3px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
table.bordered thead {
|
||||||
|
background: #cde;
|
||||||
|
border-bottom: solid 1px #666;
|
||||||
|
}
|
||||||
|
.page-footer {
|
||||||
|
border-top: solid 1px #000;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.monospaced {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2"><div class="small">Client No.</div>123456</div>
|
||||||
|
<div class="col-2"><div class="small">Date</div>2017-12-01</div>
|
||||||
|
<div class="col-2">Third</div>
|
||||||
|
<div class="col-5"></div>
|
||||||
|
<div class="col-1"><div class="small">Page</div>1 (2)</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="full-width bordered monospaced">
|
||||||
|
{{ helpers.thead() }}
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>12345</td>
|
||||||
|
<td>Abcd<br>multi-line!</td>
|
||||||
|
<td class="align-right" style="background:#def;">199.99</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>12345</td>
|
||||||
|
<td>Abcd<br>multi-line!</td>
|
||||||
|
<td class="align-right" style="background:#def;">199.99</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{ page.break() }}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-11"> </div>
|
||||||
|
<div class="col-1"><div class="small">Page</div>2 (2)</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="full-width bordered monospaced">
|
||||||
|
{{ helpers.thead }}
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>12345</td>
|
||||||
|
<td>Abcd<br>multi-line!</td>
|
||||||
|
<td class="align-right" style="background:#def;">199.99</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>12345</td>
|
||||||
|
<td>Abcd<br>multi-line!</td>
|
||||||
|
<td class="align-right" style="background:#def;">199.99</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> <br> </td>
|
||||||
|
<td style="background:#def;"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro thead() %}
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="15%">SKU</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th width="10%">Price</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{% endmacro %}
|
99
src/Resources/views/Pdf/document.html.twig
Normal file
99
src/Resources/views/Pdf/document.html.twig
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
{#
|
||||||
|
# This is the base document template for PdfBundle. You should construct your
|
||||||
|
# views by extending from this template.
|
||||||
|
#
|
||||||
|
# (c) 2017, NoccyLabs. Licensed under GPL v3
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# -- break macro -- #}
|
||||||
|
{% macro break() %}
|
||||||
|
</div><div class="new-page">
|
||||||
|
{% if block("footer") is defined %}
|
||||||
|
<div class="page-footer">{{ block("footer") }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
@media all {
|
||||||
|
div.page-footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 2cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.new-page {
|
||||||
|
page-break-before: always;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.row {
|
||||||
|
display: block;
|
||||||
|
margin: 5px 0px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
div.row:before,
|
||||||
|
div.row:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
div.row > div {
|
||||||
|
float: left;
|
||||||
|
min-height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.col-1 {
|
||||||
|
width: 8.333%;
|
||||||
|
}
|
||||||
|
div.col-2 {
|
||||||
|
width: 16.667%;
|
||||||
|
}
|
||||||
|
div.col-3 {
|
||||||
|
width: 25.000%;
|
||||||
|
}
|
||||||
|
div.col-4 {
|
||||||
|
width: 33.333%;
|
||||||
|
}
|
||||||
|
div.col-5 {
|
||||||
|
width: 41.667%;
|
||||||
|
}
|
||||||
|
div.col-6 {
|
||||||
|
width: 50.000%;
|
||||||
|
}
|
||||||
|
div.col-7 {
|
||||||
|
width: 58.333%;
|
||||||
|
}
|
||||||
|
div.col-8 {
|
||||||
|
width: 66.667%;
|
||||||
|
}
|
||||||
|
div.col-9 {
|
||||||
|
width: 75.000%;
|
||||||
|
}
|
||||||
|
div.col-10 {
|
||||||
|
width: 83.333%;
|
||||||
|
}
|
||||||
|
div.col-11 {
|
||||||
|
width: 91.667%;
|
||||||
|
}
|
||||||
|
div.col-12 {
|
||||||
|
width: 100.000%;
|
||||||
|
}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{% endblock %}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% if block("footer") is defined %}
|
||||||
|
<div class="page-footer">{{ block("footer") }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
{% block body %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user