Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Resolve shortcut destination #550

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Classes/Configuration/AutomaticConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ protected function getTemplate() {
'emptyUrlReturnValue' => GeneralUtility::getIndpEnv('TYPO3_SITE_PATH')
),
'pagePath' => array(
'dontResolveShortcuts' => TRUE
),
'fileName' => array(
'defaultToHTMLsuffixOnPrev' => 0,
Expand Down
1 change: 1 addition & 0 deletions Classes/Configuration/ConfigurationReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class ConfigurationReader {
'init/defaultLanguageUid' => 0,
'init/emptySegmentValue' => '',
'pagePath/spaceCharacter' => '-', // undocumented & deprecated!
'pagePath/dontResolveShortcuts' => TRUE
);

/**
Expand Down
32 changes: 32 additions & 0 deletions Classes/Encoder/UrlEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,10 @@ protected function createPathComponentThroughOverride() {
protected function createPathComponentUsingRootline() {
$this->logger->debug('Starting path generation');

if ($this->configuration->get('pagePath/dontResolveShortcuts') === FALSE) {
$this->urlParameters['id'] = $this->resolveShortcut($this->urlParameters['id']);
}

$mountPointParameter = '';
if (isset($this->urlParameters['MP'])) {
$mountPointParameter = $this->urlParameters['MP'];
Expand Down Expand Up @@ -668,6 +672,34 @@ protected function createPathComponentUsingRootline() {
$this->logger->debug('Finished path generation');
}

/**
* Resolve the potential shortcut pageId
* Returns the original uid, if the page is not a shortcut.
* It uses the TypoScriptFrontendController to resolve the page shortcut.
* This is why the method could throw a RuntimeException, when shortcuts are nested 20 or more recursions.
*
* @param int $pageId The pageid of a potential shortcut to resolve
*
* @return int
*/
protected function resolveShortcut($pageId) {
$page = $this->pageRepository->getPage($pageId);
if ((int)$page['doktype'] === PageRepository::DOKTYPE_SHORTCUT) {
try{
$page = $this->tsfe->getPageShortcut($page['shortcut'], $page['shortcut_mode'], $pageId);
$pageId = $page['uid'];
} catch (\RuntimeException $ex) {
if ($ex->getCode() === 1294587212) {
$this->logger->warning('Maximum iteration of shortcuts reached on pageId #' . $pageId . '!'
. 'The resulting path could be wrong!');
}
} catch (\TYPO3\CMS\Core\Error\Http\PageNotFoundException $ex) {
$this->logger->warning('The target page of the shortcut(#' . $pageId . ') could not be found!');
}
}
return $pageId;
}

/**
* Encodes fixed postVars.
*
Expand Down
120 changes: 120 additions & 0 deletions Tests/Fixtures/realurl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ Page Tree:
- 3: page3
- 4: page4 (tx_realurl_exclude=1)
- 7: subpage7-without-parent
- 10: shortcut10-to-firstsubpage
- 11: subpage11
- 12: shortcut12-to-parentpage
- 13: shortcut13-to-subpage15
- 14: subpage14
- 15: subpage15
- 16: shortcut16-to-page8
- 17: shortcut17-to-page3
- 18: shortcut18-to-page16
-->
<pages>
<uid>1</uid>
Expand Down Expand Up @@ -116,4 +125,115 @@ Page Tree:
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>10</uid>
<pid>1</pid>
<doktype>4</doktype>
<shortcut></shortcut>
<shortcut_mode>1</shortcut_mode>
<deleted>0</deleted>
<title>shortcut10-to-firstsubpage</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>11</uid>
<pid>10</pid>
<doktype>1</doktype>
<deleted>0</deleted>
<title>subpage11</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>12</uid>
<pid>1</pid>
<doktype>4</doktype>
<shortcut></shortcut>
<shortcut_mode>3</shortcut_mode>
<deleted>0</deleted>
<title>shortcut12-to-parentpage</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>13</uid>
<pid>1</pid>
<doktype>4</doktype>
<shortcut>15</shortcut>
<shortcut_mode>0</shortcut_mode>
<deleted>0</deleted>
<title>shortcut13-to-subpage15</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>14</uid>
<pid>13</pid>
<doktype>0</doktype>
<deleted>0</deleted>
<title>subpage14</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>15</uid>
<pid>13</pid>
<doktype>0</doktype>
<deleted>0</deleted>
<title>subpage15</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>16</uid>
<pid>13</pid>
<doktype>4</doktype>
<shortcut>8</shortcut>
<shortcut_mode>0</shortcut_mode>
<deleted>0</deleted>
<title>shortcut16-to-page8</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>17</uid>
<pid>1</pid>
<doktype>4</doktype>
<shortcut>3</shortcut>
<shortcut_mode>0</shortcut_mode>
<deleted>0</deleted>
<title>shortcut17-to-page3</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
<pages>
<uid>18</uid>
<pid>1</pid>
<doktype>4</doktype>
<shortcut>16</shortcut>
<shortcut_mode>0</shortcut_mode>
<deleted>0</deleted>
<title>shortcut18-to-page16</title>
<alias></alias>
<tx_realurl_pathsegment></tx_realurl_pathsegment>
<tx_realurl_pathoverride>0</tx_realurl_pathoverride>
<tx_realurl_exclude>0</tx_realurl_exclude>
</pages>
</dataset>
78 changes: 78 additions & 0 deletions Tests/Functional/Encoder/UrlEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,84 @@ public function testRegisterDisablesEncoding() {
$this->assertEquals('index.php?id=2', $parameters['LD']['totalURL'], 'tx_realurl_enable=0 TSFE register does not disable encoding');
}

/**
* Test shortcut encoding with disabled shortcut resolving
*
* @test
*/
public function testDontResolveShortcuts() {
$parameters = $this->getParametersForPage(10);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('page10/', $parameters['LD']['totalURL'], 'Encode shortcut with pagePath/dontResolveShortcuts="TRUE"');
}

/**
* Test shortcut encoding of shortcut type "First subpage" with enabled shortcut resolving
*
* @test
*/
public function testEncodeShortcutFirstSubpage() {
$this->enableShortcutResolving();
$parameters = $this->getParametersForPage(10);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('subpage11/', $parameters['LD']['totalURL'], 'Shortcut to first subpage failed');
}

/**
* Test shortcut encoding of shortcut type "Parent page" with enabled shortcut resolving
*
* @test
*/
public function testEncodeShortcutParentPage() {
$this->enableShortcutResolving();
$parameters = $this->getParametersForPage(12);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('/', $parameters['LD']['totalURL'], 'Shortcut to parent page failed');
}

/**
* Test various shortcut encodings with enabled shortcut resolving
*
* @test
*/
public function testEncodeShortcut() {
$this->enableShortcutResolving();
$parameters = $this->getParametersForPage(13);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('shortcut13/subpage15/', $parameters['LD']['totalURL'], 'Normal shortcut to second subpage failed');

$parameters = $this->getParametersForPage(16);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('page2/subpage8/', $parameters['LD']['totalURL'], 'Shortcut from a shortcut child to a page in another branch of the pagetree failed');

$parameters = $this->getParametersForPage(17);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('page3/', $parameters['LD']['totalURL'], 'Shortcut to neighboring page failed');

$parameters = $this->getParametersForPage(18);
$encoder = GeneralUtility::makeInstance(UrlEncoder::class);
$encoder->encodeUrl($parameters);
$this->assertEquals('page2/subpage8/', $parameters['LD']['totalURL'], 'Chained shortcut failed');
}

/**
* Enables the shortcut resolving
*/
protected function enableShortcutResolving() {
// adjust the configuration to enable shortcut handling
$realUrlConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['realurl']);
$realUrlConf['_DEFAULT']['pagePath'] = [
'dontResolveShortcuts' => FALSE
];
$GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['realurl'] = serialize($realUrlConf);
}

/**
* @return TypoScriptFrontendController
*/
Expand Down