250 lines
11 KiB
PHP
250 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Backend\Controller\Wizard;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use TYPO3\CMS\Backend\Attribute\AsController;
|
|
use TYPO3\CMS\Backend\Form\FormDataCompiler;
|
|
use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
|
|
use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
|
|
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
|
use TYPO3\CMS\Core\DataHandling\DataHandler;
|
|
use TYPO3\CMS\Core\Http\RedirectResponse;
|
|
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\Utility\MathUtility;
|
|
|
|
/**
|
|
* Script Class for adding new items to a group/select field. Performs proper redirection as needed.
|
|
* Script is typically called after new child record was added and then adds the new child to select value of parent.
|
|
*
|
|
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
|
*/
|
|
#[AsController]
|
|
class AddController
|
|
{
|
|
/**
|
|
* If set, the DataHandler class is loaded and used to add the returning ID to the parent record.
|
|
*/
|
|
protected int $processDataFlag = 0;
|
|
|
|
/**
|
|
* Create new record -pid (pos/neg). If blank, return immediately
|
|
*/
|
|
protected int $pid = 0;
|
|
|
|
/**
|
|
* The parent table we are working on.
|
|
*/
|
|
protected string $table = '';
|
|
|
|
/**
|
|
* Loaded with the created id of a record FormEngine returns ...
|
|
*/
|
|
protected int $id = 0;
|
|
|
|
/**
|
|
* Wizard parameters, coming from TCEforms linking to the wizard.
|
|
*/
|
|
protected array $P = [];
|
|
|
|
/**
|
|
* Information coming back from the FormEngine script, telling what the table/id was of the newly created record.
|
|
*/
|
|
protected string $returnEditConf = '';
|
|
|
|
public function __construct(
|
|
private readonly FormDataCompiler $formDataCompiler,
|
|
private readonly UriBuilder $uriBuilder,
|
|
) {}
|
|
|
|
/**
|
|
* Injects the request object for the current request or subrequest
|
|
* As this controller goes only through the main() method, it is rather simple for now
|
|
*/
|
|
public function mainAction(ServerRequestInterface $request): ResponseInterface
|
|
{
|
|
$this->init($request);
|
|
|
|
if ($this->returnEditConf) {
|
|
if ($this->processDataFlag) {
|
|
// Because OnTheFly can't handle MM relations with intermediate tables we use TcaDatabaseRecord here
|
|
// Otherwise already stored relations are overwritten with the new entry
|
|
$input = [
|
|
'request' => $request,
|
|
'tableName' => $this->P['table'],
|
|
'vanillaUid' => (int)$this->P['uid'],
|
|
'command' => 'edit',
|
|
];
|
|
$result = $this->formDataCompiler->compile($input, GeneralUtility::makeInstance(TcaDatabaseRecord::class));
|
|
$currentParentRow = $result['databaseRow'];
|
|
|
|
// If that record was found (should absolutely be...), then init DataHandler and set, prepend or append
|
|
// the record
|
|
if (is_array($currentParentRow)) {
|
|
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
|
|
$data = [];
|
|
$recordId = $this->table . '_' . $this->id;
|
|
// Setting the new field data:
|
|
// If the field is a flexForm field, work with the XML structure instead:
|
|
if ($this->P['flexFormPath']) {
|
|
// Current value of flexForm path:
|
|
$currentFlexFormData = $currentParentRow[$this->P['field']];
|
|
$currentFlexFormValueByPath = ArrayUtility::getValueByPath($currentFlexFormData, $this->P['flexFormPath']);
|
|
|
|
// Compile currentFlexFormData to functional string
|
|
$currentFlexFormValues = [];
|
|
foreach ($currentFlexFormValueByPath as $value) {
|
|
if (is_array($value)) {
|
|
// group fields are always resolved to array
|
|
$currentFlexFormValues[] = $value['table'] . '_' . $value['uid'];
|
|
} else {
|
|
// but select fields may be uids only
|
|
$currentFlexFormValues[] = $value;
|
|
}
|
|
}
|
|
$currentFlexFormValue = implode(',', $currentFlexFormValues);
|
|
|
|
$insertValue = '';
|
|
switch ((string)$this->P['params']['setValue']) {
|
|
case 'set':
|
|
$insertValue = $recordId;
|
|
break;
|
|
case 'append':
|
|
$insertValue = $currentFlexFormValue . ',' . $recordId;
|
|
break;
|
|
case 'prepend':
|
|
$insertValue = $recordId . ',' . $currentFlexFormValue;
|
|
break;
|
|
}
|
|
$insertValue = implode(',', GeneralUtility::trimExplode(',', $insertValue, true));
|
|
$data[$this->P['table']][$this->P['uid']][$this->P['field']] = ArrayUtility::setValueByPath([], $this->P['flexFormPath'], $insertValue);
|
|
} else {
|
|
$currentValue = $currentParentRow[$this->P['field']];
|
|
|
|
// Normalize CSV values
|
|
if (!is_array($currentValue)) {
|
|
$currentValue = GeneralUtility::trimExplode(',', $currentValue, true);
|
|
}
|
|
|
|
// Normalize all items to "<table>_<uid>" format
|
|
$currentValue = array_map(function (array|int|string $item): string {
|
|
// Handle per-item table for "group" elements
|
|
if (is_array($item)) {
|
|
$item = $item['table'] . '_' . $item['uid'];
|
|
} else {
|
|
$item = $this->table . '_' . $item;
|
|
}
|
|
|
|
return $item;
|
|
}, $currentValue);
|
|
|
|
switch ((string)$this->P['params']['setValue']) {
|
|
case 'set':
|
|
$currentValue = [$recordId];
|
|
break;
|
|
case 'append':
|
|
$currentValue[] = $recordId;
|
|
break;
|
|
case 'prepend':
|
|
array_unshift($currentValue, $recordId);
|
|
break;
|
|
}
|
|
|
|
$data[$this->P['table']][$this->P['uid']][$this->P['field']] = implode(',', $currentValue);
|
|
}
|
|
// Submit the data:
|
|
$dataHandler->start($data, []);
|
|
$dataHandler->process_datamap();
|
|
}
|
|
}
|
|
// Return to the parent FormEngine record editing session:
|
|
return new RedirectResponse(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl'], $request));
|
|
}
|
|
|
|
// Redirecting to FormEngine with instructions to create a new record
|
|
// AND when closing to return back with information about that records ID etc.
|
|
$normalizedParams = $request->getAttribute('normalizedParams');
|
|
$redirectUrl = (string)$this->uriBuilder->buildUriFromRoute('record_edit', [
|
|
'returnEditConf' => 1,
|
|
'edit[' . $this->P['params']['table'] . '][' . $this->pid . ']' => 'new',
|
|
// @todo add module context to wizard/add routes and set module context here
|
|
'returnUrl' => $normalizedParams->getRequestUri(),
|
|
]);
|
|
|
|
return new RedirectResponse($redirectUrl);
|
|
}
|
|
|
|
/**
|
|
* Initialization of the class.
|
|
*/
|
|
protected function init(ServerRequestInterface $request): void
|
|
{
|
|
$parsedBody = $request->getParsedBody();
|
|
$queryParams = $request->getQueryParams();
|
|
// Init GPvars:
|
|
$this->P = $parsedBody['P'] ?? $queryParams['P'] ?? [];
|
|
$this->returnEditConf = $parsedBody['returnEditConf'] ?? $queryParams['returnEditConf'] ?? '';
|
|
// Get this record
|
|
$record = BackendUtility::getRecord($this->P['table'], $this->P['uid']);
|
|
// Set table:
|
|
$this->table = $this->P['params']['table'];
|
|
// Get TSconfig for it.
|
|
$TSconfig = FormEngineUtility::getTCEFORM_TSconfig(
|
|
$this->P['table'],
|
|
is_array($record) ? $record : ['pid' => (int)$this->P['params']['pid']]
|
|
);
|
|
// Set [params][pid]
|
|
if (str_starts_with($this->P['params']['pid'], '###') && str_ends_with($this->P['params']['pid'], '###')) {
|
|
$keyword = substr($this->P['params']['pid'], 3, -3);
|
|
$this->pid = str_starts_with($keyword, 'PAGE_TSCONFIG_')
|
|
? (int)$TSconfig[$this->P['field']][$keyword]
|
|
: (int)$TSconfig['_' . $keyword];
|
|
} else {
|
|
$this->pid = (int)$this->P['params']['pid'];
|
|
}
|
|
|
|
// If a new id has returned from a newly created record...
|
|
if ($this->returnEditConf) {
|
|
$editConfiguration = json_decode($this->returnEditConf, true);
|
|
if (is_array($editConfiguration[$this->table]) && MathUtility::canBeInterpretedAsInteger($this->P['uid'])) {
|
|
// Getting id and cmd from returning editConf array.
|
|
reset($editConfiguration[$this->table]);
|
|
$this->id = (int)key($editConfiguration[$this->table]);
|
|
$cmd = current($editConfiguration[$this->table]);
|
|
// ... and if everything seems OK we will register some classes for inclusion and instruct the object
|
|
// to perform processing later.
|
|
if ($this->P['params']['setValue']
|
|
&& $cmd === 'edit'
|
|
&& $this->id
|
|
&& $this->P['table']
|
|
&& $this->P['field'] && $this->P['uid']
|
|
) {
|
|
$liveRecord = BackendUtility::getLiveVersionOfRecord($this->table, $this->id, 'uid');
|
|
if ($liveRecord) {
|
|
$this->id = $liveRecord['uid'];
|
|
}
|
|
$this->processDataFlag = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|