Skip to content

Commit f73d4ed

Browse files
author
Francois Suter
committed
[TASK] Update link validator code
Update and improved the code which hooks into the linkvalidator process.
1 parent 01d78b6 commit f73d4ed

File tree

5 files changed

+141
-136
lines changed

5 files changed

+141
-136
lines changed

Classes/Linkvalidator/LinkhandlerLinkType.php

Lines changed: 101 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
<?php
2-
namespace Aoe\Linkhandler\Linkvalidator;
2+
namespace Cobweb\Linkhandler\Linkvalidator;
33

4-
/* *
5-
* This script belongs to the TYPO3 extension "linkhandler". *
6-
* *
7-
* It is free software; you can redistribute it and/or modify it under *
8-
* the terms of the GNU General Public License as published by the Free *
9-
* Software Foundation, either version 3 of the License, or (at your *
10-
* option) any later version. *
11-
* *
12-
* This script is distributed in the hope that it will be useful, but *
13-
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14-
* TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
15-
* Public License for more details. *
16-
* *
17-
* You should have received a copy of the GNU General Public License *
18-
* along with the script. *
19-
* If not, see http://www.gnu.org/licenses/gpl.html *
20-
* *
21-
* The TYPO3 project - inspiring people to share! *
22-
* */
4+
/*
5+
* This file is part of the TYPO3 CMS project.
6+
*
7+
* It is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, either version 2
9+
* of the License, or any later version.
10+
*
11+
* For the full copyright and license information, please read the
12+
* LICENSE.txt file that was distributed with this source code.
13+
*
14+
* The TYPO3 project - inspiring people to share!
15+
*/
2316

17+
use Cobweb\Linkhandler\Domain\Model\RecordLink;
2418
use TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype;
2519
use TYPO3\CMS\Backend\Utility\BackendUtility;
2620

@@ -44,6 +38,20 @@ class LinkhandlerLinkType extends AbstractLinktype
4438
*/
4539
const ERROR_TYPE_DISABLED = 'disabled';
4640

41+
/**
42+
* This error occurs when the related record does not exist at all.
43+
*
44+
* @var string
45+
*/
46+
const ERROR_TYPE_MISSING = 'missing';
47+
48+
/**
49+
* This error occurs when the related record does not exist at all.
50+
*
51+
* @var string
52+
*/
53+
const ERROR_TYPE_INVALID = 'invalid';
54+
4755
/**
4856
* TYPO3 database connection.
4957
*
@@ -66,89 +74,90 @@ class LinkhandlerLinkType extends AbstractLinktype
6674
protected $languageService;
6775

6876
/**
69-
* If this is TRUE an error will also be reported if the linked record
70-
* is disabled. Otherwise the error will only be reported if the
71-
* record is deleted or does not exist.
72-
*
73-
* @var boolean
74-
*/
75-
protected $reportHiddenRecords;
76-
77-
/**
78-
* Tab handler factory for retrieving link information.
79-
*
80-
* @var \Aoe\Linkhandler\Browser\TabHandlerFactory
77+
* @var RecordLink
8178
*/
82-
protected $tabHandlerFactory;
79+
protected $recordLink;
8380

