Feat: Implement contract generation and up-/downloading

This commit is contained in:
Björn Fromme
2023-10-11 17:47:06 +02:00
parent 7ecacd7c78
commit f0911f57aa
13 changed files with 421 additions and 10 deletions
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Service\Pdf;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
abstract class AbstractPdfRenderer
{
protected CacheItemPoolInterface|ArrayAdapter $cache;
protected int $B = 0;
protected int $I = 0;
protected int $U = 0;
protected array $config;
public function __construct(protected readonly TranslatorInterface $translator, array $options)
{
$optionsResolver = new OptionsResolver();
$optionsResolver
->setRequired('project_dir')
->setAllowedTypes('project_dir', 'string')
;
$this->config = $optionsResolver->resolve($options);
// Static cache without serialization
$this->cache = new ArrayAdapter(0, false);
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
namespace App\Service\Pdf;
use App\Entity\Disposition;
class ContractRenderer extends AbstractPdfRenderer
{
public function render(Disposition $disposition): Pdf
{
$pdf = new Pdf();
$pdf->SetAuthor('Continentale', true);
$pdf->SetCreator('Continentale', true);
// Load template
$pdfTemplate = sprintf('%s/assets/pdf/contract.pdf', $this->config['project_dir']);
$numberOfPages = $pdf->appendPdf($pdfTemplate);
$pdf->setPage(1);
$pdf->SetFont('Arial', '', 10);
$teamer = $disposition->getTeamer();
$assignment = $disposition->getAssignment();
$destination = $assignment->getDestination();
// Current date
$date = (new \DateTimeImmutable())->format('d.m.Y');
$pdf->Text(164,43, utf8_decode($date));
// Name
$pdf->Text(45,67.75, utf8_decode($teamer));
// Address
$pdf->Text(45,77.75, utf8_decode($teamer->getAddress()));
// Jobprofile
$pdf->Text(21,104.5, utf8_decode($assignment->getJobProfile()->getName()));
// Period
$dateFrom = $assignment->getTotalPeriod()->start->format('d.m.Y');
$dateTo = $assignment->getTotalPeriod()->end->format('d.m.Y');
$period = sprintf('%s - %s', $dateFrom, $dateTo);
$pdf->Text(57,113, $period);
// Destination
$pdf->Text(57,121.5, utf8_decode(sprintf('%s, %s', $destination->getProduct(), $destination->getHotel())));
// Set pointer to last page to include all
$pdf->setPage($numberOfPages);
return $pdf;
}
}
+120
View File
@@ -0,0 +1,120 @@
<?php
namespace App\Service\Pdf;
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;
use setasign\Fpdi\PdfReader\PdfReaderException;
/**
* Functionality to center image on PDF page adapted from
* https://gist.github.com/benshimmin/4088493?permalink_comment_id=2398423#gistcomment-2398423.
*
* Functionality to append pages from external PDF file adapted from
* https://stackoverflow.com/questions/22404601/merging-pdf-files-with-php-fpdi/29552294#29552294
*
* Requires commercial FPDI PDF-Parser addon to parse compressed PDF files.
*/
class Pdf extends Fpdi
{
public const DPI = 300;
public const MM_IN_INCH = 25.4;
public const A4_HEIGHT = 297;
public const A4_WIDTH = 210;
public const MARGIN_X = 10;
public const MARGIN_Y = 10;
public function setPage(int $pageNumber): void
{
$this->page = $pageNumber;
}
public function appendPdf(string $sourceFile): int
{
try {
$pageCount = $this->setSourceFile($sourceFile);
for ($page = 1; $page <= $pageCount; ++$page) {
$templateId = $this->importPage($page);
$size = $this->getTemplateSize($templateId);
$this->AddPage($size['orientation'], [$size['width'], $size['height']]);
$this->useTemplate($templateId);
}
return $pageCount;
} catch (PdfParserException|PdfReaderException $e) {
$this->AddPage();
$this->SetFont('Arial', '', 10);
$this->Text(self::MARGIN_X, self::MARGIN_Y + 10, 'PDF-Fehler: '.$e->getMessage());
return 1;
}
}
public function appendImage(string $sourceFile, string $pageTitle = ''): void
{
$this->AddPage();
$containerWidth = self::A4_WIDTH - self::MARGIN_X * 2;
$containerHeight = self::A4_HEIGHT - self::MARGIN_Y * 3;
$this->centerImage(
$sourceFile,
self::MARGIN_X,
self::MARGIN_Y * 2,
$containerWidth,
$containerHeight
);
if ($pageTitle) {
$this->SetFont('Arial', '', 10);
$this->Text(self::MARGIN_X, self::MARGIN_Y, utf8_decode($pageTitle));
}
}
public function centerImage(
string $imgPath,
int $x = 0,
int $y = 0,
int $containerWidth = self::A4_WIDTH,
int $containerHeight = self::A4_HEIGHT
): void {
[$width, $height] = $this->resizeToFit($imgPath, $containerWidth, $containerHeight);
try {
$this->Image(
$imgPath,
$x + ($containerWidth - $width) / 2,
$y + ($containerHeight - $height) / 2,
$width,
$height
);
} catch (\Exception $e) {
$this->SetFont('Arial', '', 10);
$this->Text(self::MARGIN_X, self::MARGIN_Y + 10, 'PDF-Fehler: '.$e->getMessage());
}
}
protected function pixelsToMm($val): int
{
return (int) (round($val * $this::MM_IN_INCH / self::DPI));
}
protected function mmToPixels($val): int
{
return (int) (round($this::DPI * $val / self::MM_IN_INCH));
}
protected function resizeToFit(
string $imgPath,
int $maxWidth = self::A4_WIDTH,
int $maxHeight = self::A4_HEIGHT
): array {
[$width, $height] = getimagesize($imgPath);
$widthScale = $this->mmToPixels($maxWidth) / $width;
$heightScale = $this->mmToPixels($maxHeight) / $height;
$scale = min($widthScale, $heightScale);
return [
$this->pixelsToMm($scale * $width),
$this->pixelsToMm($scale * $height),
];
}
}