Skip to content

Commit

Permalink
!!![FEATURE] Better handling of link target results
Browse files Browse the repository at this point in the history
This is a breaking change! It is advised to look at the
Changelog in the documentation for more information.

The checkLinks functions in all LinktypeInterface classes now
results a LinkTargetResponse object. In this, a status is
stored for the link checking, which makes it easier to handling
other link target status apart from broken.

This effectively makes the following possible:

- show all links in the broken link list, not just the broken links
- better handling of link targets, which can't be checked. This includes
  for example URLs with 401 or 403 HTTP status codes, where it is not
  possible to check the URLs. Previously, these URLs were considered
  broken while in fact we do not know if they are broken or not and
  we have no was to check them. This also includes URLs protected
  by cloudflare. They are now stored not as broken but as "can't be
  checked"
- it is possible to filter in the link list by this new status

Resolves: #296
Resolves: #289
Related: #13
  • Loading branch information
sypets committed Mar 3, 2024
1 parent c22a519 commit 74bf270
Show file tree
Hide file tree
Showing 34 changed files with 876 additions and 734 deletions.
2 changes: 2 additions & 0 deletions Build/phpstan/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ parameters:

excludePaths:
- ../../Classes/Hooks/DataHandlerHook.php

treatPhpDocTypesAsCertain: false
31 changes: 0 additions & 31 deletions Classes/CheckLinks/LinkTargetCache/AbstractLinkTargetCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,6 @@
declare(strict_types=1);
namespace Sypets\Brofix\CheckLinks\LinkTargetCache;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use Sypets\Brofix\Linktype\ErrorParams;

abstract class AbstractLinkTargetCache implements LinkTargetCacheInterface
{
/**
Expand All @@ -32,20 +17,4 @@ public function setExpire(int $expire): void
{
$this->expire = $expire;
}

/**
* Generate UrlResponse array from arguments.
*
* @param bool $isValid
* @param ErrorParams $errorParams
* @return array{'valid': bool, 'errorParams': array<mixed>}
*/
public function generateUrlResponse(bool $isValid, ErrorParams $errorParams): array
{
$result = [
'valid' => $isValid,
'errorParams' => $errorParams->toArray()
];
return $result;
}
}
19 changes: 5 additions & 14 deletions Classes/CheckLinks/LinkTargetCache/LinkTargetCacheInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,12 @@
* The TYPO3 project - inspiring people to share!
*/

use Sypets\Brofix\Linktype\ErrorParams;
use Sypets\Brofix\CheckLinks\LinkTargetResponse\LinkTargetResponse;

