Project

General

Profile

Feature #103810 ยป ConvertViewHelper.php

Dieter Porth, 2024-05-09 16:21

 
<?php

declare(strict_types=1);

namespace Buergerstimmende\Newssystem\ViewHelpers;

/***************************************************************
*
* Copyright notice
*
* (c) 2024 Dr. Dieter Porth <info@mobger.de>
*
* All rights reserved
*
* This script 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.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Exception;

/**
* The viewhelper buid a convert-variable for a string by using a php-function. The variable contains the result
* of the conversion. It may be an integer, a string or an array. The list of usable php-functions are restricted.
* You can use every php-function, if you set the ignoreWarning-flag.
*
*
* Examples which defines nested variables
* =======================================
*
* IMPORTANT: The attribute ``value`` is already defined and the rendered context
*
* The nested content will be intepreted as template-content. The defined variable is only accessable in the block.
* It works similiar to <f:alias map=.... >
*
* The following table shows the behavior of the different attribute/value constellations.
* value set render exist local Result Exception Remark
* nein nein false ja
* ja nein false var global
* nein ja false var global
* ja ja false var global,
* rendering visible
* nein nein true var global,
* empty rendering lokal-flag ignored
* ja nein true var lokal,
* empty rendering
* nein ja true var global lokal-flag ignored
* ja ja true var lokal,
* rendering visible
*
* ATTENTION: The order of the parameter for the php-function must be respected within the arrays `prev` and `post`. (see anti-example `implode`)
*
* Examples which defines global variables
* =======================================
*
* IMPORTANT: The attribute ``value`` is UNDEFINED or there is no nested content.
*
* Default
* -------
*
* ::
*
* {newssys:convert(phpFunc:'strtolower',value:'Some Value In A String',as:'lowered')}
* <newssys:convert phpFunc="strtolower" as="lowered">{beforeConvert}</newssys:convert>
* {beforeConvert -> newssys:convert(phpFunc:'strtolower',as:'lowered')}
* <newssys:convert phpFunc="strtolower" as="lowered">{oldconvert}</newssys:convert>
*
* The variable ``lowered`` contains the value ``some value in a string``.
*
* ====================================
* The php-function ``implode`` is not allowed for convert, beause the value must be a string and not an array.
* You can nevertheless use thefunction ``implode`` in the following way.
*
* // remembner the attributes post and prev must be arrays.
* <newssys:convert phpFunc="implode" as="joinString"
* post="{0:{0:'The world',1:' which is nice',2:' is blue.'}}"
* ignoreWarning="1"
* value=","
* ></newssys:convert>
*
* The result should be: 'The world, which is nice, is blue.'
*
*
*/
final class ConvertViewHelper extends AbstractViewHelper
{
/**
* Output is escaped already. We must not escape children, to avoid double encoding.
*
* @var bool
*/
protected $escapeChildren = false;

protected const ALLOWED_METHOD = [
'addslashes',
'bin2hex',
'chop',
'chunk_split',
'convert_uudecode',
'convert_uuencode',
'crc32',
'crypt',
'explode',
'hex2bin',
'html_entity_decode',
'htmlentities',
'htmlspecialchars_decode',
'htmlspecialchars',
'lcfirst',
'ltrim',
'md5',
'metaphone',
'nl2br',
'quoted_printable_decode',
'quoted_printable_encode',
'quotemeta',
'rtrim',
'sha1',
'str_contains',
'str_decrement',
'str_ends_with',
'str_getcsv',
'str_increment',
'str_pad',
'str_repeat',
'str_rot13',
'str_shuffle',
'str_split',
'str_starts_with',
'str_word_count',
'strcasecmp',
'strchr',
'strcmp',
'strcoll',
'strip_tags',
'stripos',
'stripslashes',
'stristr',
'strlen',
'strnatcasecmp',
'strnatcmp',
'strncasecmp',
'strncmp',
'strpbrk',
'strpos',
'strrchr',
'strrev',
'strripos',
'strrpos',
'strstr',
'strtok',
'strtolower',
'strtoupper',
'substr',
'trim',
'ucfirst',
'ucwords',
'wordwrap',
];
protected const PARAM_VALUE = 'value';
protected const PARAM_LOKAL = 'local';
protected const PARAM_PREV = 'prev';
protected const PARAM_POST = 'post';
protected const PHP_FUNC = 'phpfunc';
protected const PARAM_IGNORE_WARNING = 'ignoreWarning';
protected const PARAM_AS = 'as';

use CompileWithRenderStatic;

/**
* @return void
*/
public function initializeArguments()
{
$this->registerArgument(self::PARAM_VALUE, 'string',
'Value to assign. If not in arguments then taken from tag content', false, '');
$this->registerArgument(self::PARAM_LOKAL, 'bool',
'flag, if the variable works only for the nested content. '.
'(It only works, if the value is defined in the attribute `value`.)', false, false);
$this->registerArgument(self::PARAM_PREV, 'array',
'parameters before string', false, []);
$this->registerArgument(self::PARAM_POST, 'array',
'parameters after string', false, []);
$this->registerArgument(self::PHP_FUNC, 'string',
'name of php-method with allows usage of a\n\r string|array = function(string) ', true);
$this->registerArgument(self::PARAM_IGNORE_WARNING, 'string',
'Usage of a php-function, which is not part of the allowed methods ', false, false);
$this->registerArgument(self::PARAM_AS, 'string',
'Name of variable to create', true);
}

/**
* @param array<mixed> $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
*
* @return mixed|void
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
)
{
try {
$ignoreWarning = [(string)((isset($arguments[self::PARAM_IGNORE_WARNING])) ?
$arguments[self::PARAM_IGNORE_WARNING] :
false
)];
$flagLokal = ((isset($arguments[self::PARAM_LOKAL]))?
$arguments[self::PARAM_LOKAL] :
false
);
$flagRender = false;
if (isset($arguments[self::PARAM_VALUE])) {
$flagRender = true;
$test = [
(string)$arguments[self::PARAM_VALUE],
];
} else {
// the agrument['value'] is missing =>
// the rendered block contains the value of the variable and will exist globally
$flagLokal = false;
$test = [
$renderChildrenClosure(),
];
}
$resolveValue = $test[0];
$phpFunction = (string)$arguments[self::PHP_FUNC];
$prev = ((isset($arguments[self::PARAM_PREV])) ?
$arguments[self::PARAM_PREV] :
[]
);
$post = ((isset($arguments[self::PARAM_POST])) ?
$arguments[self::PARAM_POST] :
[]
);
if ((!is_array($prev)) ||
(!is_array($post))
) {
throw new Exception(
'The parameters `prev` [' . print_r($prev, true) .
'] and/or `post` [' . print_r($post, true) . '] are not defined as in an array. ' .
'The arguments of the viewhelper are: ' . print_r($arguments, true),
1715246271
);
}
if ((!isset($arguments[self::PARAM_AS])) ||
(empty(trim($arguments[self::PARAM_AS])))
) {
throw new Exception(
'The name of the new variable is not correctly defined in `as`. ' .
'The current value is [' . print_r($arguments[self::PARAM_AS], true) . '].' .
'The arguments of the viewhelper are: ' . print_r($arguments, true),
1715247382
);

}
$resolveVariable = trim($arguments[self::PARAM_AS]);
if (($ignoreWarning) ||
(in_array($phpFunction, self::ALLOWED_METHOD))
) {
$result = array_merge($prev, $test, $post);
if (is_callable($phpFunction)) {
$resolveValue = $phpFunction(...$result);
}

} else {
throw new Exception(
'The method `' . $phpFunction . '` with the parameters `prev` [' . print_r($prev, true) .
'] and/or `post` [' . print_r($post, true) . '] is not callable or not allowed. ' .
'(Remark: The parameter `ignoreWarning` has the value: ' . ($ignoreWarning ? 'true' : 'false[default]') . '.)' .
'The arguments of the viewhelper are: ' . print_r($arguments, true),
1715246896
);
}
$renderingContext->getVariableProvider()->add($arguments[self::PARAM_AS], $resolveValue);
} catch (\Exception $e) {
throw new Exception(
'An unexpected error occurs. Check the name of your php-method [' . $phpFunction . ']. ' .
'Check the order of your parameters in the arrays `prev` [' . print_r($prev, true) .
'] and/or `post` [' . print_r($post, true) . ']. ' .
'The arguments of the viewhelper are: ' . print_r($arguments, true),
1715246453
);
}

if ($flagLokal) {
$res = (string) $renderChildrenClosure();
$renderingContext->getVariableProvider()->remove($arguments[self::PARAM_AS]);
return $res;
} else if ($flagRender) {
$res = (string) $renderChildrenClosure();
return $res;
}
}
}
    (1-1/1)