PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/administrator/components/com_menus/helpers/menus.php

https://bitbucket.org/ke2083/transfans.co.uk-website
PHP | 572 lines | 359 code | 78 blank | 135 comment | 47 complexity | 56d3ea746b81e07c92b936d9bb22b826 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Joomla.Administrator
  4. * @subpackage com_menus
  5. *
  6. * @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. use Joomla\CMS\Menu\MenuHelper;
  10. use Joomla\Registry\Registry;
  11. use Joomla\Utilities\ArrayHelper;
  12. defined('_JEXEC') or die;
  13. /**
  14. * Menus component helper.
  15. *
  16. * @since 1.6
  17. */
  18. class MenusHelper
  19. {
  20. /**
  21. * Defines the valid request variables for the reverse lookup.
  22. *
  23. * @since 1.6
  24. */
  25. protected static $_filter = array('option', 'view', 'layout');
  26. /**
  27. * Configure the Linkbar.
  28. *
  29. * @param string $vName The name of the active view.
  30. *
  31. * @return void
  32. *
  33. * @since 1.6
  34. */
  35. public static function addSubmenu($vName)
  36. {
  37. JHtmlSidebar::addEntry(
  38. JText::_('COM_MENUS_SUBMENU_MENUS'),
  39. 'index.php?option=com_menus&view=menus',
  40. $vName == 'menus'
  41. );
  42. JHtmlSidebar::addEntry(
  43. JText::_('COM_MENUS_SUBMENU_ITEMS'),
  44. 'index.php?option=com_menus&view=items',
  45. $vName == 'items'
  46. );
  47. }
  48. /**
  49. * Gets a list of the actions that can be performed.
  50. *
  51. * @param integer $parentId The menu ID.
  52. *
  53. * @return JObject
  54. *
  55. * @since 1.6
  56. * @deprecated 3.2 Use JHelperContent::getActions() instead
  57. */
  58. public static function getActions($parentId = 0)
  59. {
  60. // Log usage of deprecated function
  61. try
  62. {
  63. JLog::add(
  64. sprintf('%s() is deprecated. Use JHelperContent::getActions() with new arguments order instead.', __METHOD__),
  65. JLog::WARNING,
  66. 'deprecated'
  67. );
  68. }
  69. catch (RuntimeException $exception)
  70. {
  71. // Informational log only
  72. }
  73. // Get list of actions
  74. return JHelperContent::getActions('com_menus');
  75. }
  76. /**
  77. * Gets a standard form of a link for lookups.
  78. *
  79. * @param mixed $request A link string or array of request variables.
  80. *
  81. * @return mixed A link in standard option-view-layout form, or false if the supplied response is invalid.
  82. *
  83. * @since 1.6
  84. */
  85. public static function getLinkKey($request)
  86. {
  87. if (empty($request))
  88. {
  89. return false;
  90. }
  91. // Check if the link is in the form of index.php?...
  92. if (is_string($request))
  93. {
  94. $args = array();
  95. if (strpos($request, 'index.php') === 0)
  96. {
  97. parse_str(parse_url(htmlspecialchars_decode($request), PHP_URL_QUERY), $args);
  98. }
  99. else
  100. {
  101. parse_str($request, $args);
  102. }
  103. $request = $args;
  104. }
  105. // Only take the option, view and layout parts.
  106. foreach ($request as $name => $value)
  107. {
  108. if ((!in_array($name, self::$_filter)) && (!($name == 'task' && !array_key_exists('view', $request))))
  109. {
  110. // Remove the variables we want to ignore.
  111. unset($request[$name]);
  112. }
  113. }
  114. ksort($request);
  115. return 'index.php?' . http_build_query($request, '', '&');
  116. }
  117. /**
  118. * Get the menu list for create a menu module
  119. *
  120. * @param int $clientId Optional client id - viz 0 = site, 1 = administrator, can be NULL for all
  121. *
  122. * @return array The menu array list
  123. *
  124. * @since 1.6
  125. */
  126. public static function getMenuTypes($clientId = 0)
  127. {
  128. $db = JFactory::getDbo();
  129. $query = $db->getQuery(true)
  130. ->select('a.menutype')
  131. ->from('#__menu_types AS a');
  132. if (isset($clientId))
  133. {
  134. $query->where('a.client_id = ' . (int) $clientId);
  135. }
  136. $db->setQuery($query);
  137. return $db->loadColumn();
  138. }
  139. /**
  140. * Get a list of menu links for one or all menus.
  141. *
  142. * @param string $menuType An option menu to filter the list on, otherwise all menu with given client id links
  143. * are returned as a grouped array.
  144. * @param integer $parentId An optional parent ID to pivot results around.
  145. * @param integer $mode An optional mode. If parent ID is set and mode=2, the parent and children are excluded from the list.
  146. * @param array $published An optional array of states
  147. * @param array $languages Optional array of specify which languages we want to filter
  148. * @param int $clientId Optional client id - viz 0 = site, 1 = administrator, can be NULL for all (used only if menutype not givein)
  149. *
  150. * @return array
  151. *
  152. * @since 1.6
  153. */
  154. public static function getMenuLinks($menuType = null, $parentId = 0, $mode = 0, $published = array(), $languages = array(), $clientId = 0)
  155. {
  156. $db = JFactory::getDbo();
  157. $query = $db->getQuery(true)
  158. ->select('DISTINCT(a.id) AS value,
  159. a.title AS text,
  160. a.alias,
  161. a.level,
  162. a.menutype,
  163. a.client_id,
  164. a.type,
  165. a.published,
  166. a.template_style_id,
  167. a.checked_out,
  168. a.language,
  169. a.lft'
  170. )
  171. ->from('#__menu AS a');
  172. $query->select('e.name as componentname, e.element')
  173. ->join('left', '#__extensions e ON e.extension_id = a.component_id');
  174. if (JLanguageMultilang::isEnabled())
  175. {
  176. $query->select('l.title AS language_title, l.image AS language_image, l.sef AS language_sef')
  177. ->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language');
  178. }
  179. // Filter by the type if given, this is more specific than client id
  180. if ($menuType)
  181. {
  182. $query->where('(a.menutype = ' . $db->quote($menuType) . ' OR a.parent_id = 0)');
  183. }
  184. elseif (isset($clientId))
  185. {
  186. $query->where('a.client_id = ' . (int) $clientId);
  187. }
  188. // Prevent the parent and children from showing if requested.
  189. if ($parentId && $mode == 2)
  190. {
  191. $query->join('LEFT', '#__menu AS p ON p.id = ' . (int) $parentId)
  192. ->where('(a.lft <= p.lft OR a.rgt >= p.rgt)');
  193. }
  194. if (!empty($languages))
  195. {
  196. if (is_array($languages))
  197. {
  198. $languages = '(' . implode(',', array_map(array($db, 'quote'), $languages)) . ')';
  199. }
  200. $query->where('a.language IN ' . $languages);
  201. }
  202. if (!empty($published))
  203. {
  204. if (is_array($published))
  205. {
  206. $published = '(' . implode(',', $published) . ')';
  207. }
  208. $query->where('a.published IN ' . $published);
  209. }
  210. $query->where('a.published != -2');
  211. $query->order('a.lft ASC');
  212. // Get the options.
  213. $db->setQuery($query);
  214. try
  215. {
  216. $links = $db->loadObjectList();
  217. }
  218. catch (RuntimeException $e)
  219. {
  220. JError::raiseWarning(500, $e->getMessage());
  221. return false;
  222. }
  223. if (empty($menuType))
  224. {
  225. // If the menutype is empty, group the items by menutype.
  226. $query->clear()
  227. ->select('*')
  228. ->from('#__menu_types')
  229. ->where('menutype <> ' . $db->quote(''))
  230. ->order('title, menutype');
  231. if (isset($clientId))
  232. {
  233. $query->where('client_id = ' . (int) $clientId);
  234. }
  235. $db->setQuery($query);
  236. try
  237. {
  238. $menuTypes = $db->loadObjectList();
  239. }
  240. catch (RuntimeException $e)
  241. {
  242. JError::raiseWarning(500, $e->getMessage());
  243. return false;
  244. }
  245. // Create a reverse lookup and aggregate the links.
  246. $rlu = array();
  247. foreach ($menuTypes as &$type)
  248. {
  249. $rlu[$type->menutype] = & $type;
  250. $type->links = array();
  251. }
  252. // Loop through the list of menu links.
  253. foreach ($links as &$link)
  254. {
  255. if (isset($rlu[$link->menutype]))
  256. {
  257. $rlu[$link->menutype]->links[] = & $link;
  258. // Cleanup garbage.
  259. unset($link->menutype);
  260. }
  261. }
  262. return $menuTypes;
  263. }
  264. else
  265. {
  266. return $links;
  267. }
  268. }
  269. /**
  270. * Get the associations
  271. *
  272. * @param integer $pk Menu item id
  273. *
  274. * @return array
  275. *
  276. * @since 3.0
  277. */
  278. public static function getAssociations($pk)
  279. {
  280. $langAssociations = JLanguageAssociations::getAssociations('com_menus', '#__menu', 'com_menus.item', $pk, 'id', '', '');
  281. $associations = array();
  282. foreach ($langAssociations as $langAssociation)
  283. {
  284. $associations[$langAssociation->language] = $langAssociation->id;
  285. }
  286. return $associations;
  287. }
  288. /**
  289. * Load the menu items from database for the given menutype
  290. *
  291. * @param string $menutype The selected menu type
  292. * @param boolean $enabledOnly Whether to load only enabled/published menu items.
  293. * @param int[] $exclude The menu items to exclude from the list
  294. *
  295. * @return array
  296. *
  297. * @since 3.8.0
  298. */
  299. public static function getMenuItems($menutype, $enabledOnly = false, $exclude = array())
  300. {
  301. $db = JFactory::getDbo();
  302. $query = $db->getQuery(true);
  303. // Prepare the query.
  304. $query->select('m.*')
  305. ->from('#__menu AS m')
  306. ->where('m.menutype = ' . $db->q($menutype))
  307. ->where('m.client_id = 1')
  308. ->where('m.id > 1');
  309. if ($enabledOnly)
  310. {
  311. $query->where('m.published = 1');
  312. }
  313. // Filter on the enabled states.
  314. $query->select('e.element')
  315. ->join('LEFT', '#__extensions AS e ON m.component_id = e.extension_id')
  316. ->where('(e.enabled = 1 OR e.enabled IS NULL)');
  317. if (count($exclude))
  318. {
  319. $exId = array_filter($exclude, 'is_numeric');
  320. $exEl = array_filter($exclude, 'is_string');
  321. if ($exId)
  322. {
  323. $query->where('m.id NOT IN (' . implode(', ', array_map('intval', $exId)) . ')');
  324. $query->where('m.parent_id NOT IN (' . implode(', ', array_map('intval', $exId)) . ')');
  325. }
  326. if ($exEl)
  327. {
  328. $query->where('e.element NOT IN (' . implode(', ', $db->quote($exEl)) . ')');
  329. }
  330. }
  331. // Order by lft.
  332. $query->order('m.lft');
  333. $db->setQuery($query);
  334. try
  335. {
  336. $menuItems = $db->loadObjectList();
  337. foreach ($menuItems as &$menuitem)
  338. {
  339. $menuitem->params = new Registry($menuitem->params);
  340. }
  341. }
  342. catch (RuntimeException $e)
  343. {
  344. $menuItems = array();
  345. JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
  346. }
  347. return $menuItems;
  348. }
  349. /**
  350. * Method to install a preset menu into database and link them to the given menutype
  351. *
  352. * @param string $preset The preset name
  353. * @param string $menutype The target menutype
  354. *
  355. * @return void
  356. *
  357. * @throws Exception
  358. *
  359. * @since 3.8.0
  360. */
  361. public static function installPreset($preset, $menutype)
  362. {
  363. $items = MenuHelper::loadPreset($preset, false);
  364. if (count($items) == 0)
  365. {
  366. throw new Exception(JText::_('COM_MENUS_PRESET_LOAD_FAILED'));
  367. }
  368. static::installPresetItems($items, $menutype, 1);
  369. }
  370. /**
  371. * Method to install a preset menu item into database and link it to the given menutype
  372. *
  373. * @param stdClass[] $items The single menuitem instance with a list of its descendants
  374. * @param string $menutype The target menutype
  375. * @param int $parent The parent id or object
  376. *
  377. * @return void
  378. *
  379. * @throws Exception
  380. *
  381. * @since 3.8.0
  382. */
  383. protected static function installPresetItems(&$items, $menutype, $parent = 1)
  384. {
  385. $db = JFactory::getDbo();
  386. $query = $db->getQuery(true);
  387. static $components = array();
  388. if (!$components)
  389. {
  390. $query->select('extension_id, element')->from('#__extensions')->where('type = ' . $db->q('component'));
  391. $components = $db->setQuery($query)->loadObjectList();
  392. $components = ArrayHelper::getColumn((array) $components, 'element', 'extension_id');
  393. }
  394. $dispatcher = JEventDispatcher::getInstance();
  395. $dispatcher->trigger('onPreprocessMenuItems', array('com_menus.administrator.import', &$items, null, true));
  396. foreach ($items as &$item)
  397. {
  398. /** @var JTableMenu $table */
  399. $table = JTable::getInstance('Menu');
  400. $item->alias = $menutype . '-' . $item->title;
  401. if ($item->type == 'separator')
  402. {
  403. // Do not reuse a separator
  404. $item->title = $item->title ?: '-';
  405. $item->alias = microtime(true);
  406. }
  407. elseif ($item->type == 'heading' || $item->type == 'container')
  408. {
  409. // Try to match an existing record to have minimum collision for a heading
  410. $keys = array(
  411. 'menutype' => $menutype,
  412. 'type' => $item->type,
  413. 'title' => $item->title,
  414. 'parent_id' => $parent,
  415. 'client_id' => 1,
  416. );
  417. $table->load($keys);
  418. }
  419. elseif ($item->type == 'url' || $item->type == 'component')
  420. {
  421. if (substr($item->link, 0, 8) === 'special:')
  422. {
  423. $special = substr($item->link, 8);
  424. if ($special === 'language-forum')
  425. {
  426. $item->link = 'index.php?option=com_admin&amp;view=help&amp;layout=langforum';
  427. }
  428. elseif ($special === 'custom-forum')
  429. {
  430. $item->link = '';
  431. }
  432. }
  433. // Try to match an existing record to have minimum collision for a link
  434. $keys = array(
  435. 'menutype' => $menutype,
  436. 'type' => $item->type,
  437. 'link' => $item->link,
  438. 'parent_id' => $parent,
  439. 'client_id' => 1,
  440. );
  441. $table->load($keys);
  442. }
  443. // Translate "hideitems" param value from "element" into "menu-item-id"
  444. if ($item->type == 'container' && count($hideitems = (array) $item->params->get('hideitems')))
  445. {
  446. foreach ($hideitems as &$hel)
  447. {
  448. if (!is_numeric($hel))
  449. {
  450. $hel = array_search($hel, $components);
  451. }
  452. }
  453. $query->clear()->select('id')->from('#__menu')->where('component_id IN (' . implode(', ', $hideitems) . ')');
  454. $hideitems = $db->setQuery($query)->loadColumn();
  455. $item->params->set('hideitems', $hideitems);
  456. }
  457. $record = array(
  458. 'menutype' => $menutype,
  459. 'title' => $item->title,
  460. 'alias' => $item->alias,
  461. 'type' => $item->type,
  462. 'link' => $item->link,
  463. 'browserNav' => $item->browserNav ? 1 : 0,
  464. 'img' => $item->class,
  465. 'access' => $item->access,
  466. 'component_id' => array_search($item->element, $components),
  467. 'parent_id' => $parent,
  468. 'client_id' => 1,
  469. 'published' => 1,
  470. 'language' => '*',
  471. 'home' => 0,
  472. 'params' => (string) $item->params,
  473. );
  474. if (!$table->bind($record))
  475. {
  476. throw new Exception('Bind failed: ' . $table->getError());
  477. }
  478. $table->setLocation($parent, 'last-child');
  479. if (!$table->check())
  480. {
  481. throw new Exception('Check failed: ' . $table->getError());
  482. }
  483. if (!$table->store())
  484. {
  485. throw new Exception('Saved failed: ' . $table->getError());
  486. }
  487. $item->id = $table->get('id');
  488. if (!empty($item->submenu))
  489. {
  490. static::installPresetItems($item->submenu, $menutype, $item->id);
  491. }
  492. }
  493. }
  494. }