interface LinkTargetCacheInterface
{
public function setExpire(int $expire): void;

/**
* Generate UrlResponse array from arguments.
*
* @param bool $isValid
* @param ErrorParams $errorParams
* @return array{'valid': bool, 'errorParams': array<mixed>}
*/
public function generateUrlResponse(bool $isValid, ErrorParams $errorParams): array;

/**
* Check if url exists in link cache (and is not expired)
*/
Expand All @@ -42,16 +33,16 @@ public function hasEntryForUrl(string $linkTarget, string $linkType, bool $useEx
* @param string $linkTarget
* @param string $linkType
* @param int $expire (optional, default is 0, in that case uses $this->expire)
* @return mixed[]
* @return LinkTargetResponse|null
*/
public function getUrlResponseForUrl(string $linkTarget, string $linkType, int $expire = 0): array;
public function getUrlResponseForUrl(string $linkTarget, string $linkType, int $expire = 0): ?LinkTargetResponse;

/**
* @param string $linkTarget
* @param string $linkType
* @param mixed[] $urlResponse
* @param LinkTargetResponse $linkTargetResponse
*/
public function setResult(string $linkTarget, string $linkType, array $urlResponse): void;
public function setResult(string $linkTarget, string $linkType, LinkTargetResponse $linkTargetResponse): void;

public function remove(string $linkTarget, string $linkType): void;
}
56 changes: 17 additions & 39 deletions Classes/CheckLinks/LinkTargetCache/LinkTargetPersistentCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,15 @@
declare(strict_types=1);
namespace Sypets\Brofix\CheckLinks\LinkTargetCache;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use Sypets\Brofix\CheckLinks\LinkTargetResponse\LinkTargetResponse;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* This class implements a persistent link target cache using
* a database table.
* @internal
*/
class LinkTargetPersistentCache extends AbstractLinkTargetCache
{
Expand Down Expand Up @@ -70,10 +59,9 @@ public function hasEntryForUrl(string $linkTarget, string $linkType, bool $useEx
* @param string $linkTarget
* @param string $linkType
* @param int $expire (optional, default is 0, in that case uses $this->expire)
* @return mixed[] returns URL response as array or
* empty array if no entry
* @return LinkTargetResponse|null
*/
public function getUrlResponseForUrl(string $linkTarget, string $linkType, int $expire = 0): array
public function getUrlResponseForUrl(string $linkTarget, string $linkType, int $expire = 0): ?LinkTargetResponse
{
$expire = $expire ?: $this->expire;
$queryBuilder = $this->generateQueryBuilder();
Expand All @@ -90,36 +78,32 @@ public function getUrlResponseForUrl(string $linkTarget, string $linkType, int $
->executeQuery()
->fetchAssociative();
if (!$row) {
return [];
return null;
}
$urlResponse = json_decode($row['url_response'], true);
$urlResponse['lastChecked'] = (int)$row['last_check'];
return $urlResponse;
return LinkTargetResponse::createInstanceFromJson($row['url_response']);
}

/**
* Insert result / update existing result
* @param string $linkTarget
* @param string $linkType
* @param mixed[] $urlResponse
* @param LinkTargetResponse $linkTargetResponse
*/
public function setResult(string $linkTarget, string $linkType, array $urlResponse): void
public function setResult(string $linkTarget, string $linkType, LinkTargetResponse $linkTargetResponse): void
{
$checkStatus = $urlResponse['valid'] ? self::CHECK_STATUS_OK : self::CHECK_STATUS_ERROR;
if ($this->hasEntryForUrl($linkTarget, $linkType, false)) {
$this->update($linkTarget, $linkType, $urlResponse, $checkStatus);
$this->update($linkTarget, $linkType, $linkTargetResponse);
} else {
$this->insert($linkTarget, $linkType, $urlResponse, $checkStatus);
$this->insert($linkTarget, $linkType, $linkTargetResponse);
}
}

/**
* @param string $linkTarget
* @param string $linkType
* @param mixed[] $urlResponse
* @param int $checkStatus
* @param LinkTargetResponse $linkTargetResponse
*/
protected function insert(string $linkTarget, string $linkType, array $urlResponse, int $checkStatus): void
protected function insert(string $linkTarget, string $linkType, LinkTargetResponse $linkTargetResponse): void
{
$queryBuilder = $this->generateQueryBuilder();
$queryBuilder
Expand All @@ -128,21 +112,15 @@ protected function insert(string $linkTarget, string $linkType, array $urlRespon
[
'url' => $linkTarget,
'link_type' => $linkType,
'url_response' => \json_encode($urlResponse),
'check_status' => $checkStatus,
'url_response' => $linkTargetResponse->toJson(),
'check_status' => $linkTargetResponse->getStatus(),
'last_check' => \time()
]
)
->executeStatement();
}

/**
* @param string $linkTarget
* @param string $linkType
* @param mixed[] $urlResponse
* @param int $checkStatus
*/
protected function update(string $linkTarget, string $linkType, array $urlResponse, int $checkStatus): void
protected function update(string $linkTarget, string $linkType, LinkTargetResponse $linkTargetResponse): void
{
$queryBuilder = $this->generateQueryBuilder();
$queryBuilder
Expand All @@ -151,8 +129,8 @@ protected function update(string $linkTarget, string $linkType, array $urlRespon
$queryBuilder->expr()->eq('url', $queryBuilder->createNamedParameter($linkTarget)),
$queryBuilder->expr()->eq('link_type', $queryBuilder->createNamedParameter($linkType))
)
->set('url_response', \json_encode($urlResponse))
->set('check_status', (string)$checkStatus)
->set('url_response', $linkTargetResponse->toJson())
->set('check_status', (string)$linkTargetResponse->getStatus())
->set('last_check', (string)\time())
->executeStatement();
}
Expand Down
Loading

0 comments on commit 74bf270

Please sign in to comment.