I try for several days to display images in my PDF generated with domPDF on symfony 4.
In the pdf, I would like to insert an image from an entity, which I manage with VichUploader.
So I proceeded like this:
In my controller, I added :
// Configure Dompdf according to your needs
$pdfOptions = new Options();
$pdfOptions->set('isRemoteEnabled', true);
In my Twig, I display my image like this :
<img style="width:90px;" src="{{absolute_url(vich_uploader_asset(parametresAdmin, 'logoFile'))}}">
But when I start the action, there is a loop and I end up having the following error:
Error: Maximum execution time of 120 seconds exceeded
However, if I cancel adding the image, the PDF loads well (but without the image since I do not display it)
I checked on the url of the image was well an absolute way and that it was correct, doing this in my Twig:
{% set var = absolute_url(vich_uploader_asset(parametresAdmin, 'logoFile')) %}
<pre>
{{ dump(var) }}
And it is !
And the path is good, because I can open the file in a new tab.
I tried to display my image with a split in my twig :
{% set var = absolute_url(vich_uploader_asset(parametresAdmin, 'logoFile')) %}
<img style="width:90px;" src="{{var}}">
Or pass my url from my controller to my view in parameter :
Controller:
$html = $this->renderView('absence/pdf.html.twig', [
'title' => "Welcome to our PDF Test",
'parametresAdmin' => $parametresAdmin,
'url' => "http://127.0.0.1:8000/admin/logo/avatar2.jpg",
]);
Twig :
<img style="width:90px;" src="{{url}}">
But same problem. Looping for 120 seconds and error :
Error: Maximum execution time of 120 seconds exceeded
So I really do not understand why he does not want to post it in the PDF and that it loops. The path is correct, and works on normal views.
Here is my whole code for an overview:
Controller:
/* Uses */
use Dompdf\Dompdf;
use Dompdf\Options;
/*Fonction*/
/**
* Générer un PDF
* #Route("/absence/pdf", name="absence_pdf")
*
* #return void
*/
public function createPDF(ParametresAdminRepository $repoParametres)
{
$parametresAdmin = $repoParametres->findAll();
if (isset($parametresAdmin[0])) {
$parametresAdmin = $parametresAdmin[0];
} else {
$parametresAdmin = new ParametresAdmin();
}
// Configure Dompdf according to your needs
$pdfOptions = new Options();
$pdfOptions->set('isRemoteEnabled', true);
// Instantiate Dompdf with our options
$dompdf = new Dompdf($pdfOptions);
$dompdf->set_option('isHtml5ParserEnabled', true);
// Retrieve the HTML generated in our twig file
$html = $this->renderView('absence/pdf.html.twig', [
'title' => "Welcome to our PDF Test",
'parametresAdmin' => $parametresAdmin
]);
// Load HTML to Dompdf
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
$dompdf->setPaper('A4', 'portrait');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser (inline view)
$dompdf->stream("mypdf.pdf", [
"Attachment" => false,
]);
}
And my Twig:
<html>
<head>
<meta charset="UTF-8">
<title>Title of the PDF</title>
</head>
<body>
<h4>{{ title }}</h4>
<p>Lorem Ipsum</p>
{% if parametresAdmin.logoName %}
<img style="width:90px;" src="{{absolute_url(vich_uploader_asset(parametresAdmin, 'logoFile'))}}">
{% endif %}
</body>
</html>
EDIT: When I use an absolute path directly from my files, like :
"C:\Users\user\Desktop\congesTest2\public\admin\logo\avatar2.jpg"
It works.
But it seems that if the absolute path is :
http://........
In this case:
http://127.0.0.1:8000/admin/logo/avatar2.jpg
It doesn't work. But I need this path
Thanks for your help !
Related
I just updated from a fairly old version of DOMPDF and now can't see the images which were previously generating.
This is how I'm calling the PDF generation. It generates everything on the PDF apart from the images.
require_once 'dompdf_2-0-3/dompdf/autoload.inc.php';
use Dompdf\Dompdf;
use Dompdf\Options;
$options = new Options();
$options->set('isJavascriptEnabled', TRUE);
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
$dompdf->loadHtml($html); // adds the html to the pdf
$dompdf->setPaper('A4', 'portrait'); // paper size and orientation
$dompdf->render(); // Render the HTML as PDF
$date = (string)date("d.m.y");
$dompdf->stream("Yandiya Calc Results ".($date));
Below is an example of where I use images in the HTML document.
<div class="Page3 page-break">
<div class="House_Back_Container"><img src="images/PDF/buildingInformation.png" class="Template"></img></div>
<div class="House_Type_Icon"><img src="images/{HOUSE_TYPE_ICON}" class="House_Type_Icon"></img></div>
<h1 class="House_Type">{HOUSE_TYPE}</h1>
<h1 class="House_Age">{HOUSE_AGE}</h1>
<h1 class="Tariff_Value">{TARIFF}</h1>
<img src="images/{LOCATION_ICON}" class="Location"></img>
</div>
Obviously, before I updated, the images were rendering with the PDF generation, so it's been confusing me as to what has changed since.
Text displayed as {EXAMPLE} is for my PHP file where the dompdf is ran to replace with variables that I send through AJAX from my client-side.
I am using dompdf with cakephp 3.6 to generate prints from HTML to PDF
I have a function name test inside drivercontroller and i want to load a ctp file which is created inside src\Template\DriverDetails and filename is testpdf.ctp
Can u plz help me to suggest how to pass complete file.
Below is my code
public function test() {
$html = file_get_contents("testpdf.ctp");
$dompdf = new Dompdf();
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$dompdf->stream("invoice.pdf", array("Attachment" =>0));
exit(0);
}
src\Template\DriverDetails\testpdf.ctp
<html>
<body>
<table>
<tr><td align="center"><?php echo $id; ?></td></tr>
<tr><td align="center">Demo Data</td></tr>
</table>
</body>
</html>
You can try like that way.
public function test()
{
$data = "This can be accessible in view file";
$builder = $this->viewBuilder();
$builder->autoLayout(false);
// set your template path [don't use .ctp]
$builder->template('Users/add');
//Pass data into view file
$view = $builder->build(['data' => $data]);
//Render view file content and store into variable
$viewContent = $view->render();
var_dump($viewContent);
}
You can try this. Put this inside controller method. $view_output is a variable where content of ctp file stored. "elements" is ctp file to render. In youur case it is testpdf
/* Make sure the controller doesn't auto render. */
$this->autoRender = false;
/* Set up new view that won't enter the ClassRegistry */
$view = new View($this, false);
$view->set('text', 'Hello World');
$view->viewPath = 'elements';
/* Grab output into variable without */
$view_output = $view->render('box');
Here’s an example of storing the html of an element called ‘box’ with the variable of ‘text’ without the view displaying or outputting
Here is an example
I am changing my assets from PNGs to SVGs, where appropriate, however I am having difficultly including these SVGs in my Twig templates.
I am trying to include the SVG like this:
{{ source('/assets/img/crmpicco-horizontal-logo.svg') }}
However, this results in the following error:
Unable to find template "/assets/img/crmpicco-horizontal-logo.svg"
(looked into:
/Library/WebServer/Documents/crmpicco/symfony/app/Resources/views,
/Library/WebServer/Documents/crmpicco/symfony/vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form).
Why can't I include this SVG in the same directory as my other assets? Specifically, i'm interested in finding out why a SVG can't be treated as an asset with Assetic.
Here is the solution I use (Twig with Symfony 4 and Webpack Encore) :
Inside your twig config, declare your public path :
twig:
paths:
"%kernel.project_dir%/public": public_path
Load your svg asset like that :
{{ source('#public_path'~asset('build/images/your_file.svg')) }}
You have to rename your svg file with a twig extension crmpicco-horizontal-logo.svg.twig and do this :
{% include ":svg:crmpicco-horizontal-logo.svg.twig" %}
The folder svg is in app/Ressources/views in this example
The #adrien-lamotte solution was working for inlining svg tag. However I also needed to dynamically add class(es) on the tag.
I ended up coding a specialized Twig extension for loading SVG and adding attributes, so you do:
{{ source(svg_asset('/images/front/connexion.svg'))|add_class('svg-picto') }}
The svg_asset function is just to limit boilerplate; whereas the add_class and add_html_attr filters allows for the SVG DOM manipulation.
The extension class:
<?php
namespace App\Twig\Extension;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Twig\TwigFilter;
class SvgExtension extends AbstractExtension
{
private $assetExt;
public function __construct(
\Symfony\Bridge\Twig\Extension\AssetExtension $assetExt
) {
$this->assetExt = $assetExt;
}
public function getFunctions(): array
{
// We could use a macro also, but this would need to be imported
// each time.
// https://twig.symfony.com/doc/3.x/tags/macro.html
return array(
new TwigFunction('svg_asset', [$this, 'svg_asset_url']),
);
}
public function getFilters(): array
{
return array(
new TwigFilter('add_html_attr', array($this, 'add_html_attr'), [
'is_safe' => ['html'],
]),
new TwigFilter('add_class', array($this, 'add_class'), [
'is_safe' => ['html'],
]),
);
}
public function svg_asset_url($path): string
{
$assetUrl = $this->assetExt->getAssetUrl($path);
return '#public_path/' . $assetUrl;
}
public function add_html_attr(string $html, $attr_name, $attr_value): string
{
// We assume a top level tag, on which will add an attribute
// value (without checking for a prior existence of the attribute key).
// We could use a naive Regex or a DOM library.
// https://github.com/scotteh/php-dom-wrapper#attr
// Or just the plain PHP DOMDocument() https://www.php.net/domdocument.loadhtml.
$doc = new \DOMWrap\Document();
$doc->setLibxmlOptions(LIBXML_HTML_NOIMPLIED);
return $doc
->html($html)
->children()->first()
->attr($attr_name, $attr_value);
}
public function add_class(string $html, $class_value): string
{
return $this->add_html_attr($html, 'class', $class_value);
}
public function getName()
{
return 'svg.extension';
}
}
#public_path is declared in config/packages/twig.yaml:
twig:
paths:
"%kernel.project_dir%/public": public_path
It is important to note you can have a near equivalent solution to target the SVG with CSS, without the overhead: just add an HTML tag wrapper. For eg.
<div class="svg-wrapper">
{{ source('#public_path'~asset('build/images/your_file.svg')) }}
</div>
I am working on symfony2 and currently I want to check if a file does exist. My scenario look something like this,, I have two files excel file and the docx file. If a person have an excel file for her/his transaction then it is automatically that the docx file is not applicable for her or him.And vice versa. How can I possibly do it in symfony2? A lot in the net but I don't know how to do it in my case,, thanks a lot :)
UPDATE
Controller:
public function documentType ($doc_type) {
$em = $this->getDoctrine()->getEntityManager();
$result = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('xlsx');
$result1 = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('docx');
// statement that will know if the file exists for that certain user if so the other document type will be not applicable for that user. Example: that user have docx file already then the xlsx will be N/A and vice versa
}
Repository :
public function findDocumentType ($doc_type) {
$em = $this->getEntityManager();
$query = $em->createQuery(
'SELECT a, b, c FROM SupplierBundle:SupplierTransaction Details a
JOIN a.supplierTransaction b
JOIN b.supplierDocType c
WHERE c.docType LIKE :doc_type'
)->setParameter('doc_type', $doc_type);
return $query->getResult();
}
You can just use plain PHP for this. For example:
$xls = 'sheet.xlsx';
$doc = 'document.docx';
if (file_exists($xls)) {
// User has an XLSX file
echo 'Download your sheet here.';
} elseif (file_exists($doc)) {
// User has a DOCX file
echo 'Download your document here.';
}
If you want to do it the Symfony2 way, you can use the Filesystem class, it has an exists() function. In a controller an instance is automatically available in the service container:
$em = $this->getDoctrine()->getManager();
$xlsx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumentType('xlsx');
$docx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumnetType('docx');
return [
'xlsx' => $xlsx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($xlsx->getFile()) ? $xlsx->getFile() : null,
'docx' => $docx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($docx->getFile()) ? $docx->getFile() : null,
];
In your twig template:
{% if xlsx is not empty %}
{{ xlsx }}
{% endif %}
{% if docx is not empty %}
{{ docx }}
{% endif %}
I'm using Symfony and mPDF.
I'm trying to integrate both but am running into some problems.
I need to capture the content of a view but can't see how to do it.
public function executePDF(sfWebRequest $request)
{
$this->object = $this->getRoute()->getObject();
require_once 'mpdf.php';
/* Example code from mPDF site */
$mpdf=new mPDF('win-1252','A4','','',20,15,48,25,10,10);
$mpdf->useOnlyCoreFonts = true; // false is default
$mpdf->SetProtection(array('print'));
$mpdf->SetTitle("Acme Trading Co. - Invoice");
$mpdf->SetAuthor("Acme Trading Co.");
$mpdf->SetWatermarkText("Paid");
$mpdf->showWatermarkText = true;
$mpdf->watermark_font = 'DejaVuSansCondensed';
$mpdf->watermarkTextAlpha = 0.1;
$mpdf->SetDisplayMode('fullpage');
$this->setLayout(false);
$html = $this->getResponse()->getContent();
$mpdf->WriteHTML($html);
$mpdf->Output();
exit;
}
With the above example, $html is returned as an empty string. I have a view template relating to this action (PDFSuccess.php) which accesses the $object and has the HTML that mPDF will use.
Thanks for any help.
As it is just now, when accessing this action it does open a PDF correctly, but there is no content in it.
Thanks
Haven't done this in this specific context but you could try:
$html = $this->getPartial('moduleName/partialName');
... where the template is a partial (_partialName) inside a given module. As it's a partial, there's no need to switch off the layout.
You can also pass variables to it:
$html = $this->getPartial('moduleName/partialName', array('var' => 'something'));
...
If that doesn't work, here's a question relating to email templates that contains an alternative way of doing this (see the accepted answer):
Email body in Symfony 1.4 mailer?