Skip to content

Commit 9afd246

Browse files
authored
Merge pull request #5 from Gagl0u/add-custom-extension
feat: Add the possibility to add a custom extension to twig bugfix: escaping for " and ' dependencies updated
2 parents 4473378 + d3ca123 commit 9afd246

10 files changed

Lines changed: 372 additions & 217 deletions

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ Example: `_tex.dir`
5656
php -f samples/simple-report.php
5757
```
5858

59+
# Examples
60+
61+
You can find some real world examples in the `samples` Folder
62+
5963
# Contribute
6064
Please run
6165
```
6266
composer cs-fix
6367
```
64-
before doing a pull request
68+
and commit the changes in an extra commit before doing a pull request

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
"description": "Renders LaTeX Templates in PHP",
44
"type": "libary",
55
"license": "MIT",
6-
"version": "1.1.9",
6+
"version": "1.2.0",
77
"authors": [
88
{
99
"name": "Lukas Staab",
10-
"email": "l.staab@posteo.de"
10+
"email": "lukas@open-administration.de"
1111
}
1212
],
1313
"minimum-stability": "stable",
1414
"require": {
1515
"php": "^8.0",
1616
"symfony/process": "^5.3|^6.0|^7.0",
17-
"twig/twig": "^3.3",
17+
"twig/twig": "^3.10",
1818
"psr/log": "^1|^2|^3"
1919
},
2020
"require-dev": {

composer.lock

Lines changed: 254 additions & 181 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/basic.tex.twig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
\usepackage{graphicx}
66
\usepackage{xcolor}
77
\usepackage{ngerman}
8-
\usepackage[tx]{sfmath}
98
\usepackage{calc}
109
\usepackage{lastpage}
1110
\usepackage{xifthen}

samples/simple-report.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,27 @@
66

77
require ROOT . '/vendor/autoload.php';
88

9-
$finder = new \Symfony\Component\Process\ExecutableFinder();
9+
$finder = new Symfony\Component\Process\ExecutableFinder();
1010
$pdfLatex = $finder->find('pdflatex');
1111
$tex = new LatexRenderer(__DIR__, ROOT . '/runtime/', 'pdflatex', true); // <- debug true - files will not be deleted
12-
$monolog = new \Monolog\Logger('Tex-Samples', [new \Monolog\Handler\StreamHandler('php://output')]);
12+
$monolog = new Monolog\Logger('Tex-Samples', [new Monolog\Handler\StreamHandler('php://output')]);
1313
$tex->setLogger($monolog);
1414
$pdf = $tex->renderPdf('simple-report', [
1515
'title' => 'My Custom Title',
1616
'author' => 'Me!',
1717
'content' => [
1818
[
19-
'headline' => 'This is a Test Headline',
20-
'items' => [
21-
[
22-
'label' => 'test',
23-
'value' => 'value',
24-
],
25-
[
26-
'label' => 'test',
27-
'value' => 'value',
28-
],
29-
],
19+
'headline' => 'This is a Test Headline',
20+
'items' => [
21+
[
22+
'label' => 'test',
23+
'value' => 'value',
24+
],
25+
[
26+
'label' => 'test',
27+
'value' => 'value',
28+
],
29+
],
3030
],
3131
[
3232
'headline' => 'test2',
@@ -57,6 +57,6 @@
5757
],
5858
],
5959
], [
60-
'example.pdf' => file_get_contents('example.pdf'),
60+
'example.pdf' => file_get_contents(ROOT . '/samples/example.pdf'),
6161
]);
6262
echo $pdf !== null ? 'Success' . PHP_EOL : 'Failure' . PHP_EOL;

samples/simple-report.tex.twig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@
4141
\vspace{5mm}
4242
(% endif %)%end signatures
4343
(% endfor %)%end content
44-
\mysection{Attachments}
44+
\mysection{List of Attachments}
4545
\begin{enumerate}[label=\roman*)]
46+
(% if _tex.files is empty %)
47+
\item no attachments given
48+
(% endif %)
4649
(% for name,path in _tex.files %)
4750
\item \texttt{(( name ))} in \texttt{(( path ))} with \texttt{(( path|pages ))} pages
4851
(% endfor %)

samples/testEscaping.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
use PhpLatexRenderer\LatexRenderer;
4+
5+
define('ROOT', dirname(__FILE__, 2));
6+
7+
require ROOT . '/vendor/autoload.php';
8+
9+
$finder = new Symfony\Component\Process\ExecutableFinder();
10+
$pdfLatex = $finder->find('pdflatex');
11+
$tex = new LatexRenderer(__DIR__, ROOT . '/runtime/', 'pdflatex', true); // <- debug true - files will not be deleted
12+
$monolog = new Monolog\Logger('Tex-Samples', [new Monolog\Handler\StreamHandler('php://output')]);
13+
$tex->setLogger($monolog);
14+
$pdf = $tex->renderPdf('simple-report', [
15+
'title' => 'My Custom Title',
16+
'author' => 'Me!',
17+
'content' => [
18+
[
19+
'headline' => 'This is a Test Headline',
20+
'items' => [
21+
[
22+
'label' => 'Euro',
23+
'value' => '',
24+
], [
25+
'label' => 'Dollar',
26+
'value' => '$',
27+
], [
28+
'label' => 'Tilde',
29+
'value' => '~',
30+
], [
31+
'label' => 'Circumflex',
32+
'value' => '^',
33+
], [
34+
'label' => 'And',
35+
'value' => '&',
36+
], [
37+
'label' => 'Percent',
38+
'value' => '%',
39+
], [
40+
'label' => 'Hashtag',
41+
'value' => '#',
42+
], [
43+
'label' => 'Underscore',
44+
'value' => '_',
45+
], [
46+
'label' => 'Curlybraces',
47+
'value' => '{}',
48+
], [
49+
'label' => 'Hyphens',
50+
'value' => '"\'',
51+
],
52+
],
53+
],
54+
],
55+
]);
56+
echo $pdf !== null ? 'Success' . PHP_EOL : 'Failure' . PHP_EOL;

samples/testPath.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
require dirname(__FILE__, 2) . '/vendor/autoload.php';
4-
$p = new \Symfony\Component\Process\Process(['pdflatex'], __DIR__, getenv());
4+
$p = new Symfony\Component\Process\Process(['pdflatex'], __DIR__, getenv());
55
$p->run();
66
echo $p->getOutput();
77
echo PHP_EOL . 'error:';

src/LatexEscape.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,32 @@
44

55
class LatexEscape
66
{
7-
public static function escape($twig, ?string $unsafe, $charset): string
7+
// @see: https://tex.stackexchange.com/a/34586
8+
public const ESCAPES = [
9+
'\\' => '\\textbackslash{}',
10+
'&' => '\\&',
11+
'%' => '\\%',
12+
'$' => '\\$',
13+
'#' => '\\#',
14+
'_' => '\\_',
15+
'{' => '\\{',
16+
'}' => '\\}',
17+
'~' => '\\~{}',
18+
'^' => '\\^{}',
19+
"'" => "\\'{}",
20+
'"' => '\\"{}',
21+
];
22+
23+
public static function escape(?string $unsafe, $charset): string
824
{
925
if ($unsafe === null) {
1026
return '';
1127
}
1228
$safer = str_replace(
13-
['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^'],
14-
['\\textbackslash{}', '\\&', '\\%', '\\$', '\\#', '\\_', '\\{', '\\}', '\\textasciitilde{}', '\\textasciicircum{}'],
29+
array_keys(self::ESCAPES),
30+
array_values(self::ESCAPES),
1531
$unsafe
1632
);
17-
$safer = trim($safer);
18-
// $safer = str_replace(PHP_EOL, '\\\\', $safer);
19-
return $safer;
33+
return trim($safer);
2034
}
2135
}

src/LatexRenderer.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
use Twig\Environment;
1010
use Twig\Error\Error;
1111
use Twig\Extension\DebugExtension;
12-
use Twig\Extension\EscaperExtension;
12+
use Twig\Extension\ExtensionInterface;
1313
use Twig\Lexer;
1414
use Twig\Loader\FilesystemLoader;
15+
use Twig\Runtime\EscaperRuntime;
1516

1617
/**
1718
* Configure and execute the rendering
@@ -22,7 +23,7 @@ class LatexRenderer
2223

2324
private string $latexExec;
2425

25-
private \Twig\Environment $twig;
26+
private Environment $twig;
2627

2728
private bool $debug;
2829

@@ -34,7 +35,7 @@ class LatexRenderer
3435
* @param $latexExec string the path to the latex exec to use
3536
* @param $debug bool true the files will not be deleted after attempted rendering
3637
*/
37-
public function __construct($templateDirs, string $tmpDir = '/tmp/', string $latexExec = 'pdflatex', bool $debug = false)
38+
public function __construct(array|string $templateDirs, string $tmpDir = '/tmp/', string $latexExec = 'pdflatex', bool $debug = false)
3839
{
3940
$this->debug = $debug;
4041
$this->latexExec = $latexExec;
@@ -47,7 +48,7 @@ public function __construct($templateDirs, string $tmpDir = '/tmp/', string $lat
4748
'cache' => false,
4849
]);
4950
$this->twig->addGlobal('_tex', []);
50-
$this->twig->getExtension(EscaperExtension::class)->setEscaper('tex', [LatexEscape::class, 'escape']);
51+
$this->twig->getRuntime(EscaperRuntime::class)->setEscaper('tex', [LatexEscape::class, 'escape']);
5152
$this->twig->addExtension(new LatexFilterExtension());
5253
$this->twig->addExtension(new PdfFilterExtension());
5354
if ($debug) {
@@ -62,7 +63,7 @@ public function __construct($templateDirs, string $tmpDir = '/tmp/', string $lat
6263
}
6364

6465
/**
65-
* @param array $lexerOptions {@see \Twig\Lexer}
66+
* @param array $lexerOptions {@see Lexer}
6667
*/
6768
public function setTwigLexer(array $lexerOptions): void
6869
{
@@ -74,9 +75,6 @@ public function setLogger(LoggerInterface $logger): void
7475
$this->logger = $logger;
7576
}
7677

77-
/**
78-
* @param $templateDir
79-
*/
8078
public function setTemplateDir($templateDir): void
8179
{
8280
$this->twig->setLoader(new FilesystemLoader($templateDir));
@@ -96,6 +94,14 @@ public function setTmpDir(string $tmpDir): void
9694
}
9795
}
9896

97+
/**
98+
* @param ExtensionInterface $extension the custom extension to add to twig instance
99+
*/
100+
public function addCustomExtension(ExtensionInterface $extension): void
101+
{
102+
$this->twig->addExtension($extension);
103+
}
104+
99105
/**
100106
* @param array $variables _tex will be added
101107
* @param array $files additional files which will be saved to ./files/<name> - format: key=name, value=fileContent
@@ -133,7 +139,7 @@ public function renderPdf(string $templateName, array $variables, array $files =
133139

134140
$proc = new Process([$this->latexExec, 'main.tex'], $this->tmpDir . "tex/$templateName/$uid/", getenv());
135141
$proc->run();
136-
// do a second time
142+
// run it a second time, some tex features need dual compilation
137143
$proc2 = $proc->restart();
138144
$proc2->wait();
139145
$dir = $this->tmpDir . "tex/$templateName/$uid";

0 commit comments

Comments
 (0)