‪TYPO3CMS  10.4
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 
20 use Doctrine\DBAL\Connection;
34 
55 {
56  use ‪AspectTrait;
61 
65  protected ‪$settings;
66 
70  protected ‪$tableName;
71 
75  protected ‪$routeFieldName;
76 
81 
85  protected ‪$persistenceFieldNames;
86 
90  protected ‪$languageFieldName;
91 
96 
100  protected ‪$slugUniqueInSite;
101 
106  public function ‪__construct(array ‪$settings)
107  {
108  ‪$tableName = ‪$settings['tableName'] ?? null;
109  ‪$routeFieldName = ‪$settings['routeFieldName'] ?? null;
110  ‪$routeValuePrefix = ‪$settings['routeValuePrefix'] ?? '';
111 
112  if (!is_string(‪$tableName)) {
113  throw new \InvalidArgumentException(
114  'tableName must be string',
115  1537277133
116  );
117  }
118  if (!is_string(‪$routeFieldName)) {
119  throw new \InvalidArgumentException(
120  'routeFieldName name must be string',
121  1537277134
122  );
123  }
124  if (!is_string(‪$routeValuePrefix) || strlen(‪$routeValuePrefix) > 1) {
125  throw new \InvalidArgumentException(
126  '$routeValuePrefix must be string with one character',
127  1537277136
128  );
129  }
130 
131  $this->settings = ‪$settings;
132  $this->tableName = ‪$tableName;
133  $this->routeFieldName = ‪$routeFieldName;
134  $this->routeValuePrefix = ‪$routeValuePrefix;
135  $this->languageFieldName = ‪$GLOBALS['TCA'][‪$this->tableName]['ctrl']['languageField'] ?? null;
136  $this->languageParentFieldName = ‪$GLOBALS['TCA'][‪$this->tableName]['ctrl']['transOrigPointerField'] ?? null;
137  $this->persistenceFieldNames = $this->‪buildPersistenceFieldNames();
138  $this->slugUniqueInSite = $this->isSlugUniqueInSite($this->tableName, $this->routeFieldName);
139  }
140 
144  public function ‪generate(string $value): ?string
145  {
146  $result = $this->‪findByIdentifier($value);
147  $result = $this->‪resolveOverlay($result);
148  if (!isset($result[$this->routeFieldName])) {
149  return null;
150  }
152  (string)$result[$this->routeFieldName]
153  );
154  }
155 
159  public function ‪resolve(string $value): ?string
160  {
161  $value = $this->routeValuePrefix . $this->‪purgeRouteValuePrefix($value);
162  $result = $this->‪findByRouteFieldValue($value);
163  if ($result[$this->languageParentFieldName] ?? null > 0) {
164  return (string)$result[‪$this->languageParentFieldName];
165  }
166  if (isset($result['uid'])) {
167  return (string)$result['uid'];
168  }
169  return null;
170  }
171 
175  protected function ‪buildPersistenceFieldNames(): array
176  {
177  return array_filter([
178  'uid',
179  'pid',
180  $this->routeFieldName,
181  $this->languageFieldName,
182  $this->languageParentFieldName,
183  ]);
184  }
185 
190  protected function ‪purgeRouteValuePrefix(?string $value): ?string
191  {
192  if (empty($this->routeValuePrefix) || $value === null) {
193  return $value;
194  }
195  return ltrim($value, $this->routeValuePrefix);
196  }
197 
198  protected function ‪findByIdentifier(string $value): ?array
199  {
200  $queryBuilder = $this->‪createQueryBuilder();
201  $result = $queryBuilder
202  ->select(...$this->persistenceFieldNames)
203  ->where($queryBuilder->expr()->eq(
204  'uid',
205  $queryBuilder->createNamedParameter($value, \PDO::PARAM_INT)
206  ))
207  ->execute()
208  ->fetch();
209  return $result !== false ? $result : null;
210  }
211 
212  protected function ‪findByRouteFieldValue(string $value): ?array
213  {
214  $languageAware = $this->languageFieldName !== null && $this->languageParentFieldName !== null;
215 
216  $queryBuilder = $this->‪createQueryBuilder();
217  $constraints = [
218  $queryBuilder->expr()->eq(
219  $this->routeFieldName,
220  $queryBuilder->createNamedParameter($value, \PDO::PARAM_STR)
221  ),
222  ];
223 
224  $languageIds = null;
225  if ($languageAware) {
226  $languageIds = $this->resolveAllRelevantLanguageIds();
227  $constraints[] = $queryBuilder->expr()->in(
228  $this->languageFieldName,
229  $queryBuilder->createNamedParameter($languageIds, Connection::PARAM_INT_ARRAY)
230  );
231  }
232 
233  $results = $queryBuilder
234  ->select(...$this->persistenceFieldNames)
235  ->where(...$constraints)
236  ->execute()
237  ->fetchAll();
238  // limit results to be contained in rootPageId of current Site
239  // (which is defining the route configuration currently being processed)
240  if ($this->slugUniqueInSite) {
241  $results = array_values($this->filterContainedInSite($results));
242  }
243  // return first result record in case table is not language aware
244  if (!$languageAware) {
245  return $results[0] ?? null;
246  }
247  // post-process language fallbacks
248  return $this->resolveLanguageFallback($results, $this->languageFieldName, $languageIds);
249  }
250 
251  protected function ‪createQueryBuilder(): QueryBuilder
252  {
253  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
254  ->getQueryBuilderForTable($this->tableName)
255  ->from($this->tableName);
256  $queryBuilder->setRestrictions(
257  GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
258  );
259  // Frontend Groups are not available at this time (initialized via TSFE->determineId)
260  // So this must be excluded to allow access restricted records
261  $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
262  return $queryBuilder;
263  }
264 
269  protected function ‪resolveOverlay(?array $record): ?array
270  {
271  $languageId = $this->siteLanguage->getLanguageId();
272  if ($record === null || $languageId === 0) {
273  return $record;
274  }
275 
276  $pageRepository = $this->‪createPageRepository();
277  if ($this->tableName === 'pages') {
278  return $pageRepository->getPageOverlay($record, $languageId);
279  }
280  return $pageRepository
281  ->getRecordOverlay($this->tableName, $record, $languageId) ?: null;
282  }
283 
287  protected function ‪createPageRepository(): ‪PageRepository
288  {
289  $context = clone GeneralUtility::makeInstance(Context::class);
290  $context->setAspect(
291  'language',
293  );
294  return GeneralUtility::makeInstance(
295  PageRepository::class,
296  $context
297  );
298  }
299 }
‪TYPO3\CMS\Core\Context\LanguageAspectFactory
Definition: LanguageAspectFactory.php:27
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\buildPersistenceFieldNames
‪string[] buildPersistenceFieldNames()
Definition: PersistedAliasMapper.php:167
‪TYPO3\CMS\Core\Context\ContextAwareTrait
Definition: ContextAwareTrait.php:21
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\createPageRepository
‪PageRepository createPageRepository()
Definition: PersistedAliasMapper.php:279
‪TYPO3\CMS\Core\Routing\Aspect\SiteAccessorTrait
Definition: SiteAccessorTrait.php:31
‪TYPO3\CMS\Core\Site\SiteLanguageAwareInterface
Definition: SiteLanguageAwareInterface.php:26
‪TYPO3\CMS\Core\Routing\Legacy\PersistedAliasMapperLegacyTrait
Definition: PersistedAliasMapperLegacyTrait.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\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$tableName
‪string $tableName
Definition: PersistedAliasMapper.php:68
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$routeFieldName
‪string $routeFieldName
Definition: PersistedAliasMapper.php:72
‪TYPO3\CMS\Core\Site\SiteAwareInterface
Definition: SiteAwareInterface.php:26
‪TYPO3\CMS\Core\Database\Query\QueryBuilder
Definition: QueryBuilder.php:52
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\purgeRouteValuePrefix
‪string purgeRouteValuePrefix(?string $value)
Definition: PersistedAliasMapper.php:182
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\from
‪QueryBuilder from(string $from, string $alias=null)
Definition: QueryBuilder.php:531
‪TYPO3\CMS\Core\Routing\Aspect\SiteLanguageAccessorTrait
Definition: SiteLanguageAccessorTrait.php:26
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$routeValuePrefix
‪string $routeValuePrefix
Definition: PersistedAliasMapper.php:76
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\resolve
‪resolve(string $value)
Definition: PersistedAliasMapper.php:151
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$settings
‪array $settings
Definition: PersistedAliasMapper.php:64
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\findByIdentifier
‪findByIdentifier(string $value)
Definition: PersistedAliasMapper.php:190
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper
Definition: PersistedAliasMapper.php:55
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\resolveOverlay
‪array null resolveOverlay(?array $record)
Definition: PersistedAliasMapper.php:261
‪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:5
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\generate
‪generate(string $value)
Definition: PersistedAliasMapper.php:136
‪TYPO3\CMS\Core\Routing\Aspect\AspectTrait
Definition: AspectTrait.php:23
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\__construct
‪__construct(array $settings)
Definition: PersistedAliasMapper.php:98
‪TYPO3\CMS\Core\Routing\Aspect\StaticMappableAspectInterface
Definition: StaticMappableAspectInterface.php:24
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\createQueryBuilder
‪createQueryBuilder()
Definition: PersistedAliasMapper.php:243
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$slugUniqueInSite
‪bool $slugUniqueInSite
Definition: PersistedAliasMapper.php:92
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$persistenceFieldNames
‪string[] $persistenceFieldNames
Definition: PersistedAliasMapper.php:80
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:52
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:31
‪TYPO3\CMS\Core\Database\Query\QueryBuilder\setRestrictions
‪setRestrictions(QueryRestrictionContainerInterface $restrictionContainer)
Definition: QueryBuilder.php:112
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$languageFieldName
‪string null $languageFieldName
Definition: PersistedAliasMapper.php:84
‪TYPO3\CMS\Core\Routing\Aspect\PersistedMappableAspectInterface
Definition: PersistedMappableAspectInterface.php:25
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\findByRouteFieldValue
‪findByRouteFieldValue(string $value)
Definition: PersistedAliasMapper.php:204
‪TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper\$languageParentFieldName
‪string null $languageParentFieldName
Definition: PersistedAliasMapper.php:88