‪TYPO3CMS  11.5
PersistedAliasMapper.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 
25 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
32 
53 {
54  use ‪AspectTrait;
58 
62  protected ‪$settings;
63 
67  protected ‪$tableName;
68 
72  protected ‪$routeFieldName;
73 
78 
82  protected ‪$persistenceFieldNames;
83 
87  protected ‪$languageFieldName;
88 
93 
97  protected ‪$slugUniqueInSite;
98 
103  public function ‪__construct(array ‪$settings)
104  {
105  ‪$tableName = ‪$settings['tableName'] ?? null;
106  ‪$routeFieldName = ‪$settings['routeFieldName'] ?? null;
107  ‪$routeValuePrefix = ‪$settings['routeValuePrefix'] ?? '';
108 
109  if (!is_string(‪$tableName)) {
110  throw new \InvalidArgumentException(
111  'tableName must be string',
112  1537277133
113  );
114  }
115  if (!is_string(‪$routeFieldName)) {
116  throw new \InvalidArgumentException(
117  'routeFieldName name must be string',
118  1537277134
119  );
120  }
121  if (!is_string(‪$routeValuePrefix) || strlen(‪$routeValuePrefix) > 1) {
122  throw new \InvalidArgumentException(
123  '$routeValuePrefix must be string with one character',
124  1537277136
125  );
126  }
127 
128  $this->settings = ‪$settings;
129  $this->tableName = ‪$tableName;
130  $this->routeFieldName = ‪$routeFieldName;
131  $this->routeValuePrefix = ‪$routeValuePrefix;
132  $this->languageFieldName = ‪$GLOBALS['TCA'][‪$this->tableName]['ctrl']['languageField'] ?? null;
133  $this->languageParentFieldName = ‪$GLOBALS['TCA'][‪$this->tableName]['ctrl']['transOrigPointerField'] ?? null;
134  $this->persistenceFieldNames = $this->‪buildPersistenceFieldNames();
135  $this->slugUniqueInSite = $this->isSlugUniqueInSite($this->tableName, $this->routeFieldName);
136  }
137 
141  public function ‪generate(string $value): ?string
142  {
143  $result = $this->‪findByIdentifier($value);
144  $result = $this->‪resolveOverlay($result);
145  if (!isset($result[$this->routeFieldName])) {
146  return null;
147  }
149  (string)$result[$this->routeFieldName]
150  );
151  }
152 
156  public function ‪resolve(string $value): ?string
157  {
158  $value = $this->routeValuePrefix . $this->‪purgeRouteValuePrefix($value);
159  $result = $this->‪findByRouteFieldValue($value);
160  if (($result[$this->languageParentFieldName] ?? null) > 0) {
161  return (string)$result[‪$this->languageParentFieldName];
162  }
163  if (isset($result['uid'])) {
164  return (string)$result['uid'];
165  }
166  return null;
167  }
168 
172  protected function ‪buildPersistenceFieldNames(): array
173  {
174  return array_filter([
175  'uid',
176  'pid',
177  $this->routeFieldName,
178  $this->languageFieldName,
179  $this->languageParentFieldName,
180  ]);
181  }
182 
187  protected function ‪purgeRouteValuePrefix(?string $value): ?string
188  {
189  if (empty($this->routeValuePrefix) || $value === null) {
190  return $value;
191  }
192  return ltrim($value, $this->routeValuePrefix);
193  }
194 
195  protected function ‪findByIdentifier(string $value): ?array
196  {
197  $queryBuilder = $this->‪createQueryBuilder();
198  $result = $queryBuilder
199  ->select(...$this->persistenceFieldNames)
200  ->where($queryBuilder->expr()->eq(
201  'uid',
202  $queryBuilder->createNamedParameter($value, \‪TYPO3\CMS\Core\Database\‪Connection::PARAM_INT)
203  ))
204  ->executeQuery()
205  ->fetchAssociative();
206  return $result !== false ? $result : null;
207  }
208 
209  protected function ‪findByRouteFieldValue(string $value): ?array
210  {
211  $languageAware = $this->languageFieldName !== null && $this->languageParentFieldName !== null;
212 
213  $queryBuilder = $this->‪createQueryBuilder();
214  $constraints = [
215  $queryBuilder->expr()->eq(
216  $this->routeFieldName,
217  $queryBuilder->createNamedParameter($value, \‪TYPO3\CMS\Core\Database\‪Connection::PARAM_STR)
218  ),
219  ];
220 
221  $languageIds = null;
222  if ($languageAware) {
223  $languageIds = $this->resolveAllRelevantLanguageIds();
224  $constraints[] = $queryBuilder->expr()->in(
225  $this->languageFieldName,
226  $queryBuilder->createNamedParameter($languageIds, \‪TYPO3\CMS\Core\Database\Connection::PARAM_INT_ARRAY)
227  );
228  }
229 
230  $results = $queryBuilder
231  ->select(...$this->persistenceFieldNames)
232  ->where(...$constraints)
233  ->executeQuery()
234  ->fetchAllAssociative();
235  // limit results to be contained in rootPageId of current Site
236  // (which is defining the route configuration currently being processed)
237  if ($this->slugUniqueInSite) {
238  $results = array_values($this->filterContainedInSite($results));
239  }
240  // return first result record in case table is not language aware
241  if (!$languageAware) {
242  return $results[0] ?? null;
243  }
244  // post-process language fallbacks
245  return $this->resolveLanguageFallback($results, $this->languageFieldName, $languageIds);
246  }
247 
248  protected function ‪createQueryBuilder(): QueryBuilder
249  {
250  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
251  ->getQueryBuilderForTable($this->tableName)
252  ->from($this->tableName);
253  $queryBuilder->setRestrictions(
254  GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
255  );
256  // Frontend Groups are not available at this time (initialized via TSFE->determineId)
257  // So this must be excluded to allow access restricted records
258  $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
259  return $queryBuilder;
260  }
261 
266  protected function ‪resolveOverlay(?array $record): ?array
267  {
268  $languageId = $this->siteLanguage->getLanguageId();
269  if ($record === null || $languageId === 0) {
270  return $record;
271  }
272 
273  $pageRepository = $this->‪createPageRepository();
274  if ($this->tableName === 'pages') {
275  return $pageRepository->getPageOverlay($record, $languageId);
276  }
277  return $pageRepository
278  ->getRecordOverlay($this->tableName, $record, $languageId) ?: null;
279  }
280 
284  protected function ‪createPageRepository(): ‪PageRepository
285  {
286  $context = clone GeneralUtility::makeInstance(Context::class);
287  $context->setAspect(
288  'language',
290  );
291  return GeneralUtility::makeInstance(
292  PageRepository::class,
293  $context
294  );
295  }
296 }
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Core\Context\LanguageAspectFactory
Definition: LanguageAspectFactory.php:27
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\buildPersistenceFieldNames
‪string[] buildPersistenceFieldNames()
Definition: PersistedAliasMapper.php:164
‪TYPO3\CMS\Core\Context\ContextAwareTrait
Definition: ContextAwareTrait.php:21
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\createPageRepository
‪PageRepository createPageRepository()
Definition: PersistedAliasMapper.php:276
‪TYPO3
‪TYPO3\CMS\Core\Routing\Aspect\SiteAccessorTrait
Definition: SiteAccessorTrait.php:31
‪TYPO3\CMS\Core\Site\SiteLanguageAwareInterface
Definition: SiteLanguageAwareInterface.php:26
‪TYPO3\CMS\Core\Context\LanguageAspectFactory\createFromSiteLanguage
‪static LanguageAspect createFromSiteLanguage(SiteLanguage $language)
Definition: LanguageAspectFactory.php:34
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendGroupRestriction
Definition: FrontendGroupRestriction.php:30
‪TYPO3\CMS\Core\Database\Connection\PARAM_STR
‪const PARAM_STR
Definition: Connection.php:54
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$tableName
‪string $tableName
Definition: PersistedAliasMapper.php:65
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$routeFieldName
‪string $routeFieldName
Definition: PersistedAliasMapper.php:69
‪TYPO3\CMS\Core\Site\SiteAwareInterface
Definition: SiteAwareInterface.php:26
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\purgeRouteValuePrefix
‪string purgeRouteValuePrefix(?string $value)
Definition: PersistedAliasMapper.php:179
‪TYPO3\CMS\Core\Routing\Aspect\SiteLanguageAccessorTrait
Definition: SiteLanguageAccessorTrait.php:26
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$routeValuePrefix
‪string $routeValuePrefix
Definition: PersistedAliasMapper.php:73
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\resolve
‪resolve(string $value)
Definition: PersistedAliasMapper.php:148
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$settings
‪array $settings
Definition: PersistedAliasMapper.php:61
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\findByIdentifier
‪findByIdentifier(string $value)
Definition: PersistedAliasMapper.php:187
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper
Definition: PersistedAliasMapper.php:53
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\resolveOverlay
‪array null resolveOverlay(?array $record)
Definition: PersistedAliasMapper.php:258
‪TYPO3\CMS\Core\Routing\Aspect
Definition: AspectFactory.php:18
‪TYPO3\CMS\Core\Context\ContextAwareInterface
Definition: ContextAwareInterface.php:21
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\generate
‪generate(string $value)
Definition: PersistedAliasMapper.php:133
‪TYPO3\CMS\Core\Routing\Aspect\AspectTrait
Definition: AspectTrait.php:23
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\__construct
‪__construct(array $settings)
Definition: PersistedAliasMapper.php:95
‪TYPO3\CMS\Core\Routing\Aspect\StaticMappableAspectInterface
Definition: StaticMappableAspectInterface.php:23
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\createQueryBuilder
‪createQueryBuilder()
Definition: PersistedAliasMapper.php:240
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$slugUniqueInSite
‪bool $slugUniqueInSite
Definition: PersistedAliasMapper.php:89
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$persistenceFieldNames
‪string[] $persistenceFieldNames
Definition: PersistedAliasMapper.php:77
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:31
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$languageFieldName
‪string null $languageFieldName
Definition: PersistedAliasMapper.php:81
‪TYPO3\CMS\Core\Routing\Aspect\PersistedMappableAspectInterface
Definition: PersistedMappableAspectInterface.php:24
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\findByRouteFieldValue
‪findByRouteFieldValue(string $value)
Definition: PersistedAliasMapper.php:201
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$languageParentFieldName
‪string null $languageParentFieldName
Definition: PersistedAliasMapper.php:85