‪TYPO3CMS  11.5
FormSlugAjaxController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
29 
36 {
38 
40  {
41  $this->context = ‪$context;
42  }
43 
71  public function ‪suggestAction(ServerRequestInterface $request): ResponseInterface
72  {
73  $this->‪checkRequest($request);
74 
75  $queryParameters = $request->getParsedBody() ?? [];
76  $values = $queryParameters['values'];
77  $mode = $queryParameters['mode'];
78  $tableName = (string)($queryParameters['tableName'] ?? '');
79  $pid = (int)$queryParameters['pageId'];
80  $parentPageId = (int)$queryParameters['parentPageId'];
81  $recordId = (int)$queryParameters['recordId'];
82  $languageId = (int)$queryParameters['language'];
83  $fieldName = $queryParameters['fieldName'];
84 
85  $fieldConfig = ‪$GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'] ?? [];
86  $row = (array)BackendUtility::getRecord($tableName, $recordId);
87  $recordType = BackendUtility::getTCAtypeValue($tableName, $row);
88  $columnsOverridesConfigOfField = ‪$GLOBALS['TCA'][$tableName]['types'][$recordType]['columnsOverrides'][$fieldName]['config'] ?? null;
89  if ($columnsOverridesConfigOfField) {
90  ‪ArrayUtility::mergeRecursiveWithOverrule($fieldConfig, $columnsOverridesConfigOfField);
91  }
92  if (empty($fieldConfig)) {
93  throw new \RuntimeException(
94  'No valid field configuration for table ' . $tableName . ' field name ' . $fieldName . ' found.',
95  1535379534
96  );
97  }
98 
99  $evalInfo = !empty($fieldConfig['eval']) ? ‪GeneralUtility::trimExplode(',', $fieldConfig['eval'], true) : [];
100  $hasToBeUniqueInDb = in_array('unique', $evalInfo, true);
101  $hasToBeUniqueInSite = in_array('uniqueInSite', $evalInfo, true);
102  $hasToBeUniqueInPid = in_array('uniqueInPid', $evalInfo, true);
103 
104  $hasConflict = false;
105 
106  $recordData = $values;
107  if (!isset($recordData['uid'])) {
108  $recordData['uid'] = $recordId;
109  }
110  $recordData['pid'] = $pid;
111  if (!empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
112  $recordData[‪$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] = $languageId;
113  }
114  if ($tableName === 'pages' && empty($recordData['is_siteroot'])) {
115  $recordData['is_siteroot'] = $row['is_siteroot'] ?? false;
116  }
117 
118  $workspaceId = $this->context->getPropertyFromAspect('workspace', 'id');
119  $slug = GeneralUtility::makeInstance(SlugHelper::class, $tableName, $fieldName, $fieldConfig, $workspaceId);
120  if ($mode === 'auto') {
121  // New page - Feed incoming values to generator
122  $proposal = $slug->generate($recordData, $pid);
123  } elseif ($mode === 'recreate') {
124  $proposal = $slug->generate($recordData, $parentPageId);
125  } elseif ($mode === 'manual') {
126  // Existing record - Fetch full record and only validate against the new "slug" field.
127  $proposal = $slug->sanitize($values['manual']);
128  } else {
129  throw new \RuntimeException('mode must be either "auto", "recreate" or "manual"', 1535835666);
130  }
131 
132  $state = ‪RecordStateFactory::forName($tableName)
133  ->fromArray($recordData, $pid, $recordId);
134  if ($hasToBeUniqueInDb && !$slug->isUniqueInTable($proposal, $state)) {
135  $hasConflict = true;
136  $proposal = $slug->buildSlugForUniqueInTable($proposal, $state);
137  }
138  if ($hasToBeUniqueInSite && !$slug->isUniqueInSite($proposal, $state)) {
139  $hasConflict = true;
140  $proposal = $slug->buildSlugForUniqueInSite($proposal, $state);
141  }
142  if ($hasToBeUniqueInPid && !$slug->isUniqueInPid($proposal, $state)) {
143  $hasConflict = true;
144  $proposal = $slug->buildSlugForUniqueInPid($proposal, $state);
145  }
146 
147  return new ‪JsonResponse([
148  'hasConflicts' => $hasConflict,
149  'manual' => $values['manual'] ?? '',
150  'proposal' => $proposal,
151  ]);
152  }
153 
159  protected function ‪checkRequest(ServerRequestInterface $request): bool
160  {
161  $queryParameters = $request->getParsedBody() ?? [];
162  $expectedHash = GeneralUtility::hmac(
163  implode(
164  '',
165  [
166  $queryParameters['tableName'],
167  $queryParameters['pageId'],
168  $queryParameters['recordId'],
169  $queryParameters['language'],
170  $queryParameters['fieldName'],
171  $queryParameters['command'],
172  $queryParameters['parentPageId'],
173  ]
174  ),
175  __CLASS__
176  );
177  if (!hash_equals($expectedHash, $queryParameters['signature'])) {
178  throw new \InvalidArgumentException(
179  'HMAC could not be verified',
180  1535137045
181  );
182  }
183  return true;
184  }
185 }
‪TYPO3\CMS\Backend\Controller\FormSlugAjaxController\suggestAction
‪ResponseInterface suggestAction(ServerRequestInterface $request)
Definition: FormSlugAjaxController.php:71
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Backend\Controller\FormSlugAjaxController\__construct
‪__construct(Context $context)
Definition: FormSlugAjaxController.php:39
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory
Definition: RecordStateFactory.php:26
‪TYPO3\CMS\Backend\Controller\FormSlugAjaxController\$context
‪Context $context
Definition: FormSlugAjaxController.php:37
‪TYPO3\CMS\Core\DataHandling\SlugHelper
Definition: SlugHelper.php:43
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Controller\AbstractFormEngineAjaxController
Definition: AbstractFormEngineAjaxController.php:38
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:16
‪TYPO3\CMS\Backend\Controller\FormSlugAjaxController
Definition: FormSlugAjaxController.php:36
‪TYPO3\CMS\Backend\Controller\FormSlugAjaxController\checkRequest
‪bool checkRequest(ServerRequestInterface $request)
Definition: FormSlugAjaxController.php:159
‪TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory\forName
‪static static forName(string $name)
Definition: RecordStateFactory.php:35