From f028b94922b8c5364c0e8748feaa2274d9e6d81e Mon Sep 17 00:00:00 2001
From: Mathias Schreiber <mathias.schreiber@wmdb.de>
Date: Fri, 30 Dec 2016 17:49:09 +0100
Subject: [PATCH] [FEATURE] Allow modification of typolink params

Added a hook to typolink if link type is "page" to be able
to modify page links (for example enriching them with further
information from the current page row).

Resolves: #79121
Releases: master
Change-Id: If7c21339bcc80319986d1a555c559d7964878c50
Reviewed-on: https://review.typo3.org/51075
Reviewed-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
---
 ...kInTypolinkForModificationOfPageParams.rst | 48 +++++++++++++++++++
 .../ContentObject/ContentObjectRenderer.php   | 47 +++++++++++-------
 ...ifyLinkConfigForPageLinksHookInterface.php | 33 +++++++++++++
 3 files changed, 111 insertions(+), 17 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-79121-ImplementHookInTypolinkForModificationOfPageParams.rst
 create mode 100644 typo3/sysext/frontend/Classes/ContentObject/TypolinkModifyLinkConfigForPageLinksHookInterface.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-79121-ImplementHookInTypolinkForModificationOfPageParams.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-79121-ImplementHookInTypolinkForModificationOfPageParams.rst
new file mode 100644
index 000000000000..61ecf267f520
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-79121-ImplementHookInTypolinkForModificationOfPageParams.rst
@@ -0,0 +1,48 @@
+.. include:: ../../Includes.txt
+
+============================================================================
+Feature: #79121 - Implement hook in typolink for modification of page params
+============================================================================
+
+See :issue:`79121`
+
+Description
+===========
+
+A new hook has been implemented in ContentObjectRenderer::typoLink for links to pages. With this 
+hook you can modify the link configuration, for example enriching it with additional parameters or 
+meta data from the page row.
+
+
+Impact
+======
+
+You can now register a hook via:
+
+.. code-block:: php
+
+	$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typolinkProcessing']['typolinkModifyParameterForPageLinks'][] = \Your\Namespace\Hooks\MyBeautifulHook::class;
+
+Your hook has to implement `TypolinkModifyLinkConfigForPageLinksHookInterface` with its method 
+:php:`modifyPageLinkConfiguration(array $linkConfiguration, array $linkDetails, array $pageRow)`.
+In :php:`$linkConfiguration` you get the configuration array for the link - this is what your hook 
+can modify and **has to** return.
+:php:`$linkDetails` contains additional information for your link and :php:`$pageRow` is the full
+database row of the page.
+
+For more information as to which configuration options may be changed, see TSRef_.
+
+Example implementation:
+-----------------------
+
+.. code-block:: php
+
+	public function modifyPageLinkConfiguration(array $linkConfiguration, array $linkDetails, array $pageRow) : array
+	{
+		$linkConfiguration['additionalParams'] .= $pageRow['myAdditionalParamsField'];
+		return $linkConfiguration;
+	}
+
+.. _TSRef: https://docs.typo3.org/typo3cms/TyposcriptReference/Functions/Typolink/Index.html
+
+.. index:: PHP-API
diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
index 430ea9e7bf17..d3c3e6a6ac90 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
@@ -5875,10 +5875,6 @@ class ContentObjectRenderer
 
             // Link to a page
             case LinkService::TYPE_PAGE:
-                $enableLinksAcrossDomains = $tsfe->config['config']['typolinkEnableLinksAcrossDomains'];
-                if ($conf['no_cache.']) {
-                    $conf['no_cache'] = $this->stdWrap($conf['no_cache'], $conf['no_cache.']);
-                }
                 // Checking if the id-parameter is an alias.
                 if (!empty($linkDetails['pagealias'])) {
                     $linkDetails['pageuid'] = $tsfe->sys_page->getPageIdFromAlias($linkDetails['pagealias']);
@@ -5886,19 +5882,6 @@ class ContentObjectRenderer
                     // If no id or alias is given
                     $linkDetails['pageuid'] = $tsfe->id;
                 }
