Skip to content

Commit

Permalink
[WIP] Filter by error type
Browse files Browse the repository at this point in the history
todo
- use a select list instead of an edit field
- show the error code only for admin users

Resolves: #163
  • Loading branch information
sypets committed Dec 4, 2022
1 parent 818e1a2 commit 4435b72
Show file tree
Hide file tree
Showing 17 changed files with 429 additions and 16 deletions.
16 changes: 16 additions & 0 deletions Classes/CheckLinks/LinkTargetCache/LinkTargetPersistentCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ public function setResult(string $linkTarget, string $linkType, array $urlRespon
*/
protected function insert(string $linkTarget, string $linkType, array $urlResponse, int $checkStatus): void
{
$errorCode = '';
$errorType = $urlResponse['errorParams']['errorType'] ?? '';
$errno = (int)($urlResponse['errorParams']['errno'] ?? 0);
if ($errorType) {
$errorCode = $errorType . '_' . $errno;
}

$queryBuilder = $this->generateQueryBuilder();
$queryBuilder
->insert(static::TABLE)
Expand All @@ -129,6 +136,7 @@ protected function insert(string $linkTarget, string $linkType, array $urlRespon
'url' => $linkTarget,
'link_type' => $linkType,
'url_response' => \json_encode($urlResponse),
'error_code' => $errorCode,
'check_status' => $checkStatus,
'last_check' => \time()
]
Expand All @@ -144,6 +152,13 @@ protected function insert(string $linkTarget, string $linkType, array $urlRespon
*/
protected function update(string $linkTarget, string $linkType, array $urlResponse, int $checkStatus): void
{
$errorCode = '';
$errorType = $urlResponse['errorParams']['errorType'] ?? '';
$errno = (int)($urlResponse['errorParams']['errno'] ?? 0);
if ($errorType) {
$errorCode = $errorType . '_' . $errno;
}

$queryBuilder = $this->generateQueryBuilder();
$queryBuilder
->update(static::TABLE)
Expand All @@ -152,6 +167,7 @@ protected function update(string $linkTarget, string $linkType, array $urlRespon
$queryBuilder->expr()->eq('link_type', $queryBuilder->createNamedParameter($linkType))
)
->set('url_response', \json_encode($urlResponse))
->set('error_code', $errorCode)
->set('check_status', (string)$checkStatus)
->set('last_check', (string)\time())
->executeStatement();
Expand Down
18 changes: 15 additions & 3 deletions Classes/Controller/BrokenLinkListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,18 @@ protected function getSettingsFromQueryParameters(): void
if ($linkType !== null) {
$this->filter->setLinktypeFilter($linkType ?: 'all');
}
$errorCodeFilter = GeneralUtility::_GP('errorcode_searchFilter');
if ($errorCodeFilter !== null) {
$this->filter->setErrorcodeFilter($errorCodeFilter);
}

$this->userSettings = UserSettings::initializeFromSettingsAndGetParameters($this->pObj->MOD_SETTINGS);

// to prevent deleting session, when user sort the records
if (!is_null(GeneralUtility::_GP('url_searchFilter')) || !is_null(GeneralUtility::_GP('title_searchFilter')) || !is_null(GeneralUtility::_GP('uid_searchFilter'))) {
if (!is_null(GeneralUtility::_GP('url_searchFilter'))
|| !is_null(GeneralUtility::_GP('title_searchFilter'))
|| !is_null(GeneralUtility::_GP('uid_searchFilter'))
|| !is_null(GeneralUtility::_GP('errorcode_searchFilter'))) {
$this->backendSession->store(BackendSession::FILTER_KEY_LINKLIST, $this->filter);
}

Expand Down Expand Up @@ -595,7 +602,9 @@ protected function initializeViewForBrokenLinks(): void
$this->view->assign('linktype_filter', $filter->getLinktypeFilter());
$this->view->assign('url_filter', $filter->getUrlFilter());
$this->view->assign('url_match_searchFilter', $filter->getUrlFilterMatch());
$this->view->assign('errorcode_filter', $filter->getErrorcodeFilter());
$this->view->assign('view_mode', $this->userSettings->getViewMode());

if ($this->id === 0) {
$this->createFlashMessagesForRootPage();
} elseif (empty($items)) {
Expand Down Expand Up @@ -887,11 +896,13 @@ protected function renderTableRow($table, array $row): array
$variables['pagetitle'] = $path[0] ?? '';

// error message
$response = $response = json_decode($row['url_response'], true);
$response = \json_decode($row['url_response'], true);
$errorParams = new ErrorParams($response['errorParams']);
$errorCode = '';
if ($response['valid']) {
$linkMessage = '<span class="valid">' . htmlspecialchars($languageService->getLL('list.msg.ok')) . '</span>';
} else {
$errorCode = $hookObj->getErrorShortcut($errorParams);
$linkMessage = sprintf(
'<span class="error" title="%s">%s</span>',
nl2br(
Expand All @@ -905,7 +916,7 @@ protected function renderTableRow($table, array $row): array
nl2br(
// Encode for output
htmlspecialchars(
$hookObj->getErrorMessage($errorParams),
$hookObj->getErrorMessage($errorParams) . ' [' . $errorCode . ']',
ENT_QUOTES,
'UTF-8',
false
Expand All @@ -914,6 +925,7 @@ protected function renderTableRow($table, array $row): array
);
}
$variables['linkmessage'] = $linkMessage;
$variables['error_code'] = $errorCode;

// link / URL
$variables['linktarget'] = $hookObj->getBrokenUrl($row);
Expand Down
41 changes: 39 additions & 2 deletions Classes/Controller/Filter/BrokenLinkListFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,29 @@

use Sypets\Brofix\Util\Arrayable;

/**
* Stores current filter settings for filtering in broken link list.
*
* If a new item is added, it must be added to constructor,
* getInstanceFromArray and toArray()
*/
class BrokenLinkListFilter implements Arrayable
{
/** @var string */
protected const KEY_UID = 'uid';

/** @var string */
protected const KEY_URL = 'url';

/** @var string */
protected const KEY_LINKTYPE = 'linktype';

/** @var string */
protected const KEY_URL_MATCH = 'urlMatch';

/** @var string */
protected const KEY_ERRORCODE_MATCH = 'errorCode';

/** @var string */
protected const LINK_TYPE_FILTER_DEFAULT = 'all';

Expand All @@ -43,6 +55,11 @@ class BrokenLinkListFilter implements Arrayable
/** @var string */
protected $urlFilterMatch = self::URL_MATCH_DEFAULT;

/**
* @var string
*/
protected $errorcodeFilter = '';

/**
* @var string
* @deprecated
Expand All @@ -53,12 +70,14 @@ public function __construct(
string $uid = '',
string $linkType = self::LINK_TYPE_DEFAULT,
string $url = '',
string $urlMatch = self::URL_MATCH_DEFAULT
string $urlMatch = self::URL_MATCH_DEFAULT,
string $errorCode = ''
) {
$this->uid_filtre = $uid;
$this->linktype_filter = $linkType;
$this->url_filtre = $url;
$this->urlFilterMatch = $urlMatch;
$this->errorcodeFilter = $errorCode;
}

public static function getInstanceFromArray(array $values): BrokenLinkListFilter
Expand All @@ -67,7 +86,8 @@ public static function getInstanceFromArray(array $values): BrokenLinkListFilter
$values[self::KEY_UID] ?? '',
$values[self::KEY_LINKTYPE] ?? self::LINK_TYPE_DEFAULT,
$values[self::KEY_URL] ?? '',
$values[self::KEY_URL_MATCH] ?? self::URL_MATCH_DEFAULT
$values[self::KEY_URL_MATCH] ?? self::URL_MATCH_DEFAULT,
$values[self::KEY_ERRORCODE_MATCH] ?? ''
);
}

Expand All @@ -78,6 +98,7 @@ public function toArray(): array
self::KEY_LINKTYPE => $this->getLinktypeFilter(),
self::KEY_URL => $this->getUrlFilter(),
self::KEY_URL_MATCH => $this->getUrlFilterMatch(),
self::KEY_ERRORCODE_MATCH => $this->getErrorcodeFilter(),
];
}

Expand Down Expand Up @@ -146,6 +167,22 @@ public function setUrlFilterMatch(string $urlFilterMatch): void
$this->urlFilterMatch = $urlFilterMatch;
}

/**
* @return string
*/
public function getErrorcodeFilter(): string
{
return $this->errorcodeFilter;
}

/**
* @param string $errorcodeFilter
*/
public function setErrorcodeFilter(string $errorcodeFilter): void
{
$this->errorcodeFilter = $errorcodeFilter;
}

/** @deprecated */
public function getTitleFilter(): string
{
Expand Down
11 changes: 11 additions & 0 deletions Classes/LinkAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,17 @@ protected function checkLinks(array $links, array $linkTypes, int $mode = 0): vo
'valid' => false,
'errorParams' => $hookObj->getErrorParams()->toArray()
];
// @todo create class for url_response
$record['url_response'] = json_encode($response) ?: '';

$errorCode = '';
$errorType = $response['errorParams']['errorType'] ?? '';
$errno = (int)($response['errorParams']['errno'] ?? 0);
if ($errorType) {
$errorCode = $errorType . '_' . $errno;
}

$record['error_code'] = $errorCode;
// last_check reflects time of last check (may be older if URL was in cache)
$record['last_check_url'] = $hookObj->getLastChecked() ?: \time();
$record['last_check'] = \time();
Expand All @@ -408,6 +418,7 @@ protected function checkLinks(array $links, array $linkTypes, int $mode = 0): vo
} elseif (GeneralUtility::_GP('showalllinks')) {
$response = ['valid' => true];
$record['url_response'] = json_encode($response) ?: '';
$record['error_code'] = '';
$record['last_check_url'] = $hookObj->getLastChecked() ?: \time();
$record['last_check'] = \time();
$this->brokenLinkRepository->insertOrUpdateBrokenLink($record);
Expand Down
5 changes: 5 additions & 0 deletions Classes/Linktype/AbstractLinktype.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public function getErrorParams(): ErrorParams
return $this->errorParams;
}

public function getErrorShortcut(ErrorParams $errorParams = null): string
{
return $errorParams->getErrorType() . '_' . $errorParams->getErrno();
}

/**
* Base type fetching method, based on the type that softRefParserObj returns
*
Expand Down
39 changes: 33 additions & 6 deletions Classes/Linktype/ExternalLinktype.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,23 @@ class ExternalLinktype extends AbstractLinktype implements LoggerAwareInterface
{
use LoggerAwareTrait;

// HTTP status code was delivered (and can be found in $errorParams->errno)
public const ERROR_TYPE_HTTP_STATUS_CODE = 'httpStatusCode';
// An error occurred in lowlevel handler and a cURL error code can be found in $errorParams->errno
public const ERROR_TYPE_LOWLEVEL_LIBCURL_ERRNO = 'libcurlErrno';
/**
* @var string
* @todo to be deprecated, use self::ERROR_TYPE_HTTP_STATUS_CODE
*/
public const ERROR_TYPE_HTTP_STATUS_CODE_DEPRECATED = 'httpStatusCode';

/** @var string */
public const ERROR_TYPE_HTTP_STATUS_CODE = 'http';

/**
* @var string
* @todo to be deprecated, use self::ERROR_TYPE_CURL
*/
public const ERROR_TYPE_LOWLEVEL_LIBCURL_ERRNO_DEPRECATED = 'libcurlErrno';

/** @var string */
public const ERROR_TYPE_CURL = 'curl';
public const ERROR_TYPE_TOO_MANY_REDIRECTS = 'tooManyRedirects';
public const ERROR_TYPE_UNABLE_TO_PARSE = 'unableToParseUri';
public const ERROR_TYPE_UNKNOWN = 'unknown';
Expand Down Expand Up @@ -285,7 +298,7 @@ protected function requestUrl(string $url, string $method, array $options): bool
'cURL error',
strlen('cURL error')
) === 0)) {
$this->errorParams->setErrorType(self::ERROR_TYPE_LOWLEVEL_LIBCURL_ERRNO);
$this->errorParams->setErrorType(self::ERROR_TYPE_CURL);
$this->errorParams->setErrno((int)($handlerContext['errno']));
// use shorter error message
if (isset($handlerContext['error'])) {
Expand Down Expand Up @@ -320,6 +333,18 @@ public function getLastChecked(): int
return $this->lastChecked;
}

public function getErrorShortcut(ErrorParams $errorParams = null): string
{
$type = $errorParams->getErrorType();
if ($type === self::ERROR_TYPE_HTTP_STATUS_CODE_DEPRECATED) {
$type = self::ERROR_TYPE_HTTP_STATUS_CODE;
} elseif ($type === self::ERROR_TYPE_CURL) {
$type = self::ERROR_TYPE_CURL;
}

return $type . '_' . $errorParams->getErrno();
}

/**
* Generate the localized error message from the error params saved from the parsing
*
Expand All @@ -339,6 +364,7 @@ public function getErrorMessage(ErrorParams $errorParams = null): string

switch ($errorType) {
case self::ERROR_TYPE_HTTP_STATUS_CODE:
case self::ERROR_TYPE_HTTP_STATUS_CODE_DEPRECATED:
$message = $lang->getLL('list.report.error.httpstatus.' . $errno);
if (!$message) {
if ($errno !== 0) {
Expand All @@ -350,7 +376,8 @@ public function getErrorMessage(ErrorParams $errorParams = null): string
}
break;

case self::ERROR_TYPE_LOWLEVEL_LIBCURL_ERRNO:
case self::ERROR_TYPE_LOWLEVEL_LIBCURL_ERRNO_DEPRECATED:
case self::ERROR_TYPE_CURL:
$message = '';
if ($errno > 0) {
// get localized error message
Expand Down
25 changes: 22 additions & 3 deletions Classes/Linktype/FileLinktype.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@
*/
class FileLinktype extends AbstractLinktype
{
/**
* @var string
*/
protected const ERROR_TYPE_FILE = 'file';

/**
* @var int
*/
protected const ERROR_ERRNO_FILE_MISSING = 1;


public function __construct()
{
$this->initializeErrorParams();
Expand Down Expand Up @@ -69,13 +80,21 @@ public function checkLink(string $url, array $softRefEntry, int $flags = 0): boo
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
try {
$file = $resourceFactory->retrieveFileOrFolderObject($url);
$isMissing = (bool)(($file !== null) ? $file->isMissing() : true);
} catch (FileDoesNotExistException $e) {
return false;
$isMissing = true;
} catch (FolderDoesNotExistException $e) {
return false;
$isMissing = true;
}

if ($isMissing === false) {
return true;
}

return (bool)(($file !== null) ? !$file->isMissing() : false);
// file is missing
$this->errorParams->setErrorType(self::ERROR_TYPE_FILE);
$this->errorParams->setErrno(self::ERROR_ERRNO_FILE_MISSING);
return false;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions Classes/Linktype/LinktypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public function initializeErrorParams(array $params = null): void;
*/
public function getErrorParams(): ErrorParams;

public function getErrorShortcut(ErrorParams $errorParams = null): string;

/**
* Generate the localized error message from the error params saved from the parsing
*
Expand Down
10 changes: 10 additions & 0 deletions Classes/Repository/BrokenLinkRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ public function getBrokenLinks(array $pageList, array $linkTypes, array $searchF
);
}

$errorcode = $filter->getErrorcodeFilter();
if ($errorcode) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq(
self::TABLE . '.error_code',
$queryBuilder->createNamedParameter($errorcode)
)
);
}

if ($orderBy !== []) {
$values = array_shift($orderBy);
if ($values && is_array($values) && count($values) === 2) {
Expand Down
Loading

0 comments on commit 4435b72

Please sign in to comment.