f7a515783f4b66735449e9ec15a25d8606d7d754
[Packages/TYPO3.CMS.git] / typo3 / sysext / seo / Classes / Canonical / CanonicalGenerator.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Seo\Canonical;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
21 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
22 use TYPO3\CMS\Frontend\Page\PageRepository;
23
24 /**
25 * Class to add the canonical tag to the page
26 *
27 * @internal this class is not part of TYPO3's Core API.
28 */
29 class CanonicalGenerator
30 {
31 /**
32 * @var TypoScriptFrontendController
33 */
34 protected $typoScriptFrontendController;
35
36 /**
37 * @var PageRepository
38 */
39 protected $pageRepository;
40
41 /**
42 * @var Dispatcher
43 */
44 protected $signalSlotDispatcher;
45
46 /**
47 * CanonicalGenerator constructor
48 *
49 * @param TypoScriptFrontendController $typoScriptFrontendController
50 * @param Dispatcher $signalSlotDispatcher
51 */
52 public function __construct(TypoScriptFrontendController $typoScriptFrontendController = null, Dispatcher $signalSlotDispatcher = null)
53 {
54 if ($typoScriptFrontendController === null) {
55 $typoScriptFrontendController = $this->getTypoScriptFrontendController();
56 }
57 if ($signalSlotDispatcher === null) {
58 $signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
59 }
60 $this->typoScriptFrontendController = $typoScriptFrontendController;
61 $this->signalSlotDispatcher = $signalSlotDispatcher;
62 $this->pageRepository = GeneralUtility::makeInstance(PageRepository::class);
63 }
64
65 /**
66 * @return string
67 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException
68 * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException
69 */
70 public function generate(): string
71 {
72 $href = '';
73 $this->signalSlotDispatcher->dispatch(self::class, 'beforeGeneratingCanonical', [&$href]);
74
75 if (empty($href) && (int)$this->typoScriptFrontendController->page['no_index'] === 1) {
76 return '';
77 }
78
79 if (empty($href)) {
80 // 1) Check if page show content from other page
81 $href = $this->checkContentFromPid();
82 }
83 if (empty($href)) {
84 // 2) Check if page has canonical URL set
85 $href = $this->checkForCanonicalLink();
86 }
87 if (empty($href)) {
88 // 3) Fallback, create canonical URL
89 $href = $this->checkDefaultCanonical();
90 }
91
92 if (!empty($href)) {
93 $canonical = '<link ' . GeneralUtility::implodeAttributes([
94 'rel' => 'canonical',
95 'href' => $href
96 ], true) . '/>' . LF;
97 $this->typoScriptFrontendController->additionalHeaderData[] = $canonical;
98 return $canonical;
99 }
100 return '';
101 }
102
103 /**
104 * @return string
105 */
106 protected function checkForCanonicalLink(): string
107 {
108 if (!empty($this->typoScriptFrontendController->page['canonical_link'])) {
109 return $this->typoScriptFrontendController->cObj->typoLink_URL([
110 'parameter' => $this->typoScriptFrontendController->page['canonical_link'],
111 'forceAbsoluteUrl' => true,
112 ]);
113 }
114 return '';
115 }
116
117 /**
118 * @return string
119 */
120 protected function checkContentFromPid(): string
121 {
122 if (!empty($this->typoScriptFrontendController->page['content_from_pid'])) {
123 $parameter = (int)$this->typoScriptFrontendController->page['content_from_pid'];
124 if ($parameter > 0) {
125 $targetPage = $this->pageRepository->getPage($parameter, true);
126 if (!empty($targetPage['canonical_link'])) {
127 $parameter = $targetPage['canonical_link'];
128 }
129 return $this->typoScriptFrontendController->cObj->typoLink_URL([
130 'parameter' => $parameter,
131 'forceAbsoluteUrl' => true,
132 ]);
133 }
134 }
135 return '';
136 }
137
138 /**
139 * @return string
140 */
141 protected function checkDefaultCanonical(): string
142 {
143 return $this->typoScriptFrontendController->cObj->typoLink_URL([
144 'parameter' => $this->typoScriptFrontendController->page['uid'],
145 'forceAbsoluteUrl' => true,
146 'addQueryString' => true,
147 'addQueryString.' => [
148 'exclude' => 'type,no_cache'
149 ],
150 'useCacheHash' => true,
151 ]);
152 }
153
154 /**
155 * @return TypoScriptFrontendController
156 */
157 protected function getTypoScriptFrontendController(): TypoScriptFrontendController
158 {
159 return $GLOBALS['TSFE'];
160 }
161 }