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