1 <?php
2 /**
3 * @package Joomla.Libraries
4 * @subpackage Component
5 *
6 * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE.txt
8 */
9
10 defined('JPATH_PLATFORM') or die;
11
12 /**
13 * Rule to identify the right Itemid for a view in a component
14 *
15 * @since 3.4
16 */
17 class JComponentRouterRulesMenu implements JComponentRouterRulesInterface
18 {
19 /**
20 * Router this rule belongs to
21 *
22 * @var JComponentRouterView
23 * @since 3.4
24 */
25 protected $router;
26
27 /**
28 * Lookup array of the menu items
29 *
30 * @var array
31 * @since 3.4
32 */
33 protected $lookup = array();
34
35 /**
36 * Class constructor.
37 *
38 * @param JComponentRouterView $router Router this rule belongs to
39 *
40 * @since 3.4
41 */
42 public function __construct(JComponentRouterView $router)
43 {
44 $this->router = $router;
45
46 $this->buildLookup();
47 }
48
49 /**
50 * Finds the right Itemid for this query
51 *
52 * @param array &$query The query array to process
53 *
54 * @return void
55 *
56 * @since 3.4
57 */
58 public function preprocess(&$query)
59 {
60 /**
61 * If the active item id is not the same as the supplied item id or we have a supplied item id and no active
62 * menu item then we just use the supplied menu item and continue
63 */
64 if (isset($query['Itemid'])
65 && (($this->router->menu->getActive() && $query['Itemid'] != $this->router->menu->getActive()->id)
66 || ($this->router->menu->getActive() === null)))
67 {
68 return;
69 }
70
71 $language = '*';
72 if (isset($query['lang']))
73 {
74 $language = $query['lang'];
75
76 if (!isset($this->lookup[$query['lang']]))
77 {
78 $this->buildLookup($query['lang']);
79 }
80 }
81
82 $needles = $this->router->getPath($query);
83
84 $layout = '';
85
86 if (isset($query['layout']))
87 {
88 $layout = ':' . $query['layout'];
89 }
90
91 if ($needles)
92 {
93 foreach ($needles as $view => $ids)
94 {
95 if (isset($this->lookup[$language][$view . $layout]))
96 {
97 if (is_bool($ids))
98 {
99 $query['Itemid'] = $this->lookup[$language][$view . $layout];
100 return;
101 }
102 foreach ($ids as $id => $segment)
103 {
104 if (isset($this->lookup[$language][$view . $layout][(int) $id]))
105 {
106 $query['Itemid'] = $this->lookup[$language][$view . $layout][(int) $id];
107 return;
108 }
109
110 if (isset($this->lookup[$language][$view][(int) $id]))
111 {
112 $query['Itemid'] = $this->lookup[$language][$view][(int) $id];
113 return;
114 }
115 }
116 }
117 }
118 }
119
120 // Check if the active menuitem matches the requested language
121 $active = $this->router->menu->getActive();
122
123 if ($active && $active->component === 'com_' . $this->router->getName()
124 && ($language === '*' || in_array($active->language, array('*', $language)) || !JLanguageMultilang::isEnabled()))
125 {
126 $query['Itemid'] = $active->id;
127 return;
128 }
129
130 // If not found, return language specific home link
131 $default = $this->router->menu->getDefault($language);
132
133 if (!empty($default->id))
134 {
135 $query['Itemid'] = $default->id;
136 }
137 }
138
139 /**
140 * Method to build the lookup array
141 *
142 * @param string $language The language that the lookup should be built up for
143 *
144 * @return void
145 *
146 * @since 3.4
147 */
148 protected function buildLookup($language = '*')
149 {
150 // Prepare the reverse lookup array.
151 if (!isset($this->lookup[$language]))
152 {
153 $this->lookup[$language] = array();
154
155 $component = JComponentHelper::getComponent('com_' . $this->router->getName());
156 $views = $this->router->getViews();
157
158 $attributes = array('component_id');
159 $values = array((int) $component->id);
160
161 $attributes[] = 'language';
162 $values[] = array($language, '*');
163
164 $items = $this->router->menu->getItems($attributes, $values);
165
166 foreach ($items as $item)
167 {
168 if (isset($item->query) && isset($item->query['view']))
169 {
170 $view = $item->query['view'];
171
172 $layout = '';
173
174 if (isset($item->query['layout']))
175 {
176 $layout = ':' . $item->query['layout'];
177 }
178
179 if ($views[$view]->key)
180 {
181 if (!isset($this->lookup[$language][$view . $layout]))
182 {
183 $this->lookup[$language][$view . $layout] = array();
184 }
185
186 if (!isset($this->lookup[$language][$view]))
187 {
188 $this->lookup[$language][$view] = array();
189 }
190
191 // If menuitem has no key set, we assume 0.
192 if (!isset($item->query[$views[$view]->key]))
193 {
194 $item->query[$views[$view]->key] = 0;
195 }
196
197 /**
198 * Here it will become a bit tricky
199 * language != * can override existing entries
200 * language == * cannot override existing entries
201 */
202 if (!isset($this->lookup[$language][$view . $layout][$item->query[$views[$view]->key]]) || $item->language !== '*')
203 {
204 $this->lookup[$language][$view . $layout][$item->query[$views[$view]->key]] = $item->id;
205 $this->lookup[$language][$view][$item->query[$views[$view]->key]] = $item->id;
206 }
207 }
208 else
209 {
210 /**
211 * Here it will become a bit tricky
212 * language != * can override existing entries
213 * language == * cannot override existing entries
214 */
215 if (!isset($this->lookup[$language][$view . $layout]) || $item->language !== '*')
216 {
217 $this->lookup[$language][$view . $layout] = $item->id;
218 $this->lookup[$language][$view] = $item->id;
219 }
220 }
221 }
222 }
223 }
224 }
225
226 /**
227 * Dummymethod to fullfill the interface requirements
228 *
229 * @param array &$segments The URL segments to parse
230 * @param array &$vars The vars that result from the segments
231 *
232 * @return void
233 *
234 * @since 3.4
235 * @codeCoverageIgnore
236 */
237 public function parse(&$segments, &$vars)
238 {
239 }
240
241 /**
242 * Dummymethod to fullfill the interface requirements
243 *
244 * @param array &$query The vars that should be converted
245 * @param array &$segments The URL segments to create
246 *
247 * @return void
248 *
249 * @since 3.4
250 * @codeCoverageIgnore
251 */
252 public function build(&$query, &$segments)
253 {
254 }
255 }
256