YetiForceCompany/YetiForceCRM

View on GitHub
app/Pdf/Drivers/YetiForcePDF.php

Summary

Maintainability
B
6 hrs
Test Coverage
B
86%
<?php

/**
 * YetiForcePDF driver file for PDF generation.
 *
 * @package App\Pdf
 *
 * @copyright YetiForce S.A.
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
 * @author    Rafal Pospiech <r.pospiech@yetifoce.com>
 * @author    Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
 * @author      Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
 */

namespace App\Pdf\Drivers;

/**
 * YetiForcePDF driver class for PDF generation.
 */
class YetiForcePDF extends Base
{
    /** {@inheritdoc} */
    const DRIVER_NAME = 'LBL_YETIFORCE_PDF';

    /** @var string Default font. */
    protected $font = 'DejaVu Sans';

    /** @var int Default font size */
    protected $fontSize = 10;

    /** @var \YetiForcePDF\Document PDF generator instance. */
    protected $pdf;

    /** {@inheritdoc} */
    public static function isActive(): bool
    {
        return true;
    }

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->setInputCharset(\App\Config::main('default_charset') ?? 'UTF-8');
        $this->pdf = (new \YetiForcePDF\Document())->init();
    }

    /** {@inheritdoc} */
    public function setTopMargin(float $margin)
    {
        $this->pdf->setDefaultTopMargin($margin);
        $this->defaultMargins['top'] = $margin;
        return $this;
    }

    /** {@inheritdoc} */
    public function setBottomMargin(float $margin)
    {
        $this->pdf->setDefaultBottomMargin((float) $margin);
        $this->defaultMargins['bottom'] = $margin;
        return $this;
    }

    /**
     * Set left margin.
     *
     * @param float $margin
     */
    public function setLeftMargin(float $margin)
    {
        $this->pdf->setDefaultLeftMargin((float) $margin);
        $this->defaultMargins['left'] = $margin;
        return $this;
    }

    /** {@inheritdoc} */
    public function setRightMargin(float $margin)
    {
        $this->pdf->setDefaultRightMargin((float) $margin);
        $this->defaultMargins['right'] = $margin;
        return $this;
    }

    /** {@inheritdoc} */
    public function setHeaderMargin(float $margin)
    {
        $this->headerMargin = $margin;
        return $this;
    }

    /** {@inheritdoc} */
    public function setFooterMargin(float $margin)
    {
        $this->footerMargin = $margin;
        return $this;
    }

    /** {@inheritdoc} */
    public function setMargins(array $margins)
    {
        $this->setTopMargin($margins['top'] ?? $this->defaultMargins['top']);
        $this->setBottomMargin($margins['bottom'] ?? $this->defaultMargins['bottom']);
        $this->setLeftMargin($margins['left'] ?? $this->defaultMargins['left']);
        $this->setRightMargin($margins['right'] ?? $this->defaultMargins['right']);
        $this->setHeaderMargin($margins['header'] ?? $this->defaultMargins['header']);
        $this->setFooterMargin($margins['footer'] ?? $this->defaultMargins['footer']);
        return $this;
    }

    /** {@inheritdoc} */
    public function setPageSize(string $format, string $orientation = null)
    {
        $this->pdf->setDefaultFormat($format);
        if ($orientation) {
            $this->pdf->setDefaultOrientation($orientation);
        }
        return $this;
    }

    /** {@inheritdoc} */
    public function setTitle(string $title)
    {
        $this->pdf->getMeta()->setTitle($title);
        return $this;
    }

    /** {@inheritdoc} */
    public function setAuthor(string $author)
    {
        $this->pdf->getMeta()->setAuthor($author);
        return $this;
    }

    /** {@inheritdoc} */
    public function setCreator(string $creator)
    {
        $this->pdf->getMeta()->setCreator($creator);
        return $this;
    }

    /** {@inheritdoc} */
    public function setSubject(string $subject)
    {
        $this->pdf->getMeta()->setSubject($subject);
        return $this;
    }

    /** {@inheritdoc} */
    public function setKeywords(array $keywords)
    {
        $this->pdf->getMeta()->setKeywords($keywords);
        return $this;
    }

    /** {@inheritdoc} */
    public function setHeader(string $headerHtml)
    {
        $this->header = trim($headerHtml);
        return $this;
    }

    /** {@inheritdoc} */
    public function setFooter(string $footerHtml)
    {
        $this->footer = trim($footerHtml);
        return $this;
    }

    /**
     * Write html.
     *
     * @return $this
     */
    public function writeHTML()
    {
        $this->loadCustomFonts();
        $this->pdf->loadHtml($this->getHtml(), $this->charset);
        return $this;
    }

    /**
     * Gets full html.
     *
     * @return string
     */
    public function getHtml(): string
    {
        $html = $this->watermark ? $this->wrapWatermark($this->watermark) : '';
        $html .= $this->header ? $this->wrapHeaderContent($this->header) : '';
        $html .= $this->getBody();
        $html .= $this->footer ? $this->wrapFooterContent($this->footer) : '';
        return $html;
    }

    /**
     * Wrap header content.
     *
     * @param string $content
     *
     * @return string
     */
    public function wrapHeaderContent(string $content): string
    {
        $style = "padding-top:{$this->headerMargin}px; padding-left:{$this->defaultMargins['left']}px; padding-right:{$this->defaultMargins['right']}px";
        return '<div id="header" data-header style="' . $style . '">' . $content . '</div>';
    }

    /**
     * Wrap footer content.
     *
     * @param string $content
     *
     * @return string
     */
    public function wrapFooterContent(string $content): string
    {
        $style = "padding-bottom:{$this->footerMargin}px; padding-left:{$this->defaultMargins['left']}px; padding-right:{$this->defaultMargins['right']}px";
        // Modification of the following condition will violate the license!
        if (!\App\YetiForce\Shop::check('YetiForceDisableBranding')) {
            $content .= '<table style="font-size:6px;width:100%; margin: 0;"><tbody><tr><td style="width:50%">Powered by YetiForce</td></tr></tbody></table>';
        }
        // Modification of the following condition will violate the license!
        return '<div id="footer" data-footer style="' . $style . '">' . $content . '</div>';
    }

    /**
     * Wrap watermark.
     *
     * @param string $watermarkContent
     *
     * @return string
     */
    public function wrapWatermark(string $watermarkContent): string
    {
        return '<div id="watermark" data-watermark style="text-align:center">' . $watermarkContent . '</div>';
    }

    /**
     * Load custom fonts.
     *
     * @return $this
     */
    private function loadCustomFonts()
    {
        $fontsDir = 'layouts' . \DIRECTORY_SEPARATOR . 'resources' . \DIRECTORY_SEPARATOR . 'fonts' . \DIRECTORY_SEPARATOR;
        $resolvedDir = \Vtiger_Loader::resolveNameToPath('~' . $fontsDir, 'css');
        $customFonts = \App\Json::read($resolvedDir . 'fonts.json');
        foreach ($customFonts as &$font) {
            $font['file'] = $resolvedDir . $font['file'];
        }
        \YetiForcePDF\Document::addFonts($customFonts);
        return $this;
    }

    /** {@inheritdoc} */
    public function loadWatermark()
    {
        $this->watermark = '';
        if (self::WATERMARK_TYPE_IMAGE === $this->template->get('watermark_type') && '' !== trim($this->template->get('watermark_image'))) {
            if ($this->template->get('watermark_image')) {
                $this->watermark = '<img src="' . $this->template->get('watermark_image') . '" style="opacity:0.1;">';
            }
        } elseif (self::WATERMARK_TYPE_TEXT === $this->template->get('watermark_type') && '' !== trim($this->template->get('watermark_text'))) {
            $this->watermark = '<div style="opacity:0.1;display:inline-block;">' . $this->template->parseVariables($this->template->get('watermark_text')) . '</div>';
        }
        return $this;
    }

    /** {@inheritdoc} */
    public function output($fileName = '', $mode = 'D'): void
    {
        if (empty($fileName)) {
            $fileName = ($this->getFileName() ?: time()) . '.pdf';
        }
        $this->writeHTML();
        $output = $this->pdf->render();
        if ('I' !== $mode && 'D' !== $mode) {
            file_put_contents($fileName, $output);
            return;
        }
        $destination = 'I' === $mode ? 'inline' : 'attachment';
        header('accept-charset: utf-8');
        header('content-type: application/pdf; charset=utf-8');
        $basename = \App\Fields\File::sanitizeUploadFileName($fileName);
        header("content-disposition: {$destination}; filename=\"{$basename}\"");
        echo $output;
    }
}