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