Untitled

mail@pastecode.io avatar
unknown
php
a year ago
6.5 kB
4
Indexable
Never
<?php

namespace App\Pdf;

use App\Config\Config;
use App\Environment\EnvironmentProvider;
use App\Exception\InvalidArgumentException;
use App\Exception\RuntimeException;
use App\Filesystem\TempDirectory;
use App\Filesystem\TempFile;
use App\Locale\Locale;
use App\Locale\LocaleProvider;
use App\Pdf\Exception\PdfException;
use App\Request\RequestProvider;
use Doctrine\ORM\EntityManagerInterface;
use Mpdf\Mpdf;
use Mpdf\MpdfException;
use Mpdf\Output\Destination;
use Symfony\Component\Asset\Packages;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Translation\LocaleSwitcher;
use Symfony\Contracts\Translation\TranslatorInterface;
use Throwable;
use Twig\Environment as Renderer;

abstract class Pdf
{
    protected array $mpdfBaseOptions = [
        'anchor2Bookmark' => 1,
        'mode' => 'utf-8',
        'format' => 'A4',
        'allow_charset_conversion' => false,
    ];

    /** @var array<string, mixed> */
    protected array $templateParameters = [];
    protected string $template;
    protected EntityManagerInterface $em;
    protected Config $config;
    protected ParameterBagInterface $parameterBag;
    protected RequestProvider $requestProvider;
    protected LocaleProvider $localeProvider;
    protected EnvironmentProvider $environmentProvider;
    protected TranslatorInterface $translator;
    protected Renderer $renderer;
    protected Packages $packages;
    protected LocaleSwitcher $localeSwitcher;
    protected ?Locale $locale = null;
    protected string $publicDirectory;

    protected const RESERVED_TEMPLATE_PARAM_KEYS = [
        'locale',
    ];

    public function __construct(PdfServiceContainer $container)
    {
        $this->em = $container->getEntityManager();
        $this->config = $container->getConfig();
        $this->parameterBag = $container->getParameterBag();
        $this->requestProvider = $container->getRequestProvider();
        $this->localeProvider = $container->getLocaleProvider();
        $this->environmentProvider = $container->getEnvironmentProvider();
        $this->translator = $container->getTranslator();
        $this->renderer = $container->getRenderer();
        $this->packages = $container->getPackages();
        $this->publicDirectory = $container->getPublicDirectory();
        $this->localeSwitcher = $container->getLocaleSwitcher();
    }

    /**
     * @return array<string, mixed>
     */
    public function getTemplateParameters(): array
    {
        return $this->templateParameters;
    }

    /**
     * @param array<string, mixed> $templateParameters
     * @return $this
     */
    public function setTemplateParameters(array $templateParameters): static
    {
        $this->checkTemplateParameters($templateParameters);
        $this->templateParameters = $templateParameters;
        return $this;
    }

    /**
     * @param string $key
     * @param mixed $value
     * @return $this
     */
    public function addTemplateParameter(string $key, mixed $value): static
    {
        $this->checkTemplateParameterKey($key);
        $this->templateParameters[$key] = $value;
        return $this;
    }

    /**
     * @param string $key
     * @return $this
     */
    public function removeTemplateParameter(string $key): self
    {
        if (isset($this->templateParameters[$key])) {
            unset($this->templateParameters[$key]);
        }
        return $this;
    }

    protected function checkTemplateParameterKey(string $key): void
    {
        if (in_array($key, self::RESERVED_TEMPLATE_PARAM_KEYS, true)) {
            throw new InvalidArgumentException(sprintf('Parameter key "%s" is reserved.', $key));
        }
    }

    /**
     * @param array<string, mixed> $parameters
     */
    protected function checkTemplateParameters(array $parameters): void
    {
        foreach ($parameters as $key => $value) {
            $this->checkTemplateParameterKey($key);
        }
    }

    /**
     * @return string
     */
    public function getTemplate(): string
    {
        return $this->template;
    }

    /**
     * @param string $template
     * @return $this
     */
    public function setTemplate(string $template): self
    {
        $this->template = $template;
        return $this;
    }

    /**
     * @throws MpdfException
     */
    protected function initializeMpdf(): Mpdf
    {
        return new Mpdf($this->assembleMpdfOptions());
    }

    protected function assembleMpdfOptions(): array
    {
        $tempDirectory = new TempDirectory();
        return array_merge(
            [
                'tempDir' => $tempDirectory->getPath(),
            ],
            $this->mpdfBaseOptions
        );
    }

    public function render(): string
    {
        $this->setup();
        try {
            if ($this->locale !== null) {
                return $this->localeSwitcher->runWithLocale($this->locale->getCode(), function (): string {
                    return $this->renderer->render($this->template, $this->assembleTemplateParameters());
                });
            }
            return $this->renderer->render($this->template, $this->assembleTemplateParameters());
        } catch (Throwable $e) {
            throw new RuntimeException($e);
        }
    }

    protected function assembleTemplateParameters(): array
    {
        $templateParameters = $this->templateParameters;
        $this->checkTemplateParameters($templateParameters);
        $templateParameters['locale'] = $this->localeProvider->getLocale();
        return $templateParameters;
    }

    protected function setup(): void
    {
    }

    public function generate(): string
    {
        $this->setup();
        if (!isset($this->template)) {
            throw new RuntimeException('Set property "template" in ' . static::class);
        }
        try {
            $mpdf = $this->initializeMpdf();
            $mpdf->WriteHTML($this->render());
            $path = (new TempFile(extension: 'pdf'))->getRealPath();
            $mpdf->Output($path, Destination::FILE);
            $mpdf->cleanup();
            return $path;
        } catch (Throwable $e) {
            throw new PdfException($e);
        }
    }

    public function __toString(): string
    {
        return $this->render();
    }
}