8481
/**
85-
* Checks a given URL for validity
82+
* Checks a given URL for validity.
8683
*
8784
* @param string $url Url to check
8885
* @param array $softRefEntry The soft reference entry which builds the context of that url
89-
* @param \TYPO3\CMS\Linkvalidator\LinkAnalyzer $reference Parent instance
86+
* @param \TYPO3\CMS\Linkvalidator\LinkAnalyzer $linkAnalyzer Parent instance
9087
* @return boolean TRUE on success or FALSE on error
9188
*/
92-
public function checkLink($url, $softRefEntry, $reference)
89+
public function checkLink($url, $softRefEntry, $linkAnalyzer)
9390
{
9491
$response = true;
9592
$errorType = '';
9693
$errorParams = array();
9794
$this->initializeRequiredClasses();
9895

99-
$linkInfo = $this->tabHandlerFactory->getLinkInfoArrayFromMatchingHandler($url);
100-
if (empty($linkInfo)) {
101-
return true;
96+
try {
97+
$this->recordLink = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
98+
RecordLink::class,
99+
$url
100+
);
101+
}
102+
catch (\Exception $e) {
103+
// Set error type to invalid (record reference) and return early
104+
$this->setErrorParams(
105+
array(
106+
'errorType' => self::ERROR_TYPE_INVALID,
107+
'url' => $url
108+
)
109+
);
110+
return false;
102111
}
103112

104-
$tableName = $linkInfo['recordTable'];
105-
$rowid = $linkInfo['recordUid'];
106-
$row = null;
107-
$tsConfig = $reference->getTSConfig();
108-
$this->reportHiddenRecords = (bool)$tsConfig['tx_linkhandler.']['reportHiddenRecords'];
113+
// Get hidden records reporting parameter from TSconfig
114+
// If hidden records reporting is true, an error will be raised for hidden records and not just for deleted or missing records
115+
$tsConfig = $linkAnalyzer->getTSConfig();
116+
$reportHiddenRecords = (bool)$tsConfig['tx_linkhandler.']['reportHiddenRecords'];
109117

110-
// First check, if we find a non disabled record if the check
111-
// for hidden records is enabled.
112-
if ($this->reportHiddenRecords) {
113-
$row = $this->getRecordRow($tableName, $rowid, 'disabled');
114-
if ($row === null) {
115-
$response = false;
116-
$errorType = self::ERROR_TYPE_DISABLED;
117-
}
118+
// Get the record without enable fields
119+
// If reporting about "hidden" records, also get the record with enable fields
120+
$rawRecord = $this->getRecordRow();
121+
$enabledRecord = $rawRecord;
122+
if ($reportHiddenRecords) {
123+
$enabledRecord = $this->getRecordRow(true);
118124
}
119125

120-
// If no enabled record was found or we did not check that see
121-
// if we can find a non deleted record.
122-
if ($row === null) {
123-
$row = $this->getRecordRow($tableName, $rowid, 'deleted');
124-
if ($row === null) {
125-
$response = false;
126-
$errorType = self::ERROR_TYPE_DELETED;
126+
// If the record was not found without any condition, it is completely missing from the database
127+
if ($rawRecord === null) {
128+
$response = false;
129+
$errorType = self::ERROR_TYPE_MISSING;
130+
} else {
131+
// If the record was found, but its "delete" flag is set, it is a deleted record
132+
$deleteFlag = (!empty($GLOBALS['TCA'][$this->recordLink->getTable()]['ctrl']['delete'])) ? $GLOBALS['TCA'][$this->recordLink->getTable()]['ctrl']['delete'] : '';
133+
if ($deleteFlag !== '') {
134+
$deleted = (bool)$rawRecord[$deleteFlag];
135+
if ($deleted) {
136+
$response = false;
137+
$errorType = self::ERROR_TYPE_DELETED;
138+
}
127139
}
128-
}
129-
130-
// If we did not find a non deleted record, check if we find a
131-
// deleted one.
132-
if ($row === null) {
133-
$row = $this->getRecordRow($tableName, $rowid, 'all');
134-
if ($row === null) {
140+
// If no record was fetched when applying the "enable fields" conditions, the record is currently disabled
141+
if ($enabledRecord === null) {
135142
$response = false;
136-
$errorType = '';
143+
$errorType = self::ERROR_TYPE_DISABLED;
137144
}
138145
}
139146

140147
if (!$response) {
141148
$errorParams['errorType'] = $errorType;
142-
$errorParams['tablename'] = $tableName;
143-
$errorParams['uid'] = $rowid;
149+
$errorParams['tablename'] = $this->recordLink->getTable();
150+
$errorParams['uid'] = $this->recordLink->getId();
144151
$this->setErrorParams($errorParams);
145152
}
146153

147154
return $response;
148155
}
149156

150157
/**
151-
* Type fetching method, based on the type that softRefParserObj returns
158+
* Returns the type of link.
159+
*
160+
* If we detect a link starting with "record:", we consider it to be one of "ours".
152161
*
153162
* @param array $value Reference properties
154163
* @param string $type Current type
@@ -164,7 +173,7 @@ public function fetchType($value, $type, $key)
164173
}
165174

166175
/**
167-
* Generate the localized error message from the error params saved from the parsing
176+
* Generates the localized error message from the error params saved from the parsing.
168177
*
169178
* @param array $errorParams All parameters needed for the rendering of the error message
170179
* @return string Validation error message
@@ -173,55 +182,51 @@ public function getErrorMessage($errorParams)
173182
{
174183
$this->initializeRequiredClasses();
175184
$errorType = $errorParams['errorType'];
185+
186+
// For invalid reference, return early with simple error message
187+
if ($errorType === self::ERROR_TYPE_INVALID) {
188+
return $this->translate('list.report.invalidurl');
189+
}
190+
176191
$tableName = $errorParams['tablename'];
177192
$title = $this->translate('list.report.rowdeleted.default.title');
178193
if ($GLOBALS['TCA'][$tableName]['ctrl']['title']) {
179194
$title = $this->languageService->sL($GLOBALS['TCA'][$tableName]['ctrl']['title']);
180195
}
181196
switch ($errorType) {
182197
case self::ERROR_TYPE_DISABLED:
183-
$response = $this->getTranslatedErrorMessage('list.report.rownotvisible', $errorParams['uid'], $title);
198+
$message = $this->translate('list.report.rownotvisible');
199+
$response = sprintf($message, $title, $errorParams['uid']);
184200
break;
185201
case self::ERROR_TYPE_DELETED:
186-
$response = $this->getTranslatedErrorMessage('list.report.rowdeleted', $errorParams['uid'], $title);
202+
$message = $this->translate('list.report.rowdeleted');
203+
$response = sprintf($message, $title, $errorParams['uid']);
187204
break;
205+
// Default is missing record
188206
default:
189-
$response = $this->getTranslatedErrorMessage('list.report.rownotexisting', $errorParams['uid']);
207+
$message = $this->translate('list.report.rownotexisting');
208+
$response = sprintf($message, $title, $errorParams['uid']);
190209
}
191210
return $response;
192211
}
193212

194213
/**
195-
* Fetches the record with the given UID from the given table.
196-
*
197-
* The filter option accepts two values:
198-
*
199-
* "disabled" will filter out disabled and deleted records.
200-
* "deleted" filters out deleted records but will return disabled records.
201-
* If nothing is specified all records will be returned (including deleted).
214+
* Fetches the record corresponding to the current record reference.
202215
*
203-
* @param string $tableName The name of the table from which the record should be fetched.
204-
* @param string $uid The UID of the record that should be fetched.
205-
* @param string $filter A filter setting, can be empty or "disabled" or "deleted".
216+
* @param bool $applyEnableFields TRUE to apply enable fields condition to
206217
* @return array The result row as associative array.
207218
*/
208-
protected function getRecordRow($tableName, $uid, $filter = '')
219+
protected function getRecordRow($applyEnableFields = false)
209220
{
210221

211-
$whereStatement = 'uid = ' . (int)$uid;
212-
213-
switch ($filter) {
214-
case 'disabled':
215-
$whereStatement .= BackendUtility::BEenableFields($tableName) . BackendUtility::deleteClause($tableName);
216-
break;
217-
case 'deleted':
218-
$whereStatement .= BackendUtility::deleteClause($tableName);
219-
break;
222+
$whereStatement = 'uid = ' . $this->recordLink->getId();
223+
if ($applyEnableFields) {
224+
$whereStatement .= BackendUtility::BEenableFields($this->recordLink->getTable());
220225
}
221226

222227
$row = $this->databaseConnection->exec_SELECTgetSingleRow(
223228
'*',
224-
$tableName,
229+
$this->recordLink->getTable(),
225230
$whereStatement
226231
);
227232

@@ -253,14 +258,10 @@ protected function getTranslatedErrorMessage($translationKey, $uid, $title = nul
253258
}
254259

255260
/**
256-
* Initializes all required classes if required.
261+
* Initializes all required classes.
257262
*/
258263
protected function initializeRequiredClasses()
259264
{
260-
if (isset($this->tabHandlerFactory)) {
261-
return;
262-
}
263-
$this->tabHandlerFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('Aoe\\Linkhandler\\Browser\\TabHandlerFactory');
264265
$this->languageService = $GLOBALS['LANG'];
265266
$this->databaseConnection = $GLOBALS['TYPO3_DB'];
266267
}

README.md

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extensions.
1313

1414
For a version compatible with TYPO3 CMS 6.2, please use the TYPO3_6-2 branch.
1515

16+
1617
## Configuration
1718

1819
The configuration comes in two parts. TSconfig is used to define the
@@ -100,6 +101,7 @@ Note that the configuration key (i.e. `tx_news`) needs to be the same as the one
100101
used for the TSconfig part. The configuration is straight TS using the
101102
"typolink" function.
102103

104+
103105
#### Special configuration options
104106

105107
##### forceLink
@@ -129,6 +131,7 @@ In this case we want the `returnLast = url` parameter to be merged with the defa
129131
rendering configuration. With the `mergeWithLinkhandlerConfiguration = 1` we tell
130132
"linkhandler" to do just that.
131133

134+
132135
## Hooks
133136

134137
A single hook is provided. It can be used to manipulate most of the data from
@@ -146,11 +149,35 @@ The declared class must implement interface `\Cobweb\Linkhandler\ProcessLinkPara
146149
It can use the many getters and setters of `\Cobweb\Linkhandler\TypolinkHandler`
147150
to read and write data.
148151

152+
149153
## Soft reference handling
150154

151155
Extension "linkhandler" provides a soft reference parser which will pick any
152156
record being linked to and update the system references accordingly.
153157

158+
159+
## Linkvalidator support
160+
161+
This extension hooks into linkvalidator for checking record links. It is automatically activated.
162+
In case you want to disable it, you can use the following Page TSconfig:
163+
164+
To use it you have to adjust your linkvalidator TSConfig:
165+
166+
```
167+
mod.linkvalidator.linktypes := removeFromList(tx_linkhandler)
168+
}
169+
```
170+
171+
There is an additional configuration option that allows the reporting of links that point to
172+
disabled records (hidden, start tieme not met yet, etc):
173+
174+
```
175+
mod.linkvalidator {
176+
tx_linkhandler.reportHiddenRecords = 1
177+
}
178+
```
179+
180+
154181
## Tips & Tricks
155182

156183
### Link browser width
@@ -171,32 +198,3 @@ RTE {
171198
}
172199
}
173200
```
174-
175-
176-
**TODO: all the feature below are untested with TYPO3 CMS 7 LTS. Some may even have been removed during the cleanup but could be introduced again.**
177-
178-
## Linkvalidator support
179-
180-
This linkhandler version comes with its own linkvalidator link type that supports the new link format with four parameters
181-
and provides some additional features that are not merged yet to the core.
182-
183-
To use it you have to adjust your linkvalidator TSConfig:
184-
185-
```
186-
mod.linkvalidator {
187-
linktypes = db,external,tx_linkhandler
188-
}
189-
```
190-
191-
Please not that you need to use ```tx_linkhandler``` instead of ```linkhandler``` which is the default link type that comes with the core.
192-
193-
This link type comes with an additional configuration option that allows the reporting of links that point to hidden records:
194-
195-
```
196-
mod.linkvalidator {
197-
tx_linkhandler.reportHiddenRecords = 1
198-
}
199-
```
200-
201-
For this additional option to work this pending TYPO3 patch is required: https://review.typo3.org/#/c/26499/ (Provide TSConfig to link checkers).
202-
There is a TYPO3 6.2 fork that already implements the required patches (and some more) at Github: https://github.com/Intera/TYPO3.CMS

0 commit comments

Comments
 (0)