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