-                $sectionMark = trim(isset($conf['section.']) ? $this->stdWrap($conf['section'], $conf['section.']) : $conf['section']);
-                if ($sectionMark === '' && isset($linkDetails['fragment'])) {
-                    $sectionMark = $linkDetails['fragment'];
-                }
-                if ($sectionMark !== '') {
-                    $sectionMark = '#' . (MathUtility::canBeInterpretedAsInteger($sectionMark) ? 'c' : '') . $sectionMark;
-                }
-                // Overruling 'type'
-                $pageType = $linkDetails['pagetype'] ?? 0;
-
-                if (isset($linkDetails['parameters'])) {
-                    $conf['additionalParams'] .= '&' . ltrim($linkDetails['parameters'], '&');
-                }
 
                 // Link to page even if access is missing?
                 if (isset($conf['linkAccessRestrictedPages'])) {
@@ -5906,9 +5889,39 @@ class ContentObjectRenderer
                 } else {
                     $disableGroupAccessCheck = (bool)$tsfe->config['config']['typolinkLinkAccessRestrictedPages'];
                 }
+
                 // Looking up the page record to verify its existence:
                 $page = $tsfe->sys_page->getPage($linkDetails['pageuid'], $disableGroupAccessCheck);
+
                 if (!empty($page)) {
+                    if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typolinkProcessing']['typolinkModifyParameterForPageLinks'])) {
+                        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typolinkProcessing']['typolinkModifyParameterForPageLinks'] as $classData) {
+                            $hookObject = GeneralUtility::makeInstance($classData);
+                            if (!$hookObject instanceof TypolinkModifyLinkConfigForPageLinksHookInterface) {
+                                throw new \UnexpectedValueException('$hookObject must implement interface ' . TypolinkModifyLinkConfigForPageLinksHookInterface::class, 1483114905);
+                            }
+                            /** @var $hookObject TypolinkModifyLinkConfigForPageLinksHookInterface */
+                            $conf = $hookObject->modifyPageLinkConfiguration($conf, $linkDetails, $page);
+                        }
+                    }
+                    $enableLinksAcrossDomains = $tsfe->config['config']['typolinkEnableLinksAcrossDomains'];
+                    if ($conf['no_cache.']) {
+                        $conf['no_cache'] = $this->stdWrap($conf['no_cache'], $conf['no_cache.']);
+                    }
+
+                    $sectionMark = trim(isset($conf['section.']) ? $this->stdWrap($conf['section'], $conf['section.']) : $conf['section']);
+                    if ($sectionMark === '' && isset($linkDetails['fragment'])) {
+                        $sectionMark = $linkDetails['fragment'];
+                    }
+                    if ($sectionMark !== '') {
+                        $sectionMark = '#' . (MathUtility::canBeInterpretedAsInteger($sectionMark) ? 'c' : '') . $sectionMark;
+                    }
+                    // Overruling 'type'
+                    $pageType = $linkDetails['pagetype'] ?? 0;
+
+                    if (isset($linkDetails['parameters'])) {
+                        $conf['additionalParams'] .= '&' . ltrim($linkDetails['parameters'], '&');
+                    }
                     // MointPoints, look for closest MPvar:
                     $MPvarAcc = [];
                     if (!$tsfe->config['config']['MP_disableTypolinkClosestMPvalue']) {
diff --git a/typo3/sysext/frontend/Classes/ContentObject/TypolinkModifyLinkConfigForPageLinksHookInterface.php b/typo3/sysext/frontend/Classes/ContentObject/TypolinkModifyLinkConfigForPageLinksHookInterface.php
new file mode 100644
index 000000000000..eb8e9283107c
--- /dev/null
+++ b/typo3/sysext/frontend/Classes/ContentObject/TypolinkModifyLinkConfigForPageLinksHookInterface.php
@@ -0,0 +1,33 @@
+<?php
+namespace TYPO3\CMS\Frontend\ContentObject;
+
+/*
+ * 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!
+ */
+
+/**
+ * interface for classes which hook into \TYPO3\CMS\Frontend\ContentObjectRenderer and wish to modify the typolink
+ * configuration of the page link.
+ */
+interface TypolinkModifyLinkConfigForPageLinksHookInterface
+{
+    /**
+     * Modifies the typolink page link configuration array.
+     *
+     * @param array $linkConfiguration The link configuration (for options see TSRef -> typolink)
+     * @param array $linkDetails Additional information for the link
+     * @param array $pageRow The complete page row for the page to link to
+     *
+     * @return array The modified $linkConfiguration
+     */
+    public function modifyPageLinkConfiguration(array $linkConfiguration, array $linkDetails, array $pageRow) : array;
+}
-- 
GitLab