pdf refactoring and fixes

This commit is contained in:
Yuri Kuznetsov
2021-05-11 18:18:41 +03:00
parent 2738019c3f
commit 0f4391bdd1
8 changed files with 176 additions and 87 deletions
+19 -6
View File
@@ -29,18 +29,32 @@
namespace Espo\Controllers;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\{
Exceptions\Forbidden,
Exceptions\BadRequest,
};
use Espo\Core\{
Controllers\Base,
Api\Request,
Acl,
};
use Espo\Services\Pdf as Service;
use StdClass;
class Pdf extends Base
class Pdf
{
private $service;
private $acl;
public function __construct(Service $service, Acl $acl)
{
$this->service = $service;
$this->acl = $acl;
}
public function postActionMassPrint(Request $request): StdClass
{
$data = $request->getParsedBody();
@@ -66,8 +80,7 @@ class Pdf extends Base
}
return (object) [
'id' => $this->getServiceFactory()
->create('Pdf')
'id' => $this->service
->massGenerate(
$data->entityType,
$data->idList,
@@ -32,12 +32,17 @@ namespace Espo\Core\Formula\Functions\ExtGroup\PdfGroup;
use Espo\Core\Formula\{
Functions\BaseFunction,
ArgumentList,
Exceptions\Error,
};
use Espo\Core\Utils\Util;
use Espo\Tools\Pdf\Data;
use Espo\Core\Di;
use Exception;
class GenerateType extends BaseFunction implements
Di\EntityManagerAware,
Di\ServiceFactoryAware
@@ -61,12 +66,15 @@ class GenerateType extends BaseFunction implements
if (!$entityType || !is_string($entityType)) {
$this->throwBadArgumentType(1, 'string');
}
if (!$id || !is_string($id)) {
$this->throwBadArgumentType(2, 'string');
}
if (!$templateId || !is_string($templateId)) {
$this->throwBadArgumentType(3, 'string');
}
if ($fileName && !is_string($fileName)) {
$this->throwBadArgumentType(4, 'string');
}
@@ -75,21 +83,25 @@ class GenerateType extends BaseFunction implements
try {
$entity = $em->getEntity($entityType, $id);
} catch (\Exception $e) {
}
catch (Exception $e) {
$this->log("Message: " . $e->getMessage() . ".");
return null;
throw new Error();
}
if (!$entity) {
$this->log("Record {$entityType} {$id} does not exist.");
return null;
throw new Error();
}
$template = $em->getEntity('Template', $templateId);
if (!$template) {
$this->log("Template {$templateId} does not exist.");
return null;
throw new Error();
}
if ($fileName) {
@@ -100,11 +112,17 @@ class GenerateType extends BaseFunction implements
$fileName = Util::sanitizeFileName($entity->get('name')) . '.pdf';
}
$data = Data::fromNothing()->withAcl(false);
try {
$contents = $this->serviceFactory->create('Pdf')->buildFromTemplate($entity, $template);
} catch (\Exception $e) {
$contents = $this->serviceFactory
->create('Pdf')
->generate($entity, $template, $data);
}
catch (Exception $e) {
$this->log("Error while generating. Message: " . $e->getMessage() . ".", 'error');
return null;
throw new Error();
}
$attachment = $em->createEntity('Attachment', [
@@ -116,6 +134,6 @@ class GenerateType extends BaseFunction implements
'role' => 'Attachment',
]);
return $attachment->id;
return $attachment->getId();
}
}
+6 -3
View File
@@ -34,11 +34,12 @@ use Espo\Core\Utils\DateTime;
class Factory
{
protected $injectableFactory;
private $injectableFactory;
protected $dateTime;
private $dateTime;
public function __construct(InjectableFactory $injectableFactory, DateTime $dateTime) {
public function __construct(InjectableFactory $injectableFactory, DateTime $dateTime)
{
$this->injectableFactory = $injectableFactory;
$this->dateTime = $dateTime;
}
@@ -46,6 +47,7 @@ class Factory
public function create(bool $skipAcl = false, ?string $timezone = null): Htmlizer
{
$with = [];
if ($skipAcl) {
$with['acl'] = null;
}
@@ -53,6 +55,7 @@ class Factory
if ($timezone) {
$dateTime = clone($this->dateTime);
$dateTime->setTimezone($timezone);
$with['dateTime'] = $dateTime;
}
@@ -133,10 +133,6 @@ class Htmlizer
$data = get_object_vars($entity->getValueMap());
//$data = $entity->toArray();
//print_r($data);
$attributeList = $entity->getAttributeList();
$forbiddenAttributeList = [];
+27 -7
View File
@@ -34,21 +34,23 @@ use Espo\Core\{
Exceptions\BadRequest,
EntryPoint\EntryPoint,
ORM\EntityManager,
ServiceFactory,
Api\Request,
Api\Response,
Utils\Util,
};
use Espo\Services\Pdf as Service;
class Pdf implements EntryPoint
{
protected $entityManager;
private $entityManager;
protected $serviceFactory;
private $service;
public function __construct(EntityManager $entityManager, ServiceFactory $serviceFactory)
public function __construct(EntityManager $entityManager, Service $service)
{
$this->entityManager = $entityManager;
$this->serviceFactory = $serviceFactory;
$this->service = $service;
}
public function run(Request $request, Response $response): void
@@ -68,8 +70,26 @@ class Pdf implements EntryPoint
throw new NotFound();
}
$this->serviceFactory->create('Pdf')->buildFromTemplate($entity, $template, true);
$contents = $this->service->generate($entity, $template);
exit;
$fileName = Util::sanitizeFileName(
$entity->get('name') ?? 'unnamed'
);
$fileName = $fileName . '.pdf';
$response
->setHeader('Content-Type', 'application/pdf')
->setHeader('Cache-Control', 'private, must-revalidate, post-check=0, pre-check=0, max-age=1')
->setHeader('Pragma', 'public')
->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT')
->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT')
->setHeader('Content', 'inline; filename="' . basename($fileName) . '"');
if (!$request->getServerParam('HTTP_ACCEPT_ENCODING')) {
$response->setHeader('Content-Length', $contents->getLength());
}
$response->writeBody($contents);
}
}
+71 -55
View File
@@ -36,18 +36,16 @@ use Espo\Core\Exceptions\{
};
use Espo\Core\{
ServiceFactory,
Acl,
Acl\Table,
Utils\Config,
Utils\Metadata,
Utils\Language,
Utils\Util,
Htmlizer\Htmlizer,
Htmlizer\Factory as HtmlizerFactory,
ORM\EntityManager,
ORM\Entity,
Pdf\Tcpdf,
Select\SelectBuilderFactory,
Record\ServiceContainer,
};
use Espo\{
@@ -57,60 +55,57 @@ use Espo\{
Tools\Pdf\Data,
};
use Espo\ORM\{
QueryParams\Select,
};
use Espo\Entities\Template;
use DateTime;
use StdClass;
class Pdf
{
protected const DEFAULT_ENGINE = 'Tcpdf';
protected $removeMassFilePeriod = '1 hour';
protected $config;
private $config;
protected $serviceFactory;
private $metadata;
protected $metadata;
private $entityManager;
protected $entityManager;
private $acl;
protected $acl;
private $defaultLanguage;
protected $defaultLanguage;
private $selectBuilderFactory;
protected $htmlizerFactory;
private $builder;
protected $selectBuilderFactory;
protected $builder;
private $serviceContanier;
public function __construct(
Config $config,
ServiceFactory $serviceFactory,
Metadata $metadata,
EntityManager $entityManager,
Acl $acl,
Language $defaultLanguage,
HtmlizerFactory $htmlizerFactory,
SelectBuilderFactory $selectBuilderFactory,
Builder $builder
Builder $builder,
ServiceContainer $serviceContanier
) {
$this->config = $config;
$this->serviceFactory = $serviceFactory;
$this->metadata = $metadata;
$this->entityManager = $entityManager;
$this->acl = $acl;
$this->defaultLanguage = $defaultLanguage;
$this->htmlizerFactory = $htmlizerFactory;
$this->selectBuilderFactory = $selectBuilderFactory;
$this->builder = $builder;
$this->serviceContanier = $serviceContanier;
}
public function generateMailMerge(
string $entityType,
iterable $entityList,
Entity $template,
Template $template,
string $name,
?string $campaignId = null
): string {
@@ -121,12 +116,7 @@ class Pdf
$collection[] = $entity;
}
if ($this->serviceFactory->checkExists($entityType)) {
$service = $this->serviceFactory->create($entityType);
}
else {
$service = $this->serviceFactory->create('Record');
}
$service = $this->serviceContanier->get($entityType);
foreach ($entityList as $entity) {
$service->loadAdditionalFields($entity);
@@ -140,7 +130,7 @@ class Pdf
$printer = $this->builder
->setTemplate($templateWrapper)
->setEngine('Tcpdf')
->setEngine(self::DEFAULT_ENGINE)
->build();
$contents = $printer->printCollection($collection);
@@ -170,11 +160,7 @@ class Pdf
bool $checkAcl = false
): string {
if ($this->serviceFactory->checkExists($entityType)) {
$service = $this->serviceFactory->create($entityType);
} else {
$service = $this->serviceFactory->create('Record');
}
$service = $this->serviceContanier->get($entityType);
$maxCount = $this->config->get('massPrintPdfMaxCount');
@@ -224,7 +210,7 @@ class Pdf
$templateWrapper = new TemplateWrapper($template);
$engine = $this->config->get('pdfEngine') ?? 'Tcpdf';
$engine = $this->config->get('pdfEngine') ?? self::DEFAULT_ENGINE;
$printer = $this->builder
->setTemplate($templateWrapper)
@@ -265,7 +251,7 @@ class Pdf
return $attachment->id;
}
public function removeMassFileJob($data)
public function removeMassFileJob(StdClass $data): void
{
if (empty($data->id)) {
return;
@@ -284,20 +270,38 @@ class Pdf
$this->entityManager->removeEntity($attachment);
}
/**
* Generate PDF. ACL check is processed if `$data` is null.
*/
public function generate(Entity $entity, Template $template, ?Data $data = null): string
{
return $this->buildFromTemplateInternal($entity, $template, false, null, $data);
}
/**
* @deprecated
*/
public function buildFromTemplate(
Entity $entity,
Entity $template,
Template $template,
bool $displayInline = false,
?array $additionalData = null
): ?string {
return $this->buildFromTemplateInternal($entity, $template, $displayInline, $additionalData);
}
private function buildFromTemplateInternal(
Entity $entity,
Entity $template,
bool $displayInline = false,
?array $additionalData = null,
?Data $data = null
): ?string {
$entityType = $entity->getEntityType();
if ($this->serviceFactory->checkExists($entityType)) {
$service = $this->serviceFactory->create($entityType);
} else {
$service = $this->serviceFactory->create('Record');
}
$service = $this->serviceContanier->get($entityType);
$service->loadAdditionalFields($entity);
@@ -309,17 +313,31 @@ class Pdf
throw new Error("Not matching entity types.");
}
if (!$this->acl->check($entity, 'read') || !$this->acl->check($template, 'read')) {
throw new Forbidden();
$applyAcl = true;
if ($data) {
$applyAcl = $data->applyAcl();
}
if ($applyAcl) {
if (
!$this->acl->check($entity, Table::ACTION_READ) ||
!$this->acl->check($template, Table::ACTION_READ)
) {
throw new Forbidden();
}
}
$templateWrapper = new TemplateWrapper($template);
$data = Data::createFromArray([
'additionalTemplateData' => $additionalData,
]);
if (!$data) {
$data = Data
::fromNothing()
->withAdditionalTemplateData($additionalData ?? [])
->withAcl($applyAcl);
}
$engine = $this->config->get('pdfEngine') ?? 'Tcpdf';
$engine = $this->config->get('pdfEngine') ?? self::DEFAULT_ENGINE;
$printer = $this->builder
->setTemplate($templateWrapper)
@@ -337,7 +355,10 @@ class Pdf
return $contents->getString();
}
protected function displayInline(Entity $entity, Contents $contents)
/**
* @deprecated
*/
private function displayInline(Entity $entity, Contents $contents): void
{
$fileName = Util::sanitizeFileName(
$entity->get('name') ?? 'unnamed'
@@ -358,9 +379,4 @@ class Pdf
echo $contents->getString();
}
protected function createHtmlizer()
{
return $this->htmlizerFactory->create();
}
}
+24 -3
View File
@@ -36,22 +36,43 @@ class Data
{
private $additionalTemplateData = [];
private $applyAcl = false;
public function setAdditionalTemplateData(array $additionalTemplateData)
{
$this->additionalTemplateData = $additionalTemplateData;
}
public function applyAcl(): bool
{
return $this->applyAcl;
}
public function getAdditionalTemplateData(): array
{
return $this->additionalTemplateData;
}
public static function createFromArray(array $data): Data
public function withAdditionalTemplateData(array $additionalTemplateData): self
{
$obj = new self();
$obj = clone $this;
$obj->additionalTemplateData = $data['additionalTemplateData'] ?? [];
$obj->additionalTemplateData = $additionalTemplateData;
return $obj;
}
public function withAcl(bool $applyAcl = true): self
{
$obj = clone $this;
$obj->applyAcl = $applyAcl;
return $obj;
}
public static function fromNothing(): self
{
return new self();
}
}
@@ -62,7 +62,9 @@ class EntityProcessor
{
$additionalData = $data->getAdditionalTemplateData();
$htmlizer = $this->htmlizerFactory->create();
$htmlizer = $data->applyAcl() ?
$this->htmlizerFactory->create() :
$this->htmlizerFactory->createNoAcl();
$fontFace = $this->config->get('pdfFontFace', $this->fontFace);