‪TYPO3CMS  ‪main
LinkAnalyzerResult.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 TYPO3\CMS\Backend\Utility\BackendUtility;
31 
38 {
39  protected array ‪$brokenLinks = [];
40  protected array ‪$newBrokenLinkCounts = [];
41  protected array ‪$oldBrokenLinkCounts = [];
42  protected bool ‪$differentToLastResult = false;
43 
49  protected array ‪$localizedPages = [];
50 
51  public function ‪__construct(
52  private readonly ‪LinkAnalyzer $linkAnalyzer,
53  private readonly ‪BrokenLinkRepository $brokenLinkRepository,
54  private readonly ‪ConnectionPool $connectionPool,
55  private readonly ‪PagesRepository $pagesRepository
56  ) {}
57 
61  public function ‪getResultForTask(
62  int $page,
63  int $depth,
64  array $pageRow,
65  array $modTSconfig,
66  array $searchFields = [],
67  array $linkTypes = [],
68  string ‪$languages = ''
69  ): self {
70  $rootLineHidden = $this->pagesRepository->doesRootLineContainHiddenPages($pageRow);
71  $checkHidden = $modTSconfig['checkhidden'] === 1;
72 
73  if ($rootLineHidden && !$checkHidden) {
74  return $this;
75  }
76 
77  $pageIds = $this->pagesRepository->getAllSubpagesForPage(
78  $page,
79  $depth,
80  '',
81  $checkHidden
82  );
83 
84  if ($pageRow['hidden'] === 0 || $checkHidden) {
85  $pageIds[] = $page;
86  }
87 
88  if (empty($pageIds)) {
89  return $this;
90  }
91 
92  $languageIds = ‪GeneralUtility::intExplode(',', ‪$languages, true);
93  $pageTranslations = $this->pagesRepository->getTranslationForPage(
94  $page,
95  '',
96  $checkHidden,
97  $languageIds
98  );
99 
100  $pageIds = array_merge($pageIds, $pageTranslations);
101 
102  $this->linkAnalyzer->init($searchFields, $pageIds, $modTSconfig);
103  $this->oldBrokenLinkCounts = $this->linkAnalyzer->getLinkCounts();
104 
105  $this->linkAnalyzer->getLinkStatistics($linkTypes, $checkHidden);
106  $this->newBrokenLinkCounts = $this->linkAnalyzer->getLinkCounts();
107 
108  $this->brokenLinks = $this->brokenLinkRepository->getAllBrokenLinksForPages(
109  $pageIds,
110  $linkTypes,
111  $searchFields,
112  $languageIds
113  );
114 
115  $this
116  ->processLinkCounts($linkTypes)
117  ->processBrokenLinks();
118 
119  return $this;
120  }
121 
122  public function ‪setBrokenLinks(array ‪$brokenLinks): void
123  {
124  $this->brokenLinks = ‪$brokenLinks;
125  }
126 
127  public function ‪getBrokenLinks(): array
128  {
129  return ‪$this->brokenLinks;
130  }
131 
133  {
134  $this->newBrokenLinkCounts = ‪$newBrokenLinkCounts;
135  }
136 
137  public function ‪getNewBrokenLinkCounts(): array
138  {
140  }
141 
143  {
144  $this->oldBrokenLinkCounts = ‪$oldBrokenLinkCounts;
145  }
146 
147  public function ‪getOldBrokenLinkCounts(): array
148  {
150  }
151 
152  public function ‪getTotalBrokenLinksCount(): int
153  {
154  return $this->newBrokenLinkCounts['total'] ?? 0;
155  }
156 
157  public function ‪isDifferentToLastResult(): bool
158  {
160  }
161 
167  protected function ‪processLinkCounts(array $linkTypes): self
168  {
169  foreach ($linkTypes as $linkType) {
170  if (!isset($this->newBrokenLinkCounts[$linkType])) {
171  $this->newBrokenLinkCounts[$linkType] = 0;
172  }
173  if (!isset($this->oldBrokenLinkCounts[$linkType])) {
174  $this->oldBrokenLinkCounts[$linkType] = 0;
175  }
176  if ($this->newBrokenLinkCounts[$linkType] !== $this->oldBrokenLinkCounts[$linkType]) {
177  $this->differentToLastResult = true;
178  }
179  }
180 
181  return $this;
182  }
183 
189  protected function ‪processBrokenLinks(): self
190  {
191  foreach ($this->brokenLinks as &$brokenLink) {
192  $fullRecord = BackendUtility::getRecord($brokenLink['table_name'], $brokenLink['record_uid']);
193 
194  if ($fullRecord !== null) {
195  $brokenLink['full_record'] = $fullRecord;
196  $brokenLink['record_title'] = BackendUtility::getRecordTitle($brokenLink['table_name'], $fullRecord);
197  }
198 
199  $brokenLink['real_pid'] = ((int)($brokenLink['language'] ?? 0) > 0 && (string)($brokenLink['table_name'] ?? '') !== 'pages')
200  ? $this->‪getLocalizedPageId((int)$brokenLink['record_pid'], (int)$brokenLink['language'])
201  : $brokenLink['record_pid'];
202  $pageRecord = BackendUtility::getRecord('pages', $brokenLink['real_pid']);
203 
204  try {
205  $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId((int)$brokenLink['real_pid']);
206  $languageCode = $site->getLanguageById((int)$brokenLink['language'])->getLocale()->getLanguageCode();
207  } catch (‪SiteNotFoundException | \InvalidArgumentException $e) {
208  $languageCode = 'default';
209  }
210  if ($pageRecord !== null) {
211  $brokenLink['page_record'] = $pageRecord;
212  }
213 
214  $brokenLink['record_type'] = $this->‪getLanguageService()->sL(‪$GLOBALS['TCA'][$brokenLink['table_name']]['ctrl']['title'] ?? '');
215  $brokenLink['target'] = (((string)($brokenLink['link_type'] ?? '') === 'db') ? 'id:' : '') . $brokenLink['url'];
216  $brokenLink['language_code'] = (string)$languageCode;
217  }
218 
219  return $this;
220  }
221 
225  protected function ‪getLocalizedPageId(int $parentId, int $languageId): int
226  {
227  ‪$identifier = $parentId . '-' . $languageId;
228 
229  if ((bool)($this->localizedPages[‪$identifier] ?? false)) {
230  return $this->localizedPages[‪$identifier];
231  }
232 
233  $queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
234  $queryBuilder
235  ->getRestrictions()
236  ->removeAll()
237  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
238 
239  $localizedPageId = (int)$queryBuilder
240  ->select('uid')
241  ->from('pages')
242  ->where(
243  $queryBuilder->expr()->eq(
244  ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
245  $queryBuilder->createNamedParameter($parentId, ‪Connection::PARAM_INT)
246  ),
247  $queryBuilder->expr()->eq(
248  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
249  $queryBuilder->createNamedParameter($languageId, ‪Connection::PARAM_INT)
250  )
251  )
252  ->setMaxResults(1)
253  ->executeQuery()
254  ->fetchOne();
255 
256  if ($localizedPageId) {
257  $this->localizedPages[‪$identifier] = $localizedPageId;
258  return $localizedPageId;
259  }
260 
261  return $parentId;
262  }
263 
265  {
266  return ‪$GLOBALS['LANG'];
267  }
268 }
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪$languages
‪$languages
Definition: updateIsoDatabase.php:104
‪TYPO3\CMS\Linkvalidator\Repository\PagesRepository
Definition: PagesRepository.php:33
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:25
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Linkvalidator\Result
Definition: LinkAnalyzerResult.php:18
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37