When the content of the CMP is all that is wanted, do you use print styles to hide and adjust all the many elements of the manager? Or send the user to a page outside of the manager where you can better control the markup? Something else?
Also, when using print styles, is it safe to rely on IDs of the form ext-gennn? They appear to be generated by ExtJS and I have no idea when or whether they might be regenerated.
Thank you for your help! I’ve taken your advice and gone the mPDF route. I don’t know how to work with ExtJS so I’ve been trying to adapt it to use vanilla JS. I have created a processor and I think it’s mostly working but I can’t get it to download the actual file. Here’s what my processor looks like:
<?php
namespace FBECEvents\Processors;
use MODX\Revolution\Processors\Processor;
class PrintDetail extends Processor {
public function process() {
require_once MODX_CORE_PATH . 'components/fbecevents/vendor/autoload.php';
try {
$event = $this->getEvent();
$html = $this->generateHtml($event);
$mpdf = new \Mpdf\Mpdf([
'margin_left' => 20,
'margin_right' => 20,
'margin_top' => 20,
'margin_bottom' => 20,
]);
@session_write_close();
$mpdf->WriteHTML($html);
$mpdf->OutputHttpDownload('event.pdf');
$output = json_encode([
'success' => true,
'total' => 1,
'message' => $html
], JSON_INVALID_UTF8_SUBSTITUTE);
return $output;
} catch (Exception $e) {
return $this->failure($e->getMessage());
}
}
private function getEvent() {
try {
$namespace = "FBECEvents\\Model\\";
$id = $this->getProperty('id', null);
if ($id === null) throw new \Exception('No ID provided');
$event = $this->modx->getObject($namespace.'fbecEvent', $id);
if (!$event) throw new \Exception('Event not found');
return $event;
} catch (\Exception $e) {
throw $e;
}
}
private function generateHtml($event) {
if (!$event) throw new \Exception('Event not found');
$html = '
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.header { font-size: 24px; font-weight: bold; }
/* Add more styles as needed */
</style>
</head>
<body>
<div class="header">' . $event->get('title') . '</div>
<div class="date">' . $event->get('date') . '</div>
</body>
</html>';
return $html;
}
}
If I use OutputFile() it successfully creates a file on the server but how can I get the processor to send the file to the client for download? I’ve tried exit()ing after OutputHttpDownload() but it didn’t help. I tried OutputBinaryData() and OutputHttpInline() as well but they didn’t help either.
Adding the inline destination creates the download. Maybe Destination::DOWNLOAD will work too. If you use Destination::STRING_RETURN, you have to set the download headers on your own.
Please don’t use anything after $mpdf->Output(). The code works well on several custom extras.
Please make sure that no error occurs when creating the PDF file. Sometimes the headers are already sent and the browser generates a strange error message without displaying the error message. To be on the safe side, you can generate the result with Destination::STRING_RETURN, set the headers afterwards and exit the result at the end of the try block.
There must be something wrong with my general setup somewhere. I get the same result no matter whether I use INLINE, DOWNLOAD or STRING_RETURN. My try block looks like this now:
I’m not sure if you can start a file download with an AJAX request.
They way I see this usually done in MODX is with 2 requests. The first request (AJAX-request) creates the file, then on success the second request (not AJAX, using location.href) sets the headers (header('Content-Disposition: attachment; ...); etc.) and returns the file content.
Just to say that what I have done in the past when I needed to print off the contents of grids is grab the inner html of the grid container and set that as the body of a newly opened window and called print on document load on that. It actually prints very cleanly and I don’t have to think about security issues with web accessible PDFs on the server.
I remember too that when I was looking for a solution for this, I did find a Extjs plugin for it. Can’t recall exactly why I didn’t end up using it.