templete helper interface

This commit is contained in:
Yuri Kuznetsov
2021-09-22 11:58:02 +03:00
parent 50d38d127c
commit 0a320cb3b3
10 changed files with 600 additions and 123 deletions

View File

@@ -29,61 +29,79 @@
namespace Espo\Classes\TemplateHelpers;
class GoogleMaps
use Espo\Core\Htmlizer\Helper;
use Espo\Core\Htmlizer\Helper\Data;
use Espo\Core\Htmlizer\Helper\Result;
use Espo\Core\Utils\Metadata;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Log;
class GoogleMaps implements Helper
{
public static function image()
private const DEFAULT_SIZE = '400x400';
private $metadata;
private $config;
private $log;
public function __construct(
Metadata $metadata,
Config $config,
Log $log
) {
$this->metadata = $metadata;
$this->config = $config;
$this->log = $log;
}
public function render(Data $data): Result
{
$args = func_get_args();
$context = $args[count($args) - 1];
$hash = $context['hash'];
$data = $context['data']['root'];
$rootContext = $data->getRootContext();
$em = $data['__entityManager'];
$metadata = $data['__metadata'];
$config = $data['__config'];
$log = $data['__log'];
$entityType = $rootContext['__entityType'];
$entityType = $data['__entityType'];
$field = $hash['field'] ?? null;
$size = $hash['size'] ?? '400x400';
$zoom = $hash['zoom'] ?? null;
$language = $hash['language'] ?? $config->get('language');
$field = $data->getOption('field');
$size = $data->getOption('size') ?? self::DEFAULT_SIZE;
$zoom = $data->getOption('zoom');
$language = $data->getOption('language') ?? $this->config->get('language');
if (strpos($size, 'x') === false) {
$size = $size .'x' . $size;
$size = $size . 'x' . $size;
}
if ($field && $metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']) !== 'address') {
$log->warning("Template helper _googleMapsImage: Specified field is not of address type.");
if ($field && $this->metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']) !== 'address') {
$this->log->warning("Template helper _googleMapsImage: Specified field is not of address type.");
return null;
return Result::createEmpty();
}
if (
!$field &&
!array_key_exists('street', $hash) &&
!array_key_exists('city', $hash) &&
!array_key_exists('country', $hash) &&
!array_key_exists('state', $hash) &&
!array_key_exists('postalCode', $hash)
!$data->hasOption('street') &&
!$data->hasOption('city') &&
!$data->hasOption('country') &&
!$data->hasOption('state') &&
!$data->hasOption('postalCode')
) {
$field = ($entityType === 'Account') ? 'billingAddress' : 'address';
}
if ($field) {
$street = $data[$field . 'Street'] ?? null;
$city = $data[$field . 'City'] ?? null;
$country = $data[$field . 'Country'] ?? null;
$state = $data[$field . 'State'] ?? null;
$postalCode = $data[$field . 'postalCode'] ?? null;
} else {
$street = $hash['street'] ?? null;
$city = $hash['city'] ?? null;
$country = $hash['country'] ?? null;
$state = $hash['state'] ?? null;
$postalCode = $hash['postalCode'] ?? null;
$street = $rootContext[$field . 'Street'] ?? null;
$city = $rootContext[$field . 'City'] ?? null;
$country = $rootContext[$field . 'Country'] ?? null;
$state = $rootContext[$field . 'State'] ?? null;
$postalCode = $rootContext[$field . 'postalCode'] ?? null;
}
else {
$street = $data->getOption('street');
$city = $data->getOption('city');
$country = $data->getOption('country');
$state = $data->getOption('state');
$postalCode = $data->getOption('postalCode');
}
$address = '';
@@ -96,6 +114,7 @@ class GoogleMaps
if ($address != '') {
$address .= ', ';
}
$address .= $city;
}
@@ -103,16 +122,16 @@ class GoogleMaps
if ($address != '') {
$address .= ', ';
}
$address .= $state;
}
if ($postalCode) {
if ($state || $city) {
$address .= ' ';
} else {
if ($address) {
$address .= ', ';
}
}
else if ($address) {
$address .= ', ';
}
$address .= $postalCode;
@@ -126,26 +145,26 @@ class GoogleMaps
$address .= $country;
}
$address = urlencode($address);
$apiKey = $config->get('googleMapsApiKey');
$apiKey = $this->config->get('googleMapsApiKey');
if (!$apiKey) {
$log->error("Template helper _googleMapsImage: No Google Maps API key.");
$this->log->error("Template helper _googleMapsImage: No Google Maps API key.");
return null;
return Result::createEmpty();
}
if (!$address) {
$log->debug("Template helper _googleMapsImage: No address to display.");
$addressEncoded = urlencode($address);
return null;
if (!$addressEncoded) {
$this->log->debug("Template helper _googleMapsImage: No address to display.");
return Result::createEmpty();
}
$format = 'jpg;';
$url = "https://maps.googleapis.com/maps/api/staticmap?" .
'center=' . $address .
'center=' . $addressEncoded .
'format=' . $format .
'&size=' . $size .
'&key=' . $apiKey;
@@ -158,13 +177,12 @@ class GoogleMaps
$url .= '&language=' . $language;
}
$log->debug("Template helper _googleMapsImage: URL: {$url}.");
$this->log->debug("Template helper _googleMapsImage: URL: {$url}.");
// Need to use fully-qualified class name.
$image = \Espo\Classes\TemplateHelpers\GoogleMaps::getImage($url);
$image = $this->getImage($url);
if (!$image) {
return null;
return Result::createEmpty();
}
list($width, $height) = explode('x', $size);
@@ -173,14 +191,18 @@ class GoogleMaps
$tag = "<img src=\"{$src}\" width=\"{$width}\" height=\"{$height}\">";
return new LightnCandy\SafeString($tag);
return Result::createSafeString($tag);
}
public static function getImage(string $url)
/**
* @return string|bool
*/
private function getImage(string $url)
{
$headers = [];
$headers[] = 'Accept: image/jpeg, image/pjpeg';
$headers[] = 'Connection: Keep-Alive';
$headers = [
'Accept: image/jpeg, image/pjpeg',
'Connection: Keep-Alive',
];
$agent = 'Mozilla/5.0';
@@ -195,8 +217,8 @@ class GoogleMaps
curl_setopt($c, \CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($c, \CURLOPT_BINARYTRANSFER, 1);
$raw = curl_exec($c);
curl_close($c);
return $raw;

View File

@@ -0,0 +1,56 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\TemplateHelpers;
use Espo\Core\Htmlizer\Helper;
use Espo\Core\Htmlizer\Helper\Data;
use Espo\Core\Htmlizer\Helper\Result;
class TableTag implements Helper
{
public function render(Data $data): Result
{
$border = $data->getOption('border') ?? '0.5pt';
$cellpadding = $data->getOption('cellpadding') ?? '2';
$width = $data->getOption('width') ?? null;
$attributesPart = "";
if ($width) {
$attributesPart .= " width=\"{$width}\"";
}
return Result::createSafeString(
"<table border=\"{$border}\" cellpadding=\"{$cellpadding}\" {$attributesPart}>" .
$data->getFunction()() .
"</table>"
);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\TemplateHelpers;
use Espo\Core\Htmlizer\Helper;
use Espo\Core\Htmlizer\Helper\Data;
use Espo\Core\Htmlizer\Helper\Result;
class TdTag implements Helper
{
public function render(Data $data): Result
{
$align = strtolower($data->getOption('align') ?? 'left');
if (!in_array($align, ['left', 'right', 'center'])) {
$align = 'left';
}
$width = $data->getOption('width') ?? null;
$attributesPart = "align=\"{$align}\"";
if ($width) {
$attributesPart .= " width=\"{$width}\"";
}
return Result::createSafeString(
"<td>" .
$data->getFunction()() .
"</td>"
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\TemplateHelpers;
use Espo\Core\Htmlizer\Helper;
use Espo\Core\Htmlizer\Helper\Data;
use Espo\Core\Htmlizer\Helper\Result;
class TrTag implements Helper
{
public function render(Data $data): Result
{
return Result::createSafeString(
"<tr>" .
$data->getFunction()() .
"</tr>"
);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Htmlizer;
use Espo\Core\Htmlizer\Helper\Data;
use Espo\Core\Htmlizer\Helper\Result;
interface Helper
{
public function render(Data $data): Result;
}

View File

@@ -0,0 +1,122 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Htmlizer\Helper;
use stdClass;
class Data
{
private $argumentList;
private $options;
private $blockParams;
private $context;
private $name;
private $rootContext;
private $func;
private $inverseFunc;
public function __construct(
string $name,
array $argumentList,
stdClass $options,
array $context,
array $rootContext,
int $blockParams,
?callable $func,
?callable $inverseFunc
) {
$this->name = $name;
$this->argumentList = $argumentList;
$this->options = $options;
$this->context = $context;
$this->rootContext = $rootContext;
$this->blockParams = $blockParams;
$this->func = $func;
$this->inverseFunc = $inverseFunc;
}
public function getName(): string
{
return $this->name;
}
public function getContext(): array
{
return $this->context;
}
public function getRootContext(): array
{
return $this->rootContext;
}
public function getOptions(): stdClass
{
return $this->options;
}
/**
* @return mixed[]
*/
public function getArgumentList(): array
{
return $this->argumentList;
}
public function hasOption(string $name): bool
{
return property_exists($this->options, $name);
}
/**
* @return mixed
*/
public function getOption(string $name)
{
return $this->options->$name ?? null;
}
public function getFunction(): ?callable
{
return $this->func;
}
public function getInverseFunction(): ?callable
{
return $this->inverseFunc;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Htmlizer\Helper;
class Result
{
private $value;
private function __construct() {}
public static function createSafeString(string $value): self
{
$obj = new self();
$obj->value = new SafeString($value);
return $obj;
}
public static function createEmpty(): self
{
$obj = new self();
$obj->value = '';
return $obj;
}
public static function create(string $value): self
{
$obj = new self();
$obj->value = $value;
return $obj;
}
/**
* @return SafeString|string
*/
public function getValue()
{
if ($this->value instanceof SafeString) {
return $this->value;
}
return (string) $this->value;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Htmlizer\Helper;
use LightnCandy\SafeString as LightnCandySafeString;
class SafeString
{
private $wrappee;
public function __construct(string $value)
{
$this->wrappee = new LightnCandySafeString($value);
}
public static function create(string $value): self
{
return new self($value);
}
public function getWrappee(): LightnCandySafeString
{
return $this->wrappee;
}
public function __toString()
{
return (string) $this->wrappee;
}
}

View File

@@ -187,7 +187,7 @@ class Htmlizer
return $html;
}
protected function format($value)
private function format($value)
{
if (is_float($value)) {
return $this->number->format($value, 2);
@@ -204,7 +204,7 @@ class Htmlizer
return $value;
}
protected function getDataFromEntity(
private function getDataFromEntity(
Entity $entity,
bool $skipLinks = false,
int $level = 0,
@@ -443,7 +443,7 @@ class Htmlizer
return $data;
}
protected function getHelpers()
private function getHelpers(): array
{
$helpers = [
'file' => function () {
@@ -610,63 +610,6 @@ class Htmlizer
return $context['inverse'] ? $context['inverse']() : '';
},
'tableTag' => function () {
$args = func_get_args();
$context = $args[count($args) - 1];
$border = $context['hash']['border'] ?? '0.5pt';
$cellpadding = $context['hash']['cellpadding'] ?? '2';
$width = $context['hash']['width'] ?? null;
$attributesPart = "";
if ($width) {
$attributesPart .= " width=\"{$width}\"";
}
return
new LightnCandy\SafeString(
"<table border=\"{$border}\" cellpadding=\"{$cellpadding}\" {$attributesPart}>"
) .
$context['fn']() .
new LightnCandy\SafeString("</table>");
},
'tdTag' => function () {
$args = func_get_args();
$context = $args[count($args) - 1];
$align = strtolower($context['hash']['align'] ?? 'left');
if (!in_array($align, ['left', 'right', 'center'])) {
$align = 'left';
}
$width = $context['hash']['width'] ?? null;
$attributesPart = "align=\"{$align}\"";
if ($width) {
$attributesPart .= " width=\"{$width}\"";
}
return
new LightnCandy\SafeString("<td {$attributesPart}>") .
$context['fn']() .
new LightnCandy\SafeString("</td>");
},
'trTag' => function () {
$args = func_get_args();
$context = $args[count($args) - 1];
return
new LightnCandy\SafeString("<tr>") .
$context['fn']() .
new LightnCandy\SafeString("</tr>");
},
'checkboxTag' => function () {
$args = func_get_args();
@@ -706,16 +649,73 @@ class Htmlizer
},
];
$customHelper = function () {
$args = func_get_args();
$agumentList = array_slice($args, 0, -1);
$context = $args[count($args) - 1];
$options = $context['hash'];
$rootData = $context['data']['root'];
$injectableFactory = $rootData['__injectableFactory'];
$metadata = $rootData['__metadata'];
$name = $context['name'];
$className = $metadata->get(['app', 'templateHelpers', $name]);
$data = new \Espo\Core\Htmlizer\Helper\Data(
$name,
$agumentList,
(object) $options,
$context['_this'],
$rootData,
$context['fn.blockParams'],
$context['fn'] ?? null,
$context['inverse'] ?? null
);
$helper = $injectableFactory->create($className);
$result = $helper->render($data);
$value = $result->getValue();
if ($value instanceof \Espo\Core\Htmlizer\Helper\SafeString) {
return $value->getWrappee();
}
return $value;
};
if ($this->metadata) {
$additionalHelpers = $this->metadata->get(['app', 'templateHelpers']) ?? [];
$additionalHelpers = array_filter(
$this->metadata->get(['app', 'templateHelpers']) ?? [],
function (string $item) {
return strpos($item, '::') !== false;
}
);
$helpers = array_merge($helpers, $additionalHelpers);
$additionalHelper2NameList = array_keys(
array_filter(
$this->metadata->get(['app', 'templateHelpers']) ?? [],
function (string $item) {
return strpos($item, '::') == false;
}
)
);
foreach ($additionalHelper2NameList as $name) {
$helpers[$name] = $customHelper;
}
}
return $helpers;
}
protected function getFieldType(string $entityType, string $field)
private function getFieldType(string $entityType, string $field)
{
if (!$this->metadata) {
return null;

View File

@@ -1,3 +1,6 @@
{
"googleMapsImage": "Espo\\Classes\\TemplateHelpers\\GoogleMaps::image"
"googleMapsImage": "Espo\\Classes\\TemplateHelpers\\GoogleMaps",
"tableTag": "Espo\\Classes\\TemplateHelpers\\TableTag",
"trTag": "Espo\\Classes\\TemplateHelpers\\TrTag",
"tdTag": "Espo\\Classes\\TemplateHelpers\\TdTag"
}