Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Classes/Utility/TemplateDirectivesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class TemplateDirectivesService
* ignoreUids=777,888 : list of uids to ignore
*
* @param string $lineFromConstant The constant line
* @return void
* @return true
*/
public function lookForDirectives(string $lineFromConstant): void
public function lookForDirectives(string $lineFromConstant): bool
{
// Remove all spaces and line feed from input line
$inputLine = trim(str_replace(' ', '', $lineFromConstant));
Expand All @@ -47,7 +47,9 @@ public function lookForDirectives(string $lineFromConstant): void
$this->directives[$matchDirective[$i]] = $matchDirective[$i + 1];
}
}
return true;
}
return false;
}

/**
Expand Down
166 changes: 163 additions & 3 deletions Classes/Utility/TemplateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,26 @@
namespace Oktopuce\SiteGenerator\Utility;

use Doctrine\DBAL\Exception;
use Oktopuce\SiteGenerator\Dto\BaseDto;
use Oktopuce\SiteGenerator\Wizard\Event\UpdateTyposcriptContentEvent;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LogLevel;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;

// Cf. app/vendor/typo3/cms-tstemplate/Classes/Controller/ConstantEditorController.php
class TemplateService
{
public function __construct(private readonly ConnectionPool $connectionPool)
public function __construct(
private readonly EventDispatcherInterface $eventDispatcher,
private readonly ConnectionPool $connectionPool,
private readonly TemplateDirectivesService $templateDirectivesService,
private readonly DataHandler $dataHandler
)
{
}

Expand Down Expand Up @@ -79,8 +89,8 @@ public function calculateConstantPositions(
$operatorPosition = strcspn($line, ' {=<');
$key = substr($line, 0, $operatorPosition);
$line = ltrim(substr($line, $operatorPosition));
if ($line[0] === '=') {
$constantPositions[$prefix . $key] = $lineCounter - 1;
if ($line[0] === '=' || $line[0] === ':') {
$constantPositions[$prefix . $key . "_" . $lineCounter] = $lineCounter - 1;
} elseif ($line[0] === '{') {
$braceLevel++;
$this->calculateConstantPositions($rawTemplateConstantsArray, $constantPositions, $prefix . $key . '.', $braceLevel, $lineCounter);
Expand Down Expand Up @@ -114,4 +124,154 @@ public function updateValueInConf(string $rawConstant, string $var): string
}
return implode('=', $parts);
}

/**
* @param string $table Name database table
* @param array $record Record data to update
* @param string $contentField Name of field which contains the content to update
* @param BaseDto $siteData
* @return bool true if content was update, false if no data was updated
*/
public function updateContent(string $table, array $record, string $contentField, BaseDto $siteData): bool
{
$rawTemplateConstantsArray = explode(LF, $record[$contentField] ?? '');
$constantPositions = $this->calculateConstantPositions($rawTemplateConstantsArray);

$updatedTemplateConstantsArray = [];
$directivesPositions = [];

// For all constants, check if we need to update it
foreach ($constantPositions as $key => $rawP) {
// Looking for directives in comments
if($this->templateDirectivesService->lookForDirectives(($rawP > 0 ? $rawTemplateConstantsArray[$rawP - 1] : ''))) {
$directivesPositions[] = $rawP - 1;
};

$value = GeneralUtility::trimExplode('=', $rawTemplateConstantsArray[$rawP]);

$uidsToExclude = GeneralUtility::trimExplode(',',
$this->templateDirectivesService->getIgnoreUids(), true);
$filteredMapping = $mapping = $siteData->getMappingArrayMerge(
$this->templateDirectivesService->getTable('pages')
);

// Manage uids to exclude
if (!empty($uidsToExclude)) {
$filteredMapping = array_filter($mapping, static function ($key) use ($uidsToExclude) {
return !in_array((string)$key, $uidsToExclude, true);
}, ARRAY_FILTER_USE_KEY);
}

$action = $this->templateDirectivesService->getAction('mapInList');
$updatedValue = '';

switch ($action) {
case 'mapInList' :
$updatedValue = $this->mapInList($value[1], $filteredMapping);
break;
case 'mapInString' :
$updatedValue = $this->mapInString($value[1], $filteredMapping);
break;
case 'exclude' :
// Exclude all line
break;
default :
// Call custom action if there is one
$parameters = $this->templateDirectivesService->getParameters();
$event = $this->eventDispatcher->dispatch(new UpdateTyposcriptContentEvent($action, $parameters,
$value[1], $filteredMapping, $this->templateDirectivesService));
$updatedValue = $event->getUpdatedValue();
break;
}

if (!empty($updatedValue)) {
$updatedTemplateConstantsArray[$rawP] = $updatedValue;
}
}

if ($updatedTemplateConstantsArray) {
foreach ($updatedTemplateConstantsArray as $rowP => $updatedTemplateConstant) {
$rawTemplateConstantsArray[$rowP] = $this->updateValueInConf($rawTemplateConstantsArray[$rowP], $updatedTemplateConstant);
}
if($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['site_generator']['removeDirectivesFromOutput'] ?? true) {
// Remove directives from output
$rawTemplateConstantsArray = array_diff_key($rawTemplateConstantsArray, array_flip($directivesPositions));
}

// Set the data to be saved
$recordData = [];
$recordUid = $record['_ORIG_uid'] ?? $record['uid'];
$recordData[$table][$recordUid][$contentField] = implode(LF, $rawTemplateConstantsArray);
// Create new tce-object
$this->dataHandler->start($recordData, []);
$this->dataHandler->process_datamap();
return true;
}
return false;
}

