Project

General

Profile

Bug #101798 » PreventSavingUnchangedInlineRecords.php

workaround middleware - Sebastian Michaelsen, 2023-08-30 11:27

 
<?php

declare(strict_types=1);

namespace Acme\Sitepackage\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;

class PreventSavingUnchangedInlineRecords implements MiddlewareInterface
{
private ConnectionPool $connectionPool;

public function __construct(ConnectionPool $connectionPool)
{
$this->connectionPool = $connectionPool;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (!$this->isSubmittedRecordFormRequest($request)) {
return $handler->handle($request);
}

$request = $this->removeRecordsWithOnlyUnchangedHiddenField($request);

return $handler->handle($request);
}

private function isSubmittedRecordFormRequest(ServerRequestInterface $request): bool
{
if ($request->getMethod() !== 'POST') {
return false;
}
return ($request->getQueryParams()['route'] ?? '') === '/record/edit';
}

private function removeRecordsWithOnlyUnchangedHiddenField(ServerRequestInterface $request): ServerRequestInterface
{
$parsedBody = $request->getParsedBody();
if (empty($parsedBody['data'])) {
return $request;
}

foreach ($parsedBody['data'] as $tableName => $records) {
if (empty($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns']['disabled'])) {
continue; // table does not feature a hidden field
}
$hiddenFieldName = $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns']['disabled'];
foreach ($records as $recordUid => $record) {
if (array_keys($record) !== [$hiddenFieldName]) {
continue; // not only the hidden field is changed
}
if ((bool)$record[$hiddenFieldName] !== $this->isHiddenInDatabase($tableName, $recordUid)) {
continue; // the hidden value was changed
}
unset($parsedBody['data'][$tableName][$recordUid]);
$request = $request->withParsedBody($parsedBody);
}
}

return $request;
}

private function isHiddenInDatabase(string $tableName, int $recordUid): bool
{
$queryBuilder = $this->connectionPool->getQueryBuilderForTable($tableName);
$queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
$value = $queryBuilder
->select($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns']['disabled'])
->from($tableName)
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($recordUid, \PDO::PARAM_INT))
)
->execute()
->fetchOne();
return (bool)$value;
}
}
(1-1/2)