855131cbd7def53aa469c2b97f2151e42f7808bf
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid_styled_content / Classes / ViewHelpers / Menu / KeywordsViewHelper.php
1 <?php
2 namespace TYPO3\CMS\FluidStyledContent\ViewHelpers\Menu;
3
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 */
16 use TYPO3\CMS\Core\Database\DatabaseConnection;
17 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
18
19 /**
20 * A view helper which returns pages with one of the same keywords as the given pages
21 *
22 * Search default starts at the root of the current page tree.
23 * With entryLevel this can be adjusted.
24 *
25 * = Example =
26 *
27 * <code title="Pages with the similar keyword(s) of page uid = 1 and uid = 2">
28 * <ce:menu.keywords pageUids="{0: 1, 1: 2}" as="pages">
29 * <f:for each="{pages}" as="page">
30 * {page.title}
31 * </f:for>
32 * </ce:menu.keywords>
33 * </code>
34 *
35 * <output>
36 * Page with the keywords "typo3" and "fluid"
37 * Page with the keyword "fluid"
38 * Page with the keyword "typo3"
39 * </output>
40 */
41 class KeywordsViewHelper extends AbstractViewHelper
42 {
43 use MenuViewHelperTrait;
44
45 /**
46 * Output escaping is disabled as child content contains HTML by default
47 *
48 * @var bool
49 */
50 protected $escapeOutput = false;
51
52 /**
53 * Initialize ViewHelper arguments
54 *
55 * @return void
56 */
57 public function initializeArguments()
58 {
59 $this->registerArgument('as', 'string', 'Name of template variable which will contain selected pages', true);
60 $this->registerArgument('entryLevel', 'integer', 'The entry level', false, 0);
61 $this->registerArgument('pageUids', 'array', 'Page UIDs of pages to fetch the keywords from', false, array());
62 $this->registerArgument('keywords', 'array', 'Keywords for which to search', false, array());
63 $this->registerArgument('includeNotInMenu', 'boolean', 'Include pages that are marked "hide in menu"?', false, false);
64 $this->registerArgument('includeMenuSeparator', 'boolean', 'Include pages of the type "Menu separator"?', false, false);
65 $this->registerArgument('excludeNoSearchPages', 'boolean', 'Exclude pages that are NOT marked "include in search"?', false, true);
66 }
67
68 /**
69 * Render the view helper
70 *
71 * @return string
72 */
73 public function render()
74 {
75 $typoScriptFrontendController = $this->getTypoScriptFrontendController();
76 $as = (string)$this->arguments['as'];
77 $entryLevel = (int)$this->arguments['entryLevel'];
78 $pageUids = (array)$this->arguments['pageUids'];
79 $keywords = (array)$this->arguments['keywords'];
80 $includeNotInMenu = (bool)$this->arguments['includeNotInMenu'];
81 $includeMenuSeparator = (bool)$this->arguments['includeMenuSeparator'];
82 $excludeNoSearchPages = (bool)$this->arguments['excludeNoSearchPages'];
83
84 // If no pages have been defined, use the current page
85 if (empty($pageUids)) {
86 $pageUids = array($typoScriptFrontendController->page['uid']);
87 }
88
89 // Transform the keywords list into an array
90 if (!is_array($keywords)) {
91 $unfilteredKeywords = $this->keywordsToArray($keywords);
92 } else {
93 $unfilteredKeywords = $keywords;
94 }
95
96 // Use the keywords of the page when none has been given
97 if (empty($keywords)) {
98 foreach ($pageUids as $pageUid) {
99 $page = $typoScriptFrontendController->sys_page->getPage($pageUid);
100 $unfilteredKeywords = array_merge(
101 $unfilteredKeywords,
102 $this->keywordsToArray($page['keywords'])
103 );
104 }
105 }
106 $filteredKeywords = array_unique($unfilteredKeywords);
107
108 $constraints = $this->getPageConstraints($includeNotInMenu, $includeMenuSeparator);
109 if ($excludeNoSearchPages) {
110 $constraints .= ' AND no_search = 0';
111 }
112
113 $keywordConstraints = array();
114 if ($filteredKeywords) {
115 $db = $this->getDatabaseConnection();
116 foreach ($filteredKeywords as $keyword) {
117 $keyword = $db->fullQuoteStr('%' . $db->escapeStrForLike($keyword, 'pages') . '%', 'pages');
118 $keywordConstraints[] = 'keywords LIKE ' . $keyword;
119 }
120 $constraints .= ' AND (' . implode(' OR ', $keywordConstraints) . ')';
121 }
122
123 // Start point
124 if ($entryLevel < 0) {
125 $entryLevel = count($typoScriptFrontendController->tmpl->rootLine) - 1 + $entryLevel;
126 }
127 $startUid = $typoScriptFrontendController->tmpl->rootLine[$entryLevel]['uid'];
128 $treePageUids = explode(
129 ',',
130 $typoScriptFrontendController->cObj->getTreeList($startUid, 20)
131 );
132
133 $pages = $typoScriptFrontendController->sys_page->getMenuForPages(
134 array_merge([$startUid], $treePageUids),
135 '*',
136 '',
137 $constraints
138 );
139 return $this->renderChildrenWithVariables(array(
140 $as => $pages
141 ));
142 }
143
144 /**
145 * Get a clean array of keywords
146 *
147 * The list of keywords can have a separator like comma, semicolon or line feed
148 *
149 * @param string $keywords The list of keywords
150 * @return array Cleaned up list
151 */
152 protected function keywordsToArray($keywords)
153 {
154 $keywordList = preg_split('/[,;' . LF . ']/', $keywords);
155
156 return array_filter(array_map('trim', $keywordList));
157 }
158
159 /**
160 * @return DatabaseConnection
161 */
162 protected function getDatabaseConnection()
163 {
164 return $GLOBALS['TYPO3_DB'];
165 }
166 }