Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions administrator/components/com_admin/script.php
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,9 @@ public function deleteUnexistingFiles()
'/libraries/legacy/view/legacy.php',
'/libraries/legacy/web/client.php',
'/libraries/legacy/web/web.php',
// Joomla! __DEPLOY_VERSION__
'/administrator/modules/mod_menu/preset/enabled.php',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be moved up the list. There's already a 3.8 section started.

'/administrator/modules/mod_menu/preset/disabled.php',
);

// TODO There is an issue while deleting folders using the ftp mode
Expand Down Expand Up @@ -2083,6 +2086,8 @@ public function deleteUnexistingFiles()
'/libraries/legacy/model',
'/libraries/legacy/view',
'/libraries/legacy/web',
// Joomla! __DEPLOY_VERSION__
'/administrator/modules/mod_menu/preset',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

);

jimport('joomla.filesystem.file');
Expand Down
15 changes: 15 additions & 0 deletions administrator/components/com_admin/views/help/tmpl/langforum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_admin
*
* @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

defined('_JEXEC') or die;

$forumId = (int) JText::_('COM_ADMIN_HELP_SUPPORT_OFFICIAL_LANGUAGE_FORUM_VALUE');
$forum_url = 'https://forum.joomla.org/viewforum.php?f=' . $forumId;

JFactory::getApplication()->redirect($forum_url);
68 changes: 62 additions & 6 deletions administrator/components/com_menus/controllers/menu.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ public function save($key = null, $urlVar = null)
return false;
}

$data = $model->validate($form, $data);
$validData = $model->validate($form, $data);

// Check for validation errors.
if ($data === false)
if ($validData === false)
{
// Get the validation messages.
$errors = $model->getErrors();
Expand All @@ -98,20 +98,28 @@ public function save($key = null, $urlVar = null)
$app->enqueueMessage($errors[$i], 'warning');
}
}

// Save the data in the session.
$app->setUserState('com_menus.edit.menu.data', $data);
$app->setUserState($context . '.data', $data);

// Redirect back to the edit screen.
$this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&layout=edit', false));

return false;
}

if (isset($validData['preset']))
{
$preset = trim($validData['preset']) ?: null;

unset($validData['preset']);
}

// Attempt to save the data.
if (!$model->save($data))
if (!$model->save($validData))
{
// Save the data in the session.
$app->setUserState('com_menus.edit.menu.data', $data);
$app->setUserState($context . '.data', $validData);

// Redirect back to the edit screen.
$this->setMessage(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
Expand All @@ -120,7 +128,25 @@ public function save($key = null, $urlVar = null)
return false;
}

$this->setMessage(JText::_('COM_MENUS_MENU_SAVE_SUCCESS'));
// Import the preset selected
if (isset($preset) && $data['client_id'] == 1)
{
try
{
MenusHelper::installPreset($preset, $data['menutype']);

$this->setMessage(JText::_('COM_MENUS_PRESET_IMPORT_SUCCESS'));
}
catch (Exception $e)
{
// Save was successful but the preset could not be loaded. Let it through with just a warning
$this->setMessage(JText::sprintf('COM_MENUS_PRESET_IMPORT_FAILED', $e->getMessage()));
}
}
else
{
$this->setMessage(JText::_('COM_MENUS_MENU_SAVE_SUCCESS'));
}

// Redirect the user and adjust session state based on the chosen task.
switch ($task)
Expand Down Expand Up @@ -153,4 +179,34 @@ public function save($key = null, $urlVar = null)
break;
}
}

/**
* Method to display a menu as preset xml.
*
* @return boolean True if successful, false otherwise.
*
* @since __DEPLOY_VERSION__
*/
public function exportXml()
{
// Check for request forgeries.
$this->checkToken();

$cid = $this->input->get('cid', array(), 'array');
$model = $this->getModel('Menu');
$item = $model->getItem(reset($cid));

if (!$item->menutype)
{
$this->setMessage(JText::_('COM_MENUS_SELECT_MENU_FIRST_EXPORT'), 'warning');

$this->setRedirect(JRoute::_('index.php?option=com_menus&view=menus', false));

return false;
}

$this->setRedirect(JRoute::_('index.php?option=com_menus&view=menu&menutype=' . $item->menutype . '&format=xml', false));

return true;
}
}
230 changes: 230 additions & 0 deletions administrator/components/com_menus/helpers/menus.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

use Joomla\CMS\Menu\MenuHelper;
use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;

defined('_JEXEC') or die;

/**
Expand All @@ -18,6 +22,8 @@ class MenusHelper
{
/**
* Defines the valid request variables for the reverse lookup.
*
* @since 1.6
*/
protected static $_filter = array('option', 'view', 'layout');

Expand Down Expand Up @@ -321,4 +327,228 @@ public static function getAssociations($pk)

return $associations;
}

/**
* Load the menu items from database for the given menutype
*
* @param string $menutype The selected menu type
* @param boolean $enabledOnly Whether to load only enabled/published menu items.
* @param int[] $exclude The menu items to exclude from the list
*
* @return array
*
* @since __DEPLOY_VERSION__
*/
public static function getMenuItems($menutype, $enabledOnly = false, $exclude = array())
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);

// Prepare the query.
$query->select('m.*')
->from('#__menu AS m')
->where('m.menutype = ' . $db->q($menutype))
->where('m.client_id = 1')
->where('m.id > 1');

if ($enabledOnly)
{
$query->where('m.published = 1');
}

