mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-03 02:27:01 +00:00
pdfa
This commit is contained in:
45
application/Espo/Tools/Pdf/AttachmentProvider.php
Normal file
45
application/Espo/Tools/Pdf/AttachmentProvider.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Tools\Pdf;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
/**
|
||||
* @template TEntity of Entity
|
||||
* @since 9.2.0
|
||||
*/
|
||||
interface AttachmentProvider
|
||||
{
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @return AttachmentWrapper[]
|
||||
*/
|
||||
public function get(Entity $entity, Params $params): array;
|
||||
}
|
||||
53
application/Espo/Tools/Pdf/AttachmentWrapper.php
Normal file
53
application/Espo/Tools/Pdf/AttachmentWrapper.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Tools\Pdf;
|
||||
|
||||
use Espo\Entities\Attachment;
|
||||
|
||||
/**
|
||||
* @since 9.2.0
|
||||
*/
|
||||
readonly class AttachmentWrapper
|
||||
{
|
||||
public function __construct(
|
||||
private Attachment $attachment,
|
||||
private ?string $description = null,
|
||||
) {}
|
||||
|
||||
public function getAttachment(): Attachment
|
||||
{
|
||||
return $this->attachment;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,10 @@ use stdClass;
|
||||
|
||||
class Data
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
/** @var array<string, mixed> */
|
||||
private $additionalTemplateData = [];
|
||||
/** @var AttachmentWrapper[] */
|
||||
private $attachments = [];
|
||||
|
||||
public function getAdditionalTemplateData(): stdClass
|
||||
{
|
||||
@@ -55,6 +55,28 @@ class Data
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AttachmentWrapper[] $attachments
|
||||
*/
|
||||
public function withAttachmentsAdded(array $attachments): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
$obj->attachments[] = $attachment;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AttachmentWrapper[]
|
||||
*/
|
||||
public function getAttachments(): array
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
return new self();
|
||||
|
||||
@@ -30,23 +30,18 @@
|
||||
namespace Espo\Tools\Pdf\Data;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
use Espo\Tools\Pdf\AttachmentProvider;
|
||||
use Espo\Tools\Pdf\Data;
|
||||
use Espo\Tools\Pdf\Params;
|
||||
|
||||
class DataLoaderManager
|
||||
{
|
||||
private Metadata $metadata;
|
||||
private InjectableFactory $injectableFactory;
|
||||
|
||||
public function __construct(Metadata $metadata, InjectableFactory $injectableFactory)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory,
|
||||
) {}
|
||||
|
||||
public function load(Entity $entity, ?Params $params = null, ?Data $data = null): Data
|
||||
{
|
||||
@@ -58,17 +53,29 @@ class DataLoaderManager
|
||||
$data = Data::create();
|
||||
}
|
||||
|
||||
/** @var class-string<DataLoader>[] $classNameList */
|
||||
$classNameList = $this->metadata->get(['pdfDefs', $entity->getEntityType(), 'dataLoaderClassNameList']) ?? [];
|
||||
$defs = $this->metadata->get("pdfDefs.{$entity->getEntityType()}") ?? [];
|
||||
|
||||
foreach ($classNameList as $className) {
|
||||
$loader = $this->createLoader($className);
|
||||
/** @var class-string<DataLoader>[] $loaderClassList */
|
||||
$loaderClassList = $defs['dataLoaderClassNameList'] ?? [];
|
||||
|
||||
$loadedData = $loader->load($entity, $params);
|
||||
foreach ($loaderClassList as $className) {
|
||||
$loadedData = $this->createLoader($className)
|
||||
->load($entity, $params);
|
||||
|
||||
$data = $data->withAdditionalTemplateData($loadedData);
|
||||
}
|
||||
|
||||
/** @var class-string<AttachmentProvider<Entity>>[] $attachmentProviderClassList */
|
||||
$attachmentProviderClassList = $defs['attachmentProviderClassNameList'] ?? [];
|
||||
|
||||
foreach ($attachmentProviderClassList as $className) {
|
||||
$provider = $this->createProvider($className);
|
||||
|
||||
$attachments = $provider->get($entity, $params);
|
||||
|
||||
$data = $data->withAttachmentsAdded($attachments);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -79,4 +86,14 @@ class DataLoaderManager
|
||||
{
|
||||
return $this->injectableFactory->create($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<AttachmentProvider<Entity>> $className
|
||||
* @return AttachmentProvider<Entity>
|
||||
*/
|
||||
private function createProvider(string $className): AttachmentProvider
|
||||
{
|
||||
/** @var AttachmentProvider<Entity> */
|
||||
return $this->injectableFactory->create($className);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Espo\Tools\Pdf\Dompdf;
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Options;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Tools\Pdf\Params;
|
||||
use Espo\Tools\Pdf\Template;
|
||||
|
||||
class DompdfInitializer
|
||||
@@ -41,17 +42,22 @@ class DompdfInitializer
|
||||
private const PT = 2.83465;
|
||||
|
||||
public function __construct(
|
||||
private Config $config
|
||||
private Config $config,
|
||||
) {}
|
||||
|
||||
public function initialize(Template $template): Dompdf
|
||||
public function initialize(Template $template, Params $params): Dompdf
|
||||
{
|
||||
$options = new Options();
|
||||
|
||||
$options->setIsPdfAEnabled($params->isPdfA());
|
||||
$options->setDefaultFont($this->getFontFace($template));
|
||||
|
||||
$pdf = new Dompdf($options);
|
||||
|
||||
if ($params->isPdfA()) {
|
||||
$this->mapFonts($pdf);
|
||||
}
|
||||
|
||||
$size = $template->getPageFormat() === Template::PAGE_FORMAT_CUSTOM ?
|
||||
[0.0, 0.0, $template->getPageWidth() * self::PT, $template->getPageHeight() * self::PT] :
|
||||
$template->getPageFormat();
|
||||
@@ -72,4 +78,19 @@ class DompdfInitializer
|
||||
$this->config->get('pdfFontFace') ??
|
||||
$this->defaultFontFace;
|
||||
}
|
||||
|
||||
private function mapFonts(Dompdf $pdf): void
|
||||
{
|
||||
// Fonts are included in PDF/A. Map standard fonts to open source analogues.
|
||||
$fontMetrics = $pdf->getFontMetrics();
|
||||
|
||||
$fontMetrics->setFontFamily('courier', $fontMetrics->getFamily('DejaVu Sans Mono'));
|
||||
$fontMetrics->setFontFamily('fixed', $fontMetrics->getFamily('DejaVu Sans Mono'));
|
||||
$fontMetrics->setFontFamily('helvetica', $fontMetrics->getFamily('DejaVu Sans'));
|
||||
$fontMetrics->setFontFamily('monospace', $fontMetrics->getFamily('DejaVu Sans Mono'));
|
||||
$fontMetrics->setFontFamily('sans-serif', $fontMetrics->getFamily('DejaVu Sans'));
|
||||
$fontMetrics->setFontFamily('serif', $fontMetrics->getFamily('DejaVu Serif'));
|
||||
$fontMetrics->setFontFamily('times', $fontMetrics->getFamily('DejaVu Serif'));
|
||||
$fontMetrics->setFontFamily('times-roman', $fontMetrics->getFamily('DejaVu Serif'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
|
||||
namespace Espo\Tools\Pdf\Dompdf;
|
||||
|
||||
use Dompdf\Adapter\CPDF;
|
||||
use Dompdf\Dompdf;
|
||||
use Espo\Core\FileStorage\Manager;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Tools\Pdf\Contents;
|
||||
use Espo\Tools\Pdf\Data;
|
||||
@@ -36,17 +39,19 @@ use Espo\Tools\Pdf\Dompdf\Contents as DompdfContents;
|
||||
use Espo\Tools\Pdf\EntityPrinter as EntityPrinterInterface;
|
||||
use Espo\Tools\Pdf\Params;
|
||||
use Espo\Tools\Pdf\Template;
|
||||
use RuntimeException;
|
||||
|
||||
class EntityPrinter implements EntityPrinterInterface
|
||||
{
|
||||
public function __construct(
|
||||
private DompdfInitializer $dompdfInitializer,
|
||||
private HtmlComposer $htmlComposer
|
||||
private HtmlComposer $htmlComposer,
|
||||
private Manager $fileStorageManager,
|
||||
) {}
|
||||
|
||||
public function print(Template $template, Entity $entity, Params $params, Data $data): Contents
|
||||
{
|
||||
$pdf = $this->dompdfInitializer->initialize($template);
|
||||
$pdf = $this->dompdfInitializer->initialize($template, $params);
|
||||
|
||||
$headHtml = $this->htmlComposer->composeHead($template, $entity);
|
||||
$headerFooterHtml = $this->htmlComposer->composeHeaderFooter($template, $entity, $params, $data);
|
||||
@@ -57,6 +62,34 @@ class EntityPrinter implements EntityPrinterInterface
|
||||
$pdf->loadHtml($html);
|
||||
$pdf->render();
|
||||
|
||||
$this->addAttachments($pdf, $data);
|
||||
|
||||
return new DompdfContents($pdf);
|
||||
}
|
||||
|
||||
private function addAttachments(Dompdf $pdf, Data $data): void
|
||||
{
|
||||
if ($data->getAttachments() === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$canvas = $pdf->getCanvas();
|
||||
|
||||
if (!$canvas instanceof CPDF) {
|
||||
throw new RuntimeException("Non CPDF canvas");
|
||||
}
|
||||
|
||||
$cPdf = $canvas->get_cpdf();
|
||||
|
||||
foreach ($data->getAttachments() as $i => $attachmentWrapper) {
|
||||
$attachment = $attachmentWrapper->getAttachment();
|
||||
|
||||
$path = $this->fileStorageManager->getLocalFilePath($attachment);
|
||||
|
||||
$name = $attachment->getName() ?? 'file-' . $i;
|
||||
$description = $attachmentWrapper->getDescription() ?? '';
|
||||
|
||||
$cPdf->addEmbeddedFile($path, $name, $description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Espo\Tools\Pdf;
|
||||
|
||||
use DateTime;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
@@ -42,6 +43,7 @@ use Espo\Core\Record\ServiceContainer;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Language;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\Util;
|
||||
use Espo\Entities\Attachment;
|
||||
use Espo\Entities\Template as TemplateEntity;
|
||||
@@ -56,40 +58,19 @@ class MassService
|
||||
private const ATTACHMENT_MASS_PDF_ROLE = 'Mass Pdf';
|
||||
private const REMOVE_MASS_PDF_PERIOD = '1 hour';
|
||||
|
||||
private ServiceContainer $serviceContainer;
|
||||
private Config $config;
|
||||
private EntityManager $entityManager;
|
||||
private Acl $acl;
|
||||
private DataLoaderManager $dataLoaderManager;
|
||||
private SelectBuilderFactory $selectBuilderFactory;
|
||||
private Builder $builder;
|
||||
private Language $defaultLanguage;
|
||||
private JobSchedulerFactory $jobSchedulerFactory;
|
||||
private FileStorageManager $fileStorageManager;
|
||||
|
||||
public function __construct(
|
||||
ServiceContainer $serviceContainer,
|
||||
Config $config,
|
||||
EntityManager $entityManager,
|
||||
Acl $acl,
|
||||
DataLoaderManager $dataLoaderManager,
|
||||
SelectBuilderFactory $selectBuilderFactory,
|
||||
Builder $builder,
|
||||
Language $defaultLanguage,
|
||||
JobSchedulerFactory $jobSchedulerFactory,
|
||||
FileStorageManager $fileStorageManager
|
||||
) {
|
||||
$this->serviceContainer = $serviceContainer;
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->acl = $acl;
|
||||
$this->dataLoaderManager = $dataLoaderManager;
|
||||
$this->selectBuilderFactory = $selectBuilderFactory;
|
||||
$this->builder = $builder;
|
||||
$this->defaultLanguage = $defaultLanguage;
|
||||
$this->jobSchedulerFactory = $jobSchedulerFactory;
|
||||
$this->fileStorageManager = $fileStorageManager;
|
||||
}
|
||||
private ServiceContainer $serviceContainer,
|
||||
private Config $config,
|
||||
private EntityManager $entityManager,
|
||||
private Acl $acl,
|
||||
private DataLoaderManager $dataLoaderManager,
|
||||
private SelectBuilderFactory $selectBuilderFactory,
|
||||
private Builder $builder,
|
||||
private Language $defaultLanguage,
|
||||
private JobSchedulerFactory $jobSchedulerFactory,
|
||||
private FileStorageManager $fileStorageManager,
|
||||
private Metadata $metadata,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Generate a PDF for multiple records.
|
||||
@@ -98,6 +79,7 @@ class MassService
|
||||
* @throws Error
|
||||
* @throws NotFound
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function generate(
|
||||
string $entityType,
|
||||
@@ -153,6 +135,10 @@ class MassService
|
||||
|
||||
$idDataMap = IdDataMap::create();
|
||||
|
||||
$pdfA = $this->metadata->get("pdfDefs.$entityType.pdfA") ?? false;
|
||||
|
||||
$params = $params->withPdfA($pdfA);
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$service->loadAdditionalFields($entity);
|
||||
|
||||
|
||||
@@ -35,16 +35,29 @@ namespace Espo\Tools\Pdf;
|
||||
class Params
|
||||
{
|
||||
private bool $applyAcl = false;
|
||||
private bool $pdfA = false;
|
||||
|
||||
public function applyAcl(): bool
|
||||
{
|
||||
return $this->applyAcl;
|
||||
}
|
||||
|
||||
public function isPdfA(): bool
|
||||
{
|
||||
return $this->pdfA;
|
||||
}
|
||||
|
||||
public function withPdfA(bool $pdfA = true): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
$obj->pdfA = $pdfA;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function withAcl(bool $applyAcl = true): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
|
||||
$obj->applyAcl = $applyAcl;
|
||||
|
||||
return $obj;
|
||||
|
||||
@@ -35,6 +35,7 @@ use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Record\ServiceContainer;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Entities\Template as TemplateEntity;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Tools\Pdf\Data\DataLoaderManager;
|
||||
@@ -50,6 +51,7 @@ class Service
|
||||
private DataLoaderManager $dataLoaderManager,
|
||||
private Config $config,
|
||||
private Builder $builder,
|
||||
private Metadata $metadata,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -116,6 +118,10 @@ class Service
|
||||
throw new Error("Not matching entity types.");
|
||||
}
|
||||
|
||||
$pdfA = $this->metadata->get("pdfDefs.{$entity->getEntityType()}.pdfA") ?? false;
|
||||
|
||||
$params = $params->withPdfA($pdfA);
|
||||
|
||||
$data = $this->dataLoaderManager->load($entity, $params, $data);
|
||||
$engine = $this->config->get('pdfEngine') ?? self::DEFAULT_ENGINE;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"johngrogg/ics-parser": "^3.0",
|
||||
"phpseclib/phpseclib": "^3.0",
|
||||
"openspout/openspout": "~4.28",
|
||||
"dompdf/dompdf": "^3.0",
|
||||
"dompdf/dompdf": "^3.1",
|
||||
"brick/phonenumber": "^0.5.0",
|
||||
"picqer/php-barcode-generator": "^2.4",
|
||||
"chillerlan/php-qrcode": "^4.4",
|
||||
|
||||
16
composer.lock
generated
16
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "fdcc2fe81ecada0b857711ff3899dcef",
|
||||
"content-hash": "60833a543fd7f0ed10be53d868d984bf",
|
||||
"packages": [
|
||||
{
|
||||
"name": "async-aws/core",
|
||||
@@ -1043,16 +1043,16 @@
|
||||
},
|
||||
{
|
||||
"name": "dompdf/dompdf",
|
||||
"version": "v3.0.0",
|
||||
"version": "v3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/dompdf.git",
|
||||
"reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59"
|
||||
"reference": "a51bd7a063a65499446919286fb18b518177155a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/fbc7c5ee5d94f7a910b78b43feb7931b7f971b59",
|
||||
"reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59",
|
||||
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a",
|
||||
"reference": "a51bd7a063a65499446919286fb18b518177155a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1068,7 +1068,7 @@
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"mockery/mockery": "^1.3",
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10",
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
@@ -1101,9 +1101,9 @@
|
||||
"homepage": "https://github.com/dompdf/dompdf",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||
"source": "https://github.com/dompdf/dompdf/tree/v3.0.0"
|
||||
"source": "https://github.com/dompdf/dompdf/tree/v3.1.0"
|
||||
},
|
||||
"time": "2024-04-29T14:01:28+00:00"
|
||||
"time": "2025-01-15T14:09:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/php-font-lib",
|
||||
|
||||
@@ -14,6 +14,20 @@
|
||||
]
|
||||
},
|
||||
"description": "List of classes that loads additional data for PDF. Classes should implement the interface Espo\\Tools\\Pdf\\DataLoader. Use __APPEND__ for extending."
|
||||
},
|
||||
"pdfA": {
|
||||
"type": "boolean",
|
||||
"description": "Use PDF/A. Since v9.2."
|
||||
},
|
||||
"attachmentProviderClassNameList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{"const": "__APPEND__"},
|
||||
{"type": "string"}
|
||||
]
|
||||
},
|
||||
"description": "Attachment providers. Should implement `Espo\\Tools\\Pdf\\AttachmentProvider`. Since v9.2."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user