103 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'EXTCONF'][
'linkvalidator'][
'checkLinks'] ?? [] as $key => $className) {
104 $this->hookObjectsArr[$key] = GeneralUtility::makeInstance($className);
117 $this->searchFields = $searchField;
118 $this->pids = GeneralUtility::intExplode(
',', $pidList,
true);
131 if (empty($checkOptions) || empty($this->pids)) {
135 $checkKeys = array_keys($checkOptions);
137 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
138 ->getQueryBuilderForTable(
'tx_linkvalidator_link');
140 $queryBuilder->delete(
'tx_linkvalidator_link')
142 $queryBuilder->expr()->orX(
143 $queryBuilder->expr()->andX(
144 $queryBuilder->expr()->in(
146 $queryBuilder->createNamedParameter($this->pids, Connection::PARAM_INT_ARRAY)
148 $queryBuilder->expr()->eq(
'table_name', $queryBuilder->createNamedParameter(
'pages'))
150 $queryBuilder->expr()->andX(
151 $queryBuilder->expr()->in(
153 $queryBuilder->createNamedParameter($this->pids, Connection::PARAM_INT_ARRAY)
155 $queryBuilder->expr()->neq(
157 $queryBuilder->createNamedParameter(
'pages')
161 $queryBuilder->expr()->in(
163 $queryBuilder->createNamedParameter($checkKeys, Connection::PARAM_STR_ARRAY)
169 foreach ($this->searchFields as $table =>
$fields) {
172 if (!is_array(
$GLOBALS[
'TCA'][$table])) {
175 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
176 ->getQueryBuilderForTable($table);
178 if ($considerHidden) {
179 $queryBuilder->getRestrictions()
181 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
185 $selectFields = array_merge([
'uid',
'pid',
$GLOBALS[
'TCA'][$table][
'ctrl'][
'label']],
$fields);
187 $result = $queryBuilder->select(...$selectFields)
190 $queryBuilder->expr()->in(
191 ($table ===
'pages' ?
'uid' :
'pid'),
192 $queryBuilder->createNamedParameter($this->pids, Connection::PARAM_INT_ARRAY)
198 while ($row = $result->fetch()) {
203 foreach ($this->hookObjectsArr as $key => $hookObj) {
204 if (!is_array($results[$key]) || (!empty($checkOptions) && !$checkOptions[$key])) {
209 foreach ($results[$key] as $entryKey => $entryValue) {
210 $table = $entryValue[
'table'];
213 $record[
'record_pid'] = $entryValue[
'row'][
'pid'];
214 $record[
'record_uid'] = $entryValue[
'uid'];
215 $record[
'table_name'] = $table;
216 $record[
'link_title'] = $entryValue[
'link_title'];
217 $record[
'field'] = $entryValue[
'field'];
218 $record[
'last_check'] = time();
219 $this->recordReference = $entryValue[
'substr'][
'recordRef'];
220 $this->pageWithAnchor = $entryValue[
'pageAndAnchor'];
221 if (!empty($this->pageWithAnchor)) {
225 $url = $entryValue[
'substr'][
'tokenValue'];
227 $this->linkCounts[$table]++;
228 $checkUrl = $hookObj->checkLink($url, $entryValue, $this);
233 $response[
'valid'] =
false;
234 $response[
'errorParams'] = $hookObj->getErrorParams();
235 $this->brokenLinkCounts[$table]++;
236 $record[
'link_type'] = $key;
237 $record[
'url'] = $url;
238 $record[
'url_response'] = serialize($response);
239 GeneralUtility::makeInstance(ConnectionPool::class)
240 ->getConnectionForTable(
'tx_linkvalidator_link')
241 ->insert(
'tx_linkvalidator_link', $record);
242 } elseif (GeneralUtility::_GP(
'showalllinks')) {
244 $response[
'valid'] =
true;
245 $this->brokenLinkCounts[$table]++;
246 $record[
'url'] = $url;
247 $record[
'link_type'] = $key;
248 $record[
'url_response'] = serialize($response);
249 GeneralUtility::makeInstance(ConnectionPool::class)
250 ->getConnectionForTable(
'tx_linkvalidator_link')
251 ->insert(
'tx_linkvalidator_link', $record);
272 $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
273 $idRecord = $record[
'uid'];
276 $haystack .= $record[$field] .
' --- ';
277 $conf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
278 $valueField = $record[$field];
281 if (!$conf[
'softref'] || (
string)$valueField ===
'') {
287 if ($softRefs ===
false) {
292 foreach ($softRefs as $spKey => $spParams) {
297 if (!is_object($softRefObj)) {
300 $softRefParams = $spParams;
301 if (!is_array($softRefParams)) {
303 $softRefParams = [
'subst' =>
true];
307 $resultArray = $softRefObj->findRef($table, $field, $idRecord, $valueField, $spKey, $softRefParams);
308 if (empty($resultArray[
'elements'])) {
312 if ($spKey ===
'typolink_tag') {
313 $this->
analyzeTypoLinks($resultArray, $results, $htmlParser, $record, $field, $table);
315 $this->
analyzeLinks($resultArray, $results, $record, $field, $table);
343 protected function analyzeLinks(array $resultArray, array &$results, array $record, $field, $table)
345 foreach ($resultArray[
'elements'] as $element) {
346 $r = $element[
'subst'];
348 $idRecord = $record[
'uid'];
354 foreach ($this->hookObjectsArr as $keyArr => $hookObj) {
355 $type = $hookObj->fetchType($r, $type, $keyArr);
362 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $r[
'tokenID']][
'substr'] = $r;
363 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $r[
'tokenID']][
'row'] = $record;
364 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $r[
'tokenID']][
'table'] = $table;
365 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $r[
'tokenID']][
'field'] = $field;
366 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $r[
'tokenID']][
'uid'] = $idRecord;
380 protected function analyzeTypoLinks(array $resultArray, array &$results, $htmlParser, array $record, $field, $table)
383 $linkTags = $htmlParser->splitIntoBlock(
'a,link', $resultArray[
'content']);
384 $idRecord = $record[
'uid'];
387 $countLinkTags = count($linkTags);
388 for ($i = 1; $i < $countLinkTags; $i += 2) {
389 $referencedRecordType =
'';
390 foreach ($resultArray[
'elements'] as $element) {
392 $r = $element[
'subst'];
393 if (empty($r[
'tokenID']) || substr_count($linkTags[$i], $r[
'tokenID']) === 0) {
398 if (strpos($r[
'recordRef'],
'pages') !==
false) {
401 $referencedRecordType = $r[
'tokenValue'];
403 } elseif (strpos($r[
'recordRef'],
'tt_content') !==
false && (isset($wasPage) && $wasPage ===
true)) {
404 $referencedRecordType = $referencedRecordType .
'#c' . $r[
'tokenValue'];
409 $title = strip_tags($linkTags[$i]);
412 foreach ($this->hookObjectsArr as $keyArr => $hookObj) {
413 $type = $hookObj->fetchType($currentR, $type, $keyArr);
417 $currentR[
'type'] = $type;
420 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'substr'] = $currentR;
421 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'row'] = $record;
422 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'table'] = $table;
423 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'field'] = $field;
424 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'uid'] = $idRecord;
425 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'link_title'] = $title;
426 $results[$type][$table .
':' . $field .
':' . $idRecord .
':' . $currentR[
'tokenID']][
'pageAndAnchor'] = $referencedRecordType;
440 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
441 ->getQueryBuilderForTable(
'tx_linkvalidator_link');
442 $queryBuilder->getRestrictions()->removeAll();
444 $result = $queryBuilder->select(
'link_type')
445 ->addSelectLiteral($queryBuilder->expr()->count(
'uid',
'nbBrokenLinks'))
446 ->from(
'tx_linkvalidator_link')
448 $queryBuilder->expr()->orX(
449 $queryBuilder->expr()->andX(
450 $queryBuilder->expr()->in(
452 $queryBuilder->createNamedParameter($this->pids, Connection::PARAM_INT_ARRAY)
454 $queryBuilder->expr()->eq(
'table_name', $queryBuilder->createNamedParameter(
'pages'))
456 $queryBuilder->expr()->andX(
457 $queryBuilder->expr()->in(
459 $queryBuilder->createNamedParameter($this->pids, Connection::PARAM_INT_ARRAY)
461 $queryBuilder->expr()->neq(
'table_name', $queryBuilder->createNamedParameter(
'pages'))
465 ->groupBy(
'link_type')
468 while ($row = $result->fetch()) {
469 $markerArray[$row[
'link_type']] = $row[
'nbBrokenLinks'];
470 $markerArray[
'brokenlinkCount'] += $row[
'nbBrokenLinks'];
490 public function extGetTreeList($id, $depth, $begin = 0, $permsClause, $considerHidden =
false)
492 $depth = (int)$depth;
493 $begin = (int)$begin;
500 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
501 $queryBuilder->getRestrictions()
503 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
505 $result = $queryBuilder
506 ->select(
'uid',
'title',
'hidden',
'extendToSubpages')
509 $queryBuilder->expr()->eq(
511 $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
517 while ($row = $result->fetch()) {
518 if ($begin <= 0 && ($row[
'hidden'] == 0 || $considerHidden)) {
519 $theList .= $row[
'uid'] .
',';
521 if ($depth > 1 && (!($row[
'hidden'] == 1 && $row[
'extendToSubpages'] == 1) || $considerHidden)) {
542 if ($pageInfo[
'pid'] === 0) {
546 if ($pageInfo[
'extendToSubpages'] == 1 && $pageInfo[
'hidden'] == 1) {
550 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
551 $queryBuilder->getRestrictions()->removeAll();
554 ->select(
'uid',
'title',
'hidden',
'extendToSubpages')
557 $queryBuilder->expr()->eq(
559 $queryBuilder->createNamedParameter($pageInfo[
'pid'], \PDO::PARAM_INT)
565 if ($row !==
false) {
584 'beforeAnalyzeRecord',
585 [$results, $record, $table,
$fields, $this]
602 return GeneralUtility::makeInstance(\
TYPO3\CMS\
Extbase\Object\ObjectManager::class);