‪TYPO3CMS  ‪main
IntegrityService.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 
27 
32 {
36  private ‪$redirectService;
37 
41  private ‪$siteFinder;
42 
44  {
45  $this->siteFinder = ‪$siteFinder ?? GeneralUtility::makeInstance(SiteFinder::class);
46  $this->redirectService = ‪$redirectService ?? GeneralUtility::makeInstance(
47  RedirectService::class,
48  GeneralUtility::makeInstance(RedirectCacheService::class),
49  GeneralUtility::makeInstance(LinkService::class),
50  $this->siteFinder
51  );
52  }
53 
57  public function ‪findConflictingRedirects(?string ‪$siteIdentifier = null): \Generator
58  {
59  foreach ($this->‪getSites(‪$siteIdentifier) as $site) {
60  // Collect page urls for all pages and languages for $site.
61  $urls = $this->‪getAllPageUrlsForSite($site);
62  foreach ($urls as ‪$url) {
63  $uri = new ‪Uri(‪$url);
64  $matchingRedirect = $this->‪getMatchingRedirectByUri($uri);
65  if ($matchingRedirect !== null) {
66  // @todo Returning information should be improved in future to give more useful information in
67  // command output and report output, for example redirect uid, page/language details, which would
68  // make the life easier for using the command and finding the conflicts.
69  yield [
70  'uri' => (string)$uri,
71  'redirect' => [
72  'source_host' => $matchingRedirect['source_host'],
73  'source_path' => $matchingRedirect['source_path'],
74  ],
75  ];
76  }
77  }
78  }
79  }
80 
81  private function ‪getMatchingRedirectByUri(‪Uri $uri): ?array
82  {
83  $port = $uri->‪getPort();
84  $domain = $uri->‪getHost() . ($port ? ':' . $port : '');
85  return $this->redirectService->matchRedirect($domain, $uri->‪getPath());
86  }
87 
91  private function ‪getSites(?string ‪$siteIdentifier): array
92  {
93  if (‪$siteIdentifier !== null) {
94  return [$this->siteFinder->getSiteByIdentifier(‪$siteIdentifier)];
95  }
96 
97  return $this->siteFinder->getAllSites();
98  }
99 
103  private function ‪getAllPageUrlsForSite(Site $site): array
104  {
105  $pageUrls = [];
106 
107  // language bases - redirects would be nasty, but should be checked also. We do not need to add site base
108  // here, as there is always at least one default language.
109  foreach ($site->getLanguages() as $siteLanguage) {
110  $pageUrls[] = rtrim((string)$siteLanguage->getBase(), '/') . '/';
111  }
112 
113  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
114  ->getQueryBuilderForTable('pages')
115  ->select('slug', $this->‪getPagesLanguageFieldName())
116  ->from('pages');
117 
118  $queryBuilder->where(
119  $queryBuilder->expr()->or(
120  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($site->getRootPageId(), ‪Connection::PARAM_INT)),
121  $queryBuilder->expr()->eq($this->getPagesLanguageParentFieldName(), $queryBuilder->createNamedParameter($site->getRootPageId(), ‪Connection::PARAM_INT)),
122  )
123  );
124  $result = $queryBuilder->executeQuery();
125 
126  while ($row = $result->fetchAssociative()) {
127  // @todo Considering only page slug is not complete, as it does not match redirects with file extension,
128  // for ex. if PageTypeSuffix routeEnhancer are used and redirects are created based on that.
129  $slug = ltrim(($row['slug'] ?? ''), '/');
130  $lang = (int)($row[$this->‪getPagesLanguageFieldName()] ?? 0);
131  $siteLanguage = $site->getLanguageById($lang);
132 
133  // empty slug root pages has been already handled with language bases above, thus skip them here.
134  if (empty($slug)) {
135  continue;
136  }
137 
138  $pageUrls[] = rtrim((string)$siteLanguage->getBase(), '/') . '/' . $slug;
139  }
140 
141  $subPageUrls = $this->‪getSlugsOfSubPages($site->getRootPageId(), $site);
142  $pageUrls = array_merge($pageUrls, $subPageUrls);
143  return array_unique($pageUrls);
144  }
145 
150  private function ‪getSlugsOfSubPages(int $pageId, Site $site): array
151  {
152  $pageUrls = [[]];
153 
154  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
155  ->getQueryBuilderForTable('pages')
156  ->select('uid', 'slug', $this->‪getPagesLanguageFieldName())
157  ->from('pages');
158 
159  $queryBuilder->where(
160  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, ‪Connection::PARAM_INT)),
161  );
162  $result = $queryBuilder->executeQuery();
163 
164  while ($row = $result->fetchAssociative()) {
165  // @todo Considering only page slug is not complete, as it does not matches redirects with file extension,
166  // for ex. if PageTypeSuffix routeEnhancer are used and redirects are created based on that.
167  $slug = ltrim($row['slug'] ?? '', '/');
168  $lang = (int)($row[$this->‪getPagesLanguageFieldName()] ?? 0);
169  $siteLanguage = $site->getLanguageById($lang);
170 
171  // empty slugs should to occur here, but to be sure we skip them here, as they were already handled.
172  if (empty($slug)) {
173  continue;
174  }
175 
176  $pageUrls[] = [rtrim((string)$siteLanguage->getBase(), '/') . '/' . $slug];
177 
178  // only traverse for pages of default language (as even translated pages contain pid of parent in default language)
179  if ($lang === 0) {
180  $pageUrls[] = $this->‪getSlugsOfSubPages((int)$row['uid'], $site);
181  }
182  }
183  return array_merge(...$pageUrls);
184  }
185 
186  private function ‪getPagesLanguageFieldName(): string
187  {
188  return ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'] ?? 'sys_language_uid';
189  }
190 
191  private function ‪getPagesLanguageParentFieldName(): string
192  {
193  return ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? 'l10n_parent';
194  }
195 }
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:50
‪TYPO3\CMS\Redirects\Service\IntegrityService\getAllPageUrlsForSite
‪getAllPageUrlsForSite(Site $site)
Definition: IntegrityService.php:101
‪TYPO3\CMS\Redirects\Service\IntegrityService\$redirectService
‪RedirectService $redirectService
Definition: IntegrityService.php:35
‪TYPO3\CMS\Core\Http\Uri\getPath
‪string getPath()
Definition: Uri.php:278
‪TYPO3\CMS\Redirects\Service\IntegrityService\getPagesLanguageFieldName
‪getPagesLanguageFieldName()
Definition: IntegrityService.php:184
‪TYPO3\CMS\Core\Http\Uri\getPort
‪int null getPort()
Definition: Uri.php:248
‪TYPO3\CMS\Redirects\Service\RedirectService
Definition: RedirectService.php:51
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Http\Uri
Definition: Uri.php:30
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Site\Entity\Site\getRootPageId
‪getRootPageId()
Definition: Site.php:189
‪TYPO3\CMS\Redirects\Service\IntegrityService\getMatchingRedirectByUri
‪getMatchingRedirectByUri(Uri $uri)
Definition: IntegrityService.php:79
‪TYPO3\CMS\Redirects\Service\IntegrityService\findConflictingRedirects
‪findConflictingRedirects(?string $siteIdentifier=null)
Definition: IntegrityService.php:55
‪TYPO3\CMS\Redirects\Service\IntegrityService\getPagesLanguageParentFieldName
‪getPagesLanguageParentFieldName()
Definition: IntegrityService.php:189
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:39
‪TYPO3\CMS\Redirects\Service\IntegrityService\__construct
‪__construct(RedirectService $redirectService=null, SiteFinder $siteFinder=null)
Definition: IntegrityService.php:41
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Redirects\Service
Definition: IntegrityService.php:18
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Site\Entity\SiteInterface\getLanguages
‪SiteLanguage[] getLanguages()
‪TYPO3\CMS\Redirects\Service\IntegrityService\$siteFinder
‪SiteFinder $siteFinder
Definition: IntegrityService.php:39
‪TYPO3\CMS\Core\Http\Uri\getHost
‪string getHost()
Definition: Uri.php:228
‪TYPO3\CMS\Redirects\Service\IntegrityService\getSlugsOfSubPages
‪getSlugsOfSubPages(int $pageId, Site $site)
Definition: IntegrityService.php:148
‪TYPO3\CMS\Redirects\Service\IntegrityService
Definition: IntegrityService.php:32
‪TYPO3\CMS\Redirects\Service\IntegrityService\getSites
‪Site[] getSites(?string $siteIdentifier)
Definition: IntegrityService.php:89
‪TYPO3\CMS\Webhooks\Message\$siteIdentifier
‪identifier readonly int readonly array readonly string readonly string $siteIdentifier
Definition: PageModificationMessage.php:38
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:48
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Core\Site\Entity\SiteInterface\getLanguageById
‪getLanguageById(int $languageId)