5b283de2008aa2844d331a89fe3bfdde1824746c
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / Menu / CategoryMenuUtility.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject\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\Collection\AbstractRecordCollection;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Frontend\Category\Collection\CategoryCollection;
20
21 /**
22 * Utility class for menus based on category collections of pages.
23 *
24 * Returns all the relevant pages for rendering with a menu content object.
25 */
26 class CategoryMenuUtility
27 {
28 /**
29 * @var string Name of the field used for sorting the pages
30 */
31 protected static $sortingField;
32
33 /**
34 * Collects all pages for the selected categories, sorted according to configuration.
35 *
36 * @param string $selectedCategories Comma-separated list of system categories primary keys
37 * @param array $configuration TypoScript configuration for the "special." keyword
38 * @param \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject $parentObject Back-reference to the calling object
39 * @return string List of selected pages
40 */
41 public function collectPages($selectedCategories, $configuration, $parentObject)
42 {
43 $selectedPages = [];
44 $categoriesPerPage = [];
45 // Determine the name of the relation field
46 $relationField = '';
47 if (isset($configuration['relation.'])) {
48 $relationField = $parentObject->parent_cObj->stdWrap(
49 $configuration['relation'],
50 $configuration['relation.']
51 );
52 } elseif (isset($configuration['relation'])) {
53 $relationField = $configuration['relation'];
54 }
55 // Get the pages for each selected category
56 $selectedCategories = GeneralUtility::intExplode(',', $selectedCategories, true);
57 foreach ($selectedCategories as $aCategory) {
58 $collection = CategoryCollection::load(
59 $aCategory,
60 true,
61 'pages',
62 $relationField
63 );
64 $categoryUid = 0;
65 if ($collection instanceof AbstractRecordCollection) {
66 $categoryUid = $collection->getUid();
67 }
68 // Loop on the results, overlay each page record found
69 foreach ($collection as $pageItem) {
70 $parentObject->getSysPage()->versionOL('pages', $pageItem, true);
71 if (is_array($pageItem)) {
72 $selectedPages[$pageItem['uid']] = $parentObject->getSysPage()->getPageOverlay($pageItem);
73 // Keep a list of the categories each page belongs to
74 if (!isset($categoriesPerPage[$pageItem['uid']])) {
75 $categoriesPerPage[$pageItem['uid']] = [];
76 }
77 $categoriesPerPage[$pageItem['uid']][] = $categoryUid;
78 }
79 }
80 }
81 // Loop on the selected pages to add the categories they belong to, as comma-separated list of category uid's)
82 // (this makes them available for rendering, if needed)
83 foreach ($selectedPages as $uid => $pageRecord) {
84 $selectedPages[$uid]['_categories'] = implode(',', $categoriesPerPage[$uid]);
85 }
86
87 // Sort the pages according to the sorting property
88 self::$sortingField = isset($configuration['sorting.']) ? $parentObject->getParentContentObject()->stdWrap($configuration['sorting'], $configuration['sorting.']) : $configuration['sorting'];
89 $order = isset($configuration['order.']) ? $parentObject->getParentContentObject()->stdWrap($configuration['order'], $configuration['order.']) : $configuration['order'];
90 $selectedPages = $this->sortPages($selectedPages, $order);
91
92 return $selectedPages;
93 }
94
95 /**
96 * Sorts the selected pages
97 *
98 * If the sorting field is not defined or does not corresponding to an existing field
99 * of the "pages" tables, the list of pages will remain unchanged.
100 *
101 * @param array $pages List of selected pages
102 * @param string $order Order for sorting (should "asc" or "desc")
103 * @return array Sorted list of pages
104 */
105 protected function sortPages($pages, $order)
106 {
107 // Perform the sorting only if a criterion was actually defined
108 if (!empty(self::$sortingField)) {
109 // Check that the sorting field exists (checking the first record is enough)
110 $firstPage = current($pages);
111 if (isset($firstPage[self::$sortingField])) {
112 // Make sure the order property is either "asc" or "desc" (default is "asc")
113 if (!empty($order)) {
114 $order = strtolower($order);
115 if ($order !== 'desc') {
116 $order = 'asc';
117 }
118 }
119 uasort(
120 $pages,
121 [
122 self::class,
123 'sortPagesUtility'
124 ]
125 );
126 // If the sort order is descending, reverse the sorted array
127 if ($order === 'desc') {
128 $pages = array_reverse($pages, true);
129 }
130 }
131 }
132 return $pages;
133 }
134
135 /**
136 * Static utility for sorting pages according to the selected criterion
137 *
138 * @param array $pageA Record for first page to be compared
139 * @param array $pageB Record for second page to be compared
140 * @return array -1 if first argument is smaller than second argument, 1 if first is greater than second and 0 if both are equal
141 */
142 public static function sortPagesUtility($pageA, $pageB)
143 {
144 return strnatcasecmp($pageA[self::$sortingField], $pageB[self::$sortingField]);
145 }
146 }