/**
* Update constant in list
*
* @param string $value
* @param array $filteredMapping
* @return string Empty string or value updated
*/
protected function mapInList(
string $value,
array $filteredMapping
): string {
$functionName = '';
// Check if the value in constant is a list of int - 78,125,98 - or just an int
if (preg_match('/^\\s*([[:alpha:]]+)\\s*\\((.*)\\).*/', $value, $match)) {
$functionName = $match[1];
$value = $match[2];
}
if (preg_match('/^\d+(?:,\d+)*$/', $value)) {
$updateConstant = false;

$listOfInt = GeneralUtility::trimExplode(',', $value, true);

// Set new uid for constants
array_walk($listOfInt,
static function (&$constantValue) use ($filteredMapping, &$updateConstant) {
if (isset($filteredMapping[(int)$constantValue])) {
$constantValue = $filteredMapping[(int)$constantValue];
$updateConstant = true;
}
});
if ($updateConstant) {
$newList = implode(',', $listOfInt);
if($functionName) {
$newList = "$functionName($newList)";
}
return $newList;
}
}
return ('');
}

/**
* Update constants in string
*
* @param string $value
* @param array $filteredMapping
* @return string Empty string or value updated
*/
protected function mapInString(
string $value,
array $filteredMapping
): string {
$updateConstant = false;
$count = 0;

foreach ($filteredMapping as $modelUid => $siteUid) {
$value = str_replace((string)$modelUid, (string)$siteUid, $value, $count);
$updateConstant = ($updateConstant || $count > 0);
}
if ($updateConstant) {
return ($value);
}
return ('');
}
}
130 changes: 130 additions & 0 deletions Classes/Wizard/Event/AbstractUpdateTyposcriptContentEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

declare(strict_types=1);

/*
*
* This file is part of the "Site Generator" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
*/

namespace Oktopuce\SiteGenerator\Wizard\Event;

use Oktopuce\SiteGenerator\Utility\TemplateDirectivesService;

/**
* This event is fired when state updating record with TypoScript (StateUpdateTemplateHP etc) is executed and action is a custom action
* i.e. : different from : mapInList, mapInString or exclude
*/
abstract class AbstractUpdateTyposcriptContentEvent
{
/**
* @var string
*/
private string $updatedValue = '';

/**
* @var string
*/
private string $action;

/**
* @var string
*/
private string $parameters;

/**
* @var array
*/
private array $filteredMapping;

/**
* @var string
*/
private string $value;

/**
* @var TemplateDirectivesService
*/
private TemplateDirectivesService $templateDirectivesService;

/**
* @param string $action The action
* @param string $parameters The parameter
* @param string $value Current value
* @param array $filteredMapping Mapping filtered - i.e. ignoredUids already removed
* @param TemplateDirectivesService $templateDirectivesService
*/
public function __construct(string $action, string $parameters, string $value, array $filteredMapping, TemplateDirectivesService $templateDirectivesService)
{
$this->action = $action;
$this->parameters = $parameters;
$this->value = $value;
$this->filteredMapping = $filteredMapping;
$this->templateDirectivesService = $templateDirectivesService;
}

/**
* @return string
*/
public function getAction(): string
{
return $this->action;
}

/**
* @return string
*/
public function getParameters(): string
{
return $this->parameters;
}

/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}

/**
* @return array
*/
public function getFilteredMapping(): array
{
return $this->filteredMapping;
}

/**
* @return TemplateDirectivesService
*/
public function getTemplateDirectivesService(): TemplateDirectivesService
{
return $this->templateDirectivesService;
}

/**
* Get the updated value
*
* @return string Empty if no update required otherwise the value to update
*/
public function getUpdatedValue(): string
{
return $this->updatedValue;
}

/**
* Set the updated value
*
* @param string $updatedValue The value to update
* @return void
*/
public function setUpdatedValue(string $updatedValue): void
{
$this->updatedValue = $updatedValue;
}
}
Loading