TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user