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