// Filter on the enabled states.
$query->select('e.element')
->join('LEFT', '#__extensions AS e ON m.component_id = e.extension_id')
->where('(e.enabled = 1 OR e.enabled IS NULL)');

if (count($exclude))
{
$exId = array_filter($exclude, 'is_numeric');
$exEl = array_filter($exclude, 'is_string');

if ($exId)
{
$query->where('m.id NOT IN (' . implode(', ', array_map('intval', $exId)) . ')');
$query->where('m.parent_id NOT IN (' . implode(', ', array_map('intval', $exId)) . ')');
}

if ($exEl)
{
$query->where('e.element NOT IN (' . implode(', ', $db->quote($exEl)) . ')');
}
}

// Order by lft.
$query->order('m.lft');

$db->setQuery($query);

try
{
$menuItems = $db->loadObjectList();

foreach ($menuItems as &$menuitem)
{
$menuitem->params = new Registry($menuitem->params);
}
}
catch (RuntimeException $e)
{
$menuItems = array();

JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
Copy link
Contributor

@andrepereiradasilva andrepereiradasilva Jun 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't review the rest of the PR, but just one comment to this line

Why catch the default JDatabase (or Registry) exception and replace it with something called JERROR_AN_ERROR_HAS_OCCURRED?

This is more or less the same as saying: "Joomla knows the system is not working properly but doesn't have idea what happened! All it can say is .. an error has occurred ..." 😄

Maybe use $e->getMessage() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I actually reused the old code as is. I'll fix when I get to steal few minutes. Please review further so I can fix them all at once. Thanks.

}

return $menuItems;
}

/**
* Method to install a preset menu into database and link them to the given menutype
*
* @param string $preset The preset name
* @param string $menutype The target menutype
*
* @return void
*
* @throws Exception
*
* @since __DEPLOY_VERSION__
*/
public static function installPreset($preset, $menutype)
{
$items = MenuHelper::loadPreset($preset, false);

if (count($items) == 0)
{
throw new Exception(JText::_('COM_MENUS_PRESET_LOAD_FAILED'));
}

static::installPresetItems($items, $menutype, 1);
}

/**
* Method to install a preset menu item into database and link it to the given menutype
*
* @param stdClass[] &$items The single menuitem instance with a list of its descendants
* @param string $menutype The target menutype
* @param int $parent The parent id or object
*
* @return void
*
* @throws Exception
*
* @since __DEPLOY_VERSION__
*/
protected static function installPresetItems(&$items, $menutype, $parent = 1)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);

static $components = array();

if (!$components)
{
$query->select('extension_id, element')->from('#__extensions')->where('type = ' . $db->q('component'));
$components = $db->setQuery($query)->loadObjectList();
$components = ArrayHelper::getColumn((array) $components, 'element', 'extension_id');
}

foreach ($items as &$item)
{
/** @var JTableMenu $table */
$table = JTable::getInstance('Menu');

$item->alias = $menutype . '-' . $item->title;

if ($item->type == 'separator')
{
// Do not reuse a separator
$item->title = $item->title ?: '-';
$item->alias = microtime(true);
}
elseif ($item->type == 'heading' || $item->type == 'container')
{
// Try to match an existing record to have minimum collision for a heading
$keys = array(
'menutype' => $menutype,
'type' => $item->type,
'title' => $item->title,
'parent_id' => $parent,
'client_id' => 1,
);
$table->load($keys);
}
elseif ($item->type == 'url' || $item->type == 'component')
{
// Try to match an existing record to have minimum collision for a link
$keys = array(
'menutype' => $menutype,
'type' => $item->type,
'link' => $item->link,
'parent_id' => $parent,
'client_id' => 1,
);
$table->load($keys);
}

// Translate "hideitems" param value from "element" into "menu-item-id"
if ($item->type == 'container' && count($hideitems = (array) $item->params->get('hideitems')))
{
foreach ($hideitems as &$hel)
{
if (!is_numeric($hel))
{
$hel = array_search($hel, $components);
}
}

$query->clear()->select('id')->from('#__menu')->where('component_id IN (' . implode(', ', $hideitems) . ')');
$hideitems = $db->setQuery($query)->loadColumn();

$item->params->set('hideitems', $hideitems);
}

$record = array(
'menutype' => $menutype,
'title' => $item->title,
'alias' => $item->alias,
'type' => $item->type,
'link' => $item->link,
'browserNav' => $item->browserNav ? 1 : 0,
'img' => $item->class,
'access' => $item->access,
'component_id' => array_search($item->element, $components),
'parent_id' => $parent,
'client_id' => 1,
'published' => 1,
'language' => '*',
'home' => 0,
'params' => (string) $item->params,
);

if (!$table->bind($record))
{
throw new Exception('Bind failed: ' . $table->getError());
}

$table->setLocation($parent, 'last-child');

if (!$table->check())
{
throw new Exception('Check failed: ' . $table->getError());
}

if (!$table->store())
{
throw new Exception('Saved failed: ' . $table->getError());
}

$item->id = $table->get('id');

if (!empty($item->submenu))
{
static::installPresetItems($item->submenu, $menutype, $item->id);
}
}
}
}
1 change: 1 addition & 0 deletions administrator/components/com_menus/menus.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<folder>helpers</folder>
<folder>models</folder>
<folder>views</folder>
<folder>presets</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB.com_menus.ini</language>
Expand Down
Loading