Add PDF generation module with HTML2PDF integration.

This commit introduces a new PDF generation module leveraging the HTML2PDF library. The module generates PDFs from HTML templates, supports customization through styles and templates, and integrates with Minio for storage and retrieval. A test route is added for generating and serving PDFs dynamically.
This commit is contained in:
Jepp9350
2025-03-14 14:56:55 +01:00
parent b95215677a
commit 45328a6b72
17 changed files with 1176 additions and 0 deletions
@@ -0,0 +1,264 @@
<?php
namespace classes;
require_once WD . '/modules/html2pdf/html2pdf_templates.php';
use Exception;
use html2pdf\html2pdf_templates;
use interfaces\pdf_generator_i;
use Spipu\Html2Pdf\Exception\Html2PdfException;
use Spipu\Html2Pdf\Html2Pdf;
class pdf_generator implements pdf_generator_i
{
/**
* The templates
* @var html2pdf_templates $templates The templates
*/
public html2pdf_templates $templates;
/**
* The HTML content to be converted to PDF
* @var string $html HTML content to be converted to PDF
*/
protected string $html;
/**
* The filename to save the PDF as
* @notation When the filename is null, the PDF will be stored as a file with a random name.
* @var string|null $filename Filename to save the PDF as
*/
protected string|null $filename;
/**
* The path where the module is located
* @notation The path must end with a /
* @var string $module_path Path to module files (Example: /var/www/html/pdf/)
*/
protected string $module_path;
/**
* The path where the PDF will be saved (temporary path)
* @notation This is automatically generated and should not be changed
* @var string $pdf_path
*/
protected string $pdf_path;
/**
* The tmp pdf location
* @notation This is automatically generated and should not be changed
* @var string $tmp_file_path (Example: /tmp/filename.pdf)
*/
protected string $tmp_file_path;
/**
* The path where the templates are located
* @notation The path must end with a /
* @var string $template_path Path to templates (Example: /var/www/html/pdf/templates/)
*/
protected string $template_path;
/**
* The unique ID for the tmp file
* @var string $tmp_file_unique_id The unique ID for the tmp file
* @notation This is automatically generated and should not be changed
* @see generate_tmp_file_unique_id()
* @see get_temp_file_path()
* @see store_tmp_file()
* @see is_temp_file_path_set()
*/
protected string $tmp_file_unique_id;
/**
* The HTML2PDF object
* @var Html2Pdf $html2pdf HTML2PDF object
*/
protected Html2Pdf $html2pdf;
/**
* The constructor for the pdf_generator class
* @notation This function is used to initialize the class and set the paths
* @throws Exception If the paths are not valid, writeable or readable
*/
public function __construct()
{
$this->html = '';
$this->filename = null;
$this->module_path = WD . '/modules/html2pdf/';
$this->template_path = $this->module_path . 'templates/';
$this->html2pdf = new Html2Pdf();
$this->templates = new html2pdf_templates();
//self::create_tmp_dir();
self::require_valid_paths([$this->template_path, $this->module_path]);
}
/**
* @inheritDoc
*/
public function require_valid_paths(array $paths): bool
{
if (!self::validate_paths($paths)) {
foreach ( $paths as $path ) {
if (!self::validate_paths(array($path))) {
// Check if the path is valid
if (!is_dir($path)) {
throw new Exception('The path ' . $path . ' is not valid');
}
// Check if the path is readable
if (!is_readable($path)) {
throw new Exception('The path ' . $path . ' is not readable');
}
}
}
}
return true;
}
/**
* @inheritDoc
*/
public function validate_paths(array $paths): bool
{
// Check if the paths are valid
foreach ( $paths as $path ) {
if (!is_dir($path) || !is_readable($path)) {
return false;
}
}
return true;
}
/**
* @inheritDoc
*/
public function is_writeable(string $path): bool
{
// Check if the path is writeable
if (is_writable($path)) {
return true;
}
return false;
}
/**
* Add the HTML content to be converted to PDF
* @param string $html HTML content to be converted to PDF
* @return self
*/
public function add_html(string $html): self
{
$this->html .= $html;
return $this;
}
/**
* Set the filename to save the PDF as
* @param string|null $filename Filename to save the PDF as
* @return self
*/
public function set_filename(string|null $filename): self
{
$this->filename = $filename;
return $this;
}
/**
* @inheritDoc
* @throws Html2PdfException If there is an error generating the PDF
* @throws Exception
*/
public function generate_pdf(): string
{
// Set the HTML content
$this->html2pdf->writeHTML($this->html);
// Generate a random tmp file name if the filename is not set
self::generate_tmp_file();
// Set the path to save the PDF
$pdf_file = $this->pdf_path;
// Output the PDF to a file
$this->html2pdf->output($pdf_file, 'F');
// Set the path to the tmp file
$this->tmp_file_path = $pdf_file;
self::store_tmp_file();
return $this->tmp_file_path;
}
/**
* @inheritDoc
*/
public function generate_tmp_file(): pdf_generator_i
{
// Generate a random filename
$this->filename = uniqid() . '.pdf';
// Set the path to save the PDF
$this->pdf_path = '/tmp/' . $this->filename;
return $this;
}
/**
* @inheritDoc
*/
public function store_tmp_file(): pdf_generator_i
{
// Check if the tmp_file_path is set
if (!self::is_temp_file_path_set()) {
throw new Exception('The tmp_file_path is not set, cannot store unknown file');
}
// Save the PDF to the minio store
$pdf_store = new pdf_store();
$pdf_store->upload(self::generate_tmp_file_unique_id(), self::get_temp_file_path());
// Delete the tmp file
if (file_exists($this->tmp_file_path)) {
unlink($this->tmp_file_path);
}
// Set the path to the tmp file
$this->tmp_file_path = $pdf_store->get_pdf_key_name($this->tmp_file_unique_id);
return $this;
}
/**
* Check if the tmp_file_path is set
* @notation This function checks if the tmp_file_path is set
* @return bool True if the tmp_file_path is set, false otherwise
* @see is_temp_file_path_set()
* @see store_tmp_file()
* @see generate_tmp_file()
*/
private function is_temp_file_path_set(): bool
{
// Check if the tmp_file_path is set
if (!empty($this->tmp_file_path)) {
return true;
}
return false;
}
/**
* Generate a unique ID for the tmp file
* @notation This function generates a unique ID for the tmp file
* @return string The unique ID for the tmp file
*/
private function generate_tmp_file_unique_id(): string
{
// Generate a unique ID for the tmp file (numbers only)
$unique_id = uniqid();
// Set the unique ID for the tmp file
$this->tmp_file_unique_id = (string)$unique_id;
return $this->tmp_file_unique_id;
}
/**
* Get the path to the tmp file
* @notation This function gets the path to the tmp file
* @return string The path to the tmp file
* @throws Exception If the tmp_file_path is not set
*/
public function get_temp_file_path(): string
{
// Check if the tmp_file_path is set
if (!self::is_temp_file_path_set()) {
throw new Exception('The tmp_file_path is not set, cannot get unknown file');
}
return $this->tmp_file_path;
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
namespace classes;
use interfaces\minio_pdfs_i;
use traits\minio_t;
class pdf_store implements minio_pdfs_i
{
use minio_t;
public function __construct()
{
self::setBucket('pdfs'); // Change the bucket to 'pdfs'
}
/**
* @inheritDoc
*/
public function pdf_exists(int $pdf_id): bool
{
// Check if the file exists
$objects = self::getS3Client()->listObjects([
'Bucket' => self::getBucket(),
'Prefix' => self::get_pdf_key_name($pdf_id)
]);
return count($objects['Contents'] ?? []) > 0;
}
/**
* @inheritDoc
*/
public function get_pdf_key_name(string $id): string
{
// Generate the PDF key name
return 'pdf_' . $id . '.pdf';
}
public function getDownloadUrl(int $id): string
{
return self::getPresignedUrl(self::get_pdf_key_name($id));
}
/**
* @param string $file
* @return string The path to the downloaded file
*/
public function download(string $file): string
{
$path = '/tmp/' . $file;
$result = self::getS3Client()->getObject([
'Bucket' => self::getBucket(),
'Key' => $file,
'SaveAs' => $path
]);
return $path;
}
public function isFileInStore(string $file): bool
{
return self::getS3Client()->doesObjectExist(self::getBucket(), $file);
}
/**
* @inheritDoc
*/
public function upload(string $pdf_id, string $file_path): string
{
// Upload the file to the Minio bucket
return self::uploadFile(
self::get_pdf_key_name($pdf_id),
$file_path
);
}
}
+2
View File
@@ -49,6 +49,7 @@ require_once 'classes/request.php';
require_once 'classes/ratelimit.php';
require_once 'classes/wash_certificate_store.php';
require_once 'classes/invoice_store.php';
require_once 'classes/pdf_store.php';
require_once 'classes/redis.php';
require_once 'classes/slack.php';
require_once 'classes/wordpress_bookings_remote.php';
@@ -61,6 +62,7 @@ require_once 'classes/backup_store.php';
require_once 'classes/motorapi.php';
require_once 'classes/stripe.php';
require_once 'classes/form.php';
require_once 'classes/pdf_generator.php';
/**
* Modules
@@ -0,0 +1,28 @@
<?php
namespace interfaces;
interface minio_pdfs_i
{
/**
* Check if a PDF file exists in the Minio bucket
* @param int $pdf_id
* @return bool
*/
public function pdf_exists(int $pdf_id): bool;
/**
* Upload a PDF file to the Minio bucket
* @param string $pdf_id (e.g. 123)
* @param string $file_path (e.g. /tmp/test.pdf)
* @return string
*/
public function upload(string $pdf_id, string $file_path): string;
/**
* Get the pdf key name for a given pdf id (E.g. pdf_123.pdf)
* @param string $id (e.g. 67d4043850e78 )
* @return string
*/
public function get_pdf_key_name(string $id): string;
}
@@ -0,0 +1,67 @@
<?php
namespace interfaces;
use Exception;
interface pdf_generator_i
{
/**
* Add the HTML content to be converted to PDF
* @param string $html HTML content to be converted to PDF
* @return self
*/
public function add_html(string $html): self;
/**
* Set the filename to save the PDF as
* @param string|null $filename Filename to save the PDF as
* @return self
*/
public function set_filename(string|null $filename): self;
/**
* Generate the PDF and save it to the specified path
* @return string Path to the generated PDF file
*/
public function generate_pdf(): string;
/**
* The function to check if a file is writeable
* @param string $path Path to the file
* @return bool True if the file is writeable, false otherwise
*/
public function is_writeable(string $path): bool;
/**
* The function to validate the paths
* This function checks if the paths are valid and writeable
* @notation This function is used to validate the paths before generating the PDF
* @param array $paths Array of paths to validate (e.g. ['var/tmp', 'var/log'])
* @return bool True if the paths are valid, false otherwise
*/
public function validate_paths(array $paths): bool;
/**
* The function to require valid paths
* @param array $paths Array of paths to validate (e.g. ['var/tmp', 'var/log'])
* @return bool True if the paths are valid, false otherwise
* @throws Exception If the paths are not valid
*/
public function require_valid_paths(array $paths): bool;
/**
* Generate the tmp file location
* @notation This function creates a place to temporarily store the PDF file
* @return self
* @throws Exception If the tmp file location cannot be generated
*/
public function generate_tmp_file(): self;
/**
* Store the PDF file in persistent storage
* @return pdf_generator_i Path to the stored PDF file
* @throws Exception If the PDF file cannot be stored
*/
public function store_tmp_file(): self;
}
@@ -0,0 +1,23 @@
# HTML2PDF MODULE
### This module is used to convert HTML to PDF using the html2pdf library.
#### Repository: https://github.com/spipu/html2pdf/
### What does it do?
- Converts HTML to PDF using the html2pdf library.
- Automatically stores the generated PDF in the specified directory. (temporary directory)
- Sends the generated PDF to the minio / s3 bucket.
- Downloads the generated PDF to the local container, when the user requests it. (This is to ensure that the user can
download the PDF even if the file is not stored in the local machine)
- Sends the generated PDF to the user as a response to the request.
### Requirements
- PHP 7.2 or higher
- Composer
- HTML2PDF library
- TCPDF library
- The `./tmp` directory must be writable by the web server user
- The `./tmp` directory must be writable by the user running the PHP script
@@ -0,0 +1,247 @@
<?php
namespace html2pdf\helpers;
require_once WD . '/modules/html2pdf/helpers/html2pdf_template_i.php';
require_once WD . '/modules/html2pdf/helpers/html2pdf_template_t.php';
require_once WD . '/modules/html2pdf/helpers/html2pdf_template_styles.php';
abstract class html2pdf_template extends html2pdf_template_styles implements html2pdf_template_i
{
use html2pdf_template_t;
protected array $data = [];
protected array $company = [
'name' => 'Truck Wash',
'address' => '123 Truck Wash Lane',
'zip' => 12345,
'city' => 'Truck City',
// The prefix for the phone number (e.g. 45 for +45)
'phone_prefix' => 45,
// The phone number without the prefix (e.g. 12345678)
'phone' => 12345678,
'email' => 'email@example.com',
'website' => 'www.truckwash.com',
'images' => [
'logo' => 'path/to/logo.png',
'banner' => 'path/to/banner.png',
'signature' => 'path/to/signature.png',
],
];
public function __construct($data = null)
{
// Constructor code here
if ($data) {
$this->data = $data;
}
}
/**
* Add data to the template
* @param array $data Data to add
* @return self
*/
public function addData(array $data): self
{
$this->data = array_merge($this->data, $data);
return $this;
}
/**
* Set the company data
* @param array $company Company data
* @notation The company data is an associative array with the following keys:
* - name: The name of the company
* - address: The address of the company
* - zip: The zip code of the company
* - city: The city of the company
* - phone_prefix: The prefix for the phone number (e.g. 45 for +45)
* - phone: The phone number without the prefix (e.g. 12345678)
* - email: The email address of the company
* - website: The website of the company
* - images: An associative array with the following keys:
* - logo: The path to the logo image (e.g. path/to/logo.png)
* - banner: The path to the banner image (e.g. path/to/banner.png)
* - signature: The path to the signature image (e.g. path/to/signature.png)
* @return self
*/
public function setCompany(array $company): self
{
$this->company = array_merge($this->company, $company);
return $this;
}
/**
* Get the HTML content for the template
* @return string HTML content
*/
abstract public function getHtml(): string;
/**
* Set a key-value pair in the template data
* @param string $key Key
* @return string|null Value, or null if not set
*/
public function getKey(string $key): string|null
{
return $this->data[$key] ?? null;
}
/**
* Get the company logo image path
* @return string Company logo image path (e.g. path/to/logo.png)
*/
public function getCompanyLogo(): string
{
return $this->company['images']['logo'];
}
/**
* Get the issuer company details and logo for the template
* @return string HTML header
*/
public function getIssuerCompany(): string
{
return '
<table>
<tr>
<td style="width: 50%; text-align: left;">
<h1>' . self::getCompanyName() . '</h1>
<p>' . self::getCompanyAddress() . '</p>
<p>' . self::getCompanyZip() . ' ' . self::getCompanyCity() . '</p>
<p>Phone: +' . self::getCompanyPhoneCountryCode() . ' ' . self::getCompanyPhone() . '</p>
<p>Email: ' . self::getCompanyEmail() . '</p>
<p>Website: ' . self::getCompanyWebsite() . '</p>
</td>
<td style="width: 50%; text-align: right;">
' . $this->addImage($this->pathSrc(self::getCompanyBanner()), 'Company Logo', 50, 250, 'right') . '
</td>
</tr>
</table>
';
}
/**
* Get the company name
* @return string Company name
*/
public function getCompanyName(): string
{
return $this->company['name'];
}
/**
* Get the company address
* @return string Company address
*/
public function getCompanyAddress(): string
{
return $this->company['address'];
}
/**
* Get the company zip code
* @return int Company zip code
*/
public function getCompanyZip(): int
{
return $this->company['zip'];
}
/**
* Get the company city
* @return string Company city
*/
public function getCompanyCity(): string
{
return $this->company['city'];
}
/**
* Get the company phone country code
* @return int Company phone country code (e.g. 45 for +45)
*/
public function getCompanyPhoneCountryCode(): int
{
return $this->company['phone_prefix'];
}
/**
* Get the company phone number
* @return int Company phone number
*/
public function getCompanyPhone(): int
{
return $this->company['phone'];
}
/**
* Get the company email
* @return string Company email
*/
public function getCompanyEmail(): string
{
return $this->company['email'];
}
/**
* Get the company website
* @return string Company website
*/
public function getCompanyWebsite(): string
{
return $this->company['website'];
}
/**
* Get the company banner image path
* @return string Company banner image path (e.g. path/to/banner.png)
*/
public function getCompanyBanner(): string
{
return $this->company['images']['banner'];
}
/**
* Get the signature for the template
* @return string HTML signature
*/
public function getSignature(): string
{
return '
<div style="text-align: center; margin-top: 20px;">
' . $this->addImage($this->pathSrc(self::getCompanySignature()), 'Signature', null, 200, 'center') . '
</div>
';
}
/**
* Get the company signature image path
* @return string Company signature image path (e.g. path/to/signature.png)
*/
public function getCompanySignature(): string
{
return $this->company['images']['signature'];
}
/**
* Get the header for the template
* @param string|null $title Title
* @return string HTML header
*/
public function getHeader(string $title = null): string
{
return '
<table>
<tr>
<td style="width: 50%; text-align: left; padding: 10px; max-height: 50px;">
' . $this->addImage($this->pathSrc(self::getCompanyBanner()), self::getCompanyName() . ' Logo', 50, 250, 'left') . '
</td>
<td style="width: 50%; text-align: right; max-height: 50px;">
' . self::getHeaderTitle($title) . '
</td>
</tr>
</table>
';
}
}
@@ -0,0 +1,26 @@
<?php
namespace html2pdf\helpers;
interface html2pdf_template_i
{
/**
* Add an image to the template
* @param string $imagePath
* @param string $altText
* @param int $height
* @param int $width
* @param string $align
*
* @return string HTML string for the image
*/
public function addImage(string $imagePath, string $altText = '', int $height = 100, int $width = 100, string $align = 'center'): string;
/**
* Get a src path for the template
* @notation This method is used to get the path of e.g. images (e.g. truckwash-banner-white-compressed.png)
* @param string $path The path to the file, relative to the modules src directory.
* @return string The full path to the file. (e.g. /var/www/html/modules/html2pdf/src/truckwash-banner-white-compressed.png)
*/
public function pathSrc(string $path): string;
}
@@ -0,0 +1,106 @@
<?php
namespace html2pdf\helpers;
class html2pdf_template_styles
{
/**
* @var array Styles for different elements
*/
private array $styles = [
'title' => 'font-size: 48px; font-weight: bold; color: #000; text-align: center;',
'subtitle' => 'font-size: 24px; font-weight: normal; color: #555; text-align: center;',
'header' => 'font-size: 36px; font-weight: bold; color: #17375e;',
'footer' => 'font-size: 12px; font-weight: normal; color: #777;',
// Add more styles as needed
'default' => 'font-size: 12px; font-weight: normal; color: #000;',
'content' => 'padding-left: 1rem; padding-right: 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem;',
];
/**
* Set the style for an element
* @param string $element Element name / identifier (E.g. 'title', 'subtitle', 'header', etc.)
* @param string $style CSS styles
*/
public function setStyle(string $element, string $style): void
{
$this->styles[$element] = $style;
}
/**
* Get the title for the template
* @param string|null $title Title
* @param string|null $subtitle Subtitle
* @return string HTML title
*/
public function getTitle(string $title = null, string $subtitle = null): string
{
$html = '';
if (!empty($title)) {
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
$html .= '<h1 style="' . self::getStyle('title') . '">' . $title . '</h1>';
}
if (!empty($subtitle)) {
$subtitle = htmlspecialchars($subtitle, ENT_QUOTES, 'UTF-8');
$html .= '<h2 style="' . self::getStyle('subtitle') . '">' . $subtitle . '</h2>';
}
return $html;
}
/**
* Get the style for an element
* @param string $element Element name / identifier (E.g. 'title', 'subtitle', 'header', etc.)
* @return string CSS styles
*/
public function getStyle(string $element): string
{
return $this->styles[$element] ?? $this->styles['default'];
}
/**
* Get the header title for the template
* @param string|null $title Title
* @return string HTML header title
*/
public function getHeaderTitle(string $title = null): string
{
$html = '';
if (!empty($title)) {
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
$html .= '<span style="' . self::getStyle('header') . '">' . $title . '</span>';
}
return $html;
}
/**
* Get the CSS (default) styles for the template
* @return string CSS styles
*/
public function getDefaultStyles(): string
{
return '
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
color: #333;
}
h1 {
font-size: 24px;
margin-bottom: 10px;
}
p {
margin: 5px 0;
}
table {
width: 100%;
border-collapse: collapse;
}
td {
padding: 10px;
vertical-align: top;
}
</style>
';
}
}
@@ -0,0 +1,38 @@
<?php
namespace html2pdf\helpers;
trait html2pdf_template_t
{
/**
* @inheritDoc
*/
public function addImage(string $imagePath, string $altText = '', int|null $height = 100, int|null $width = 100, string $align = 'center'): string
{
// Validate the image path (Local, then URL)
if (!file_exists($imagePath)) {
if (filter_var($imagePath, FILTER_VALIDATE_URL) === false) {
throw new \InvalidArgumentException("Invalid image path: $imagePath");
}
}
// Validate the height and width
if (empty($height)) {
$height = 'auto';
}
if (empty($width)) {
$width = 'auto';
}
// Generate the HTML for the image
$style = "height: {$height}px; width: {$width}px; text-align: {$align};";
return "<img src='{$imagePath}' alt='{$altText}' style='max-height: {$height}px; max-width: {$width}px; {$style}' />";
}
public function pathSrc(string $path): string
{
// Assuming the path is relative to the module directory
return WD . '/modules/html2pdf/src/' . $path;
}
}
@@ -0,0 +1,41 @@
<?php
namespace html2pdf;
require_once WD . '/modules/html2pdf/html2pdf_templates_i.php';
require_once WD . '/modules/html2pdf/helpers/html2pdf_template.php';
/** Template classes */
require_once WD . '/modules/html2pdf/templates/wash_certificate.php';
use Exception;
use html2pdf\helpers\html2pdf_template;
class html2pdf_templates implements html2pdf_templates_i
{
/**
* Get the template with the given name, and optionally pass data to it
* @param string $templateName Template name
* @param array|null $data Data to pass to the template
* @return html2pdf_template Template object
* @throws Exception If the template class does not exist
*/
public static function getTemplate(string $templateName, array $data = null): html2pdf_template
{
$className = self::getTemplateClass($templateName);
if (!class_exists($className)) {
throw new Exception('Template class does not exist: ' . $className);
}
return new $className($data);
}
/**
* Get the template class name based on the template name
* @param string $templateName Template name
* @return string Class name of the template
*/
public static function getTemplateClass(string $templateName): string
{
return 'html2pdf\\templates\\' . $templateName;
}
}
@@ -0,0 +1,8 @@
<?php
namespace html2pdf;
interface html2pdf_templates_i
{
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@@ -0,0 +1,179 @@
<?php
namespace html2pdf\templates;
use html2pdf\helpers\html2pdf_template;
class wash_certificate extends html2pdf_template
{
/**
* @inheritDoc
*/
public function getHtml($data = null): string
{
// self::addImage(self::pathSrc('truckwash-banner-white-compressed.png'), 'Certificate Image', 100, 100, 'center');
/** Add the styles */
$html = self::getDefaultStyles();
/** Add the header */
$html .= self::getHeader();
/** Add the issuer company */
//$html .= self::getIssuerCompany();
/** Open the content div */
$html .= '<div style="' . self::getStyle('content') . '">';
/** Add the title */
$html .= self::getTitle('Wash Certificate');
/** Add the seal number */
$html .= self::getSealNumber();
/** Add the registration numbers, time, date and the carried out by */
$html .= self::getDetails();
/** Add the provider details */
$html .= self::getProviderDetails();
/** Add the regarding this document */
$html .= self::getRegardingThisDocument('DK');
/** Add the regarding this document in English */
$html .= self::getRegardingThisDocument('EN');
/** Add the signature */
$html .= self::getSignature();
/** Close the content div */
$html .= '</div>';
return $html;
}
/**
* Get the seal number for the wash certificate
* @notation This method is used to generate the seal number for the wash certificate.
* @return string HTML table
* @see addData() - This method is used to add data to the template.
*/
public function getSealNumber(): string
{
return '
<table style="width: 80%; border-collapse: collapse; margin-top: 20px; margin-left: 10%; margin-right: 10%; align-content: space-between;">
<tr>
<!-- Seal number -->
<td style="width: 100%; padding: 10px; align-content: center; text-align: center">
<strong>SEAL/PLOM number</strong> <br>' . htmlspecialchars($this->getKey('seal_number'), ENT_QUOTES, 'UTF-8') . '
</td>
</tr>
</table>
';
}
/**
* Get the HTML details for the wash certificate
* @notation This method is used to generate the details of the wash certificate. (E.g. registration numbers, time, date and the carried out by)
* @return string HTML table
* @see addData() - This method is used to add data to the template.
*/
public function getDetails(): string
{
return '
<table style="width: 80%; border-collapse: collapse; margin-left: 10%; margin-right: 10%; align-content: space-between;">
<tr>
<!-- Customer name -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Company name</strong> <br>' . htmlspecialchars($this->getKey('customer_name'), ENT_QUOTES, 'UTF-8') . '
</td>
<!-- Reg number 1 -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Reg.no.</strong> <br>' . htmlspecialchars($this->getKey('reg_1'), ENT_QUOTES, 'UTF-8') . '
</td>
<!-- Date -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Date</strong> <br>' . htmlspecialchars($this->getKey('time'), ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars($this->getKey('date'), ENT_QUOTES, 'UTF-8') . '
</td>
</tr>
<tr>
<!-- Type -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Type</strong> <br>' . htmlspecialchars($this->getKey('type'), ENT_QUOTES, 'UTF-8') . '
</td>
<!-- Reg number 2 -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Trailerno.</strong> <br>' . htmlspecialchars($this->getKey('reg_2'), ENT_QUOTES, 'UTF-8') . '
</td>
<!-- Time -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Time</strong> <br>' . htmlspecialchars($this->getKey('time'), ENT_QUOTES, 'UTF-8') . '
</td>
</tr>
</table>
';
}
/**
* Get the HTML provider details for the wash certificate
* @notation This method is used to generate the provider details of the wash certificate. (E.g. department, company name, address, zip, city, phone prefix, phone, email and website)
* @return string HTML table
* @see addData() - This method is used to add data to the template.
*/
public function getProviderDetails(): string
{
return '
<table style="width: 80%; border-collapse: collapse; margin-left: 10%; margin-right: 10%; align-content: space-evenly;">
<tr>
<!-- Service provider -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Service Provider</strong>
<br>' . self::getCompanyName() . '
<br>' . self::getCompanyAddress() . '
<br>' . self::getCompanyZip() . ' ' . self::getCompanyCity() . '
</td>
<!-- Contact details -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Contact Details</strong>
<br>+' . self::getCompanyPhoneCountryCode() . ' ' . self::getCompanyPhone() . '
<br>' . self::getCompanyEmail() . '
</td>
<!-- Operator -->
<td style="width: 33%; padding: 10px; align-content: center; text-align: center">
<strong>Carried Out By</strong>
<br>' . htmlspecialchars($this->getKey('carried_out_by'), ENT_QUOTES, 'UTF-8') . '
</td>
</tr>
</table>
';
}
/**
* Get the regarding this document
* @notation This method is used to generate the regarding this document.
* @param string $language Language code (e.g. 'DK', 'EN', etc.)
* @return string HTML table
*/
public function getRegardingThisDocument(string $language = 'DK'): string
{
$translations = [
'DK' => [
'Angående dette dokument',
'Der kvitteres herved for udførelse af indvendig vask af denne trailer. Vasken er udført med en godkendt sæbe til formålet samt afskyllet med vand bagefter.',
'Der er udført egenkontrol af vasken, Herved bekræftes det at vasken er udført optimalt.',
'Datablade kan rekvireres hos Copenhagen Truck Wash.',
'Bakterielle prøver bør tages umiddelbart efter vask, dog max 3 timer efter. Prøven skal tages på et tørt sted og ikke på gulvet',
],
'EN' => [
'Regarding this document',
'This is hereby confirmed for the performance of internal washing of this trailer. The wash has been performed with an approved soap for the purpose - and rinsed with water afterwards.',
'Self-control of the wash has been performed, hereby confirming that the wash has been performed optimally.',
'Data sheets can be requested from Copenhagen Truck Wash.',
'Bacterial samples should be taken immediately after washing, but no later than 3 hours after. The sample should be taken in a dry place and not on the floor.',
],
];
return '
<table style="width: 80%; border-collapse: collapse; margin-top: 20px; margin-left: 10%; margin-right: 10%; align-content: space-between;">
<tr>
<!-- Regarding this document -->
<td style="width: 100%; padding: 10px; align-content: center; text-align: left">
<strong>' . htmlspecialchars($translations[$language][0], ENT_QUOTES, 'UTF-8') . '</strong>
<br>' . htmlspecialchars($translations[$language][1], ENT_QUOTES, 'UTF-8') . '
<br>' . htmlspecialchars($translations[$language][2], ENT_QUOTES, 'UTF-8') . '
<br>' . htmlspecialchars($translations[$language][3], ENT_QUOTES, 'UTF-8') . '
<br>' . htmlspecialchars($translations[$language][4], ENT_QUOTES, 'UTF-8') . '
</td>
</tr>
</table>
';
}
}
@@ -0,0 +1,72 @@
<?php
namespace routes;
use classes\pdf_generator;
use classes\response;
use classes\router;
use objects\logs_o;
use traits\route_t;
class pdfGeneratorRoute
{
use route_t;
public function run(): void
{
global /** @var response $response */
/** @var router $router */
$router, $response;
/** PDF Generator > GET */
$this->get('/modules/pdf-generator/test', function () {
global $response;
//self::requirePermission('modules_pdf_generator_test');
if (true) {
//(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'LIST_COLLECTED_INVOICES', 'User accessed the list of collected order invoices');
$pdf_generator = new pdf_generator();
$pdf_generator->add_html($pdf_generator->templates->getTemplate('wash_certificate')
->setCompany([
'name' => 'Truck Wash',
'address' => 'Letland Allé 2',
'zip' => 2630,
'city' => 'Taastrup',
'phone_prefix' => 45,
'phone' => 43717886,
'email' => 'cph@truckwash.dk',
'website' => 'www.truckwash.dk',
'images' => [
'logo' => '/truckwash-banner-png.png',
'banner' => '/truckwash-banner-png.png',
'signature' => '/truckwash-underskrift.png',
],
])
->addData([
'seal_number' => 123456,
'reg_1' => 'EC21233',
'reg_2' => 'FB1703',
'date' => '2023-10-01',
'time' => '12:00',
'carried_out_by' => 'John Doe',
'department_id' => 1,
'customer_name' => 'Customer Name',
'type' => 'Interior Cleaning',
])
->getHtml()
);
$pdf_path = $pdf_generator->generate_pdf();
$response->success([
'pdf_path' => $pdf_path,
'message' => 'PDF generated successfully'
]);
} else {
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES', 'User tried to access the list of collected order invoices without a valid session');
$response->error('Invalid session', 400);
}
},
[
'list_collected_invoices' => 'List ALL collected order invoices. This is a superuser-only route.'
]
);
}
}