/**
* Method to build menu database entries for a component
*
* @param int|null $componentId The component ID for which I'm building menus
*
* @return boolean True if successful
*
* @since 3.1
*/
protected function _buildAdminMenus($componentId = null)
{
$db = $this->parent->getDbo();
$option = $this->element;
// If a component exists with this option in the table within the protected menutype 'main' then we don't need to add menus
$query = $db->getQuery(true)->select([$db->quoteName('m.id'), $db->quoteName('e.extension_id')])->from($db->quoteName('#__menu', 'm'))->join('LEFT', $db->quoteName('#__extensions', 'e'), $db->quoteName('m.component_id') . ' = ' . $db->quoteName('e.extension_id'))->where([$db->quoteName('m.parent_id') . ' = 1', $db->quoteName('m.client_id') . ' = 1', $db->quoteName('m.menutype') . ' = ' . $db->quote('main'), $db->quoteName('e.element') . ' = :element'])->bind(':element', $option);
$db->setQuery($query);
// In case of a failed installation (e.g. timeout error) we may have duplicate menu item and extension records.
$componentrows = $db->loadObjectList();
// Check if menu items exist
if (!empty($componentrows)) {
// Don't do anything if overwrite has not been enabled
if (!$this->parent->isOverwrite()) {
return true;
}
// Remove all menu items
foreach ($componentrows as $componentrow) {
// Remove existing menu items if overwrite has been enabled
if ($option) {
// If something goes wrong, there's no way to rollback @todo: Search for better solution
$this->_removeAdminMenus($componentrow->extension_id);
}
}
}
// Only try to detect the component ID if it's not provided
if (empty($componentId)) {
// Lets find the extension id
$query->clear()->select($db->quoteName('e.extension_id'))->from($db->quoteName('#__extensions', 'e'))->where([$db->quoteName('e.type') . ' = ' . $db->quote('component'), $db->quoteName('e.element') . ' = :element'])->bind(':element', $option);
$db->setQuery($query);
$componentId = $db->loadResult();
}
// Ok, now its time to handle the menus. Start with the component root menu, then handle submenus.
$menuElement = $this->getManifest()->administration->menu;
// Just do not create the menu if $menuElement not exist
if (!$menuElement) {
return true;
}
// If the menu item is hidden do nothing more, just return
if (\in_array((string) $menuElement['hidden'], array('true', 'hidden'))) {
return true;
}
// Let's figure out what the menu item data should look like
$data = array();
// I have a menu element, use this information
$data['menutype'] = 'main';
$data['client_id'] = 1;
$data['title'] = (string) trim($menuElement);
$data['alias'] = (string) $menuElement;
$data['type'] = 'component';
$data['published'] = 1;
$data['parent_id'] = 1;
$data['component_id'] = $componentId;
$data['img'] = (string) $menuElement->attributes()->img ?: 'class:component';
$data['home'] = 0;
$data['path'] = '';
$data['params'] = '';
if ($params = $menuElement->params) {
// Pass $params through Registry to convert to JSON.
$params = new Registry($params);
$data['params'] = $params->toString();
}
// Set the menu link
$request = [];
if ((string) $menuElement->attributes()->task) {
$request[] = 'task=' . $menuElement->attributes()->task;
}
if ((string) $menuElement->attributes()->view) {
$request[] = 'view=' . $menuElement->attributes()->view;
}
$qstring = \count($request) ? '&' . implode('&', $request) : '';
$data['link'] = 'index.php?option=' . $option . $qstring;
// Try to create the menu item in the database
$parent_id = $this->_createAdminMenuItem($data, 1);
if ($parent_id === false) {
return false;
}
/*
* Process SubMenus
*/
if (!$this->getManifest()->administration->submenu) {
// No submenu? We're done.
return true;
}
foreach ($this->getManifest()->administration->submenu->menu as $child) {
$data = array();
$data['menutype'] = 'main';
$data['client_id'] = 1;
$data['title'] = (string) trim($child);
$data['alias'] = (string) $child;
$data['type'] = 'component';
$data['published'] = 1;
$data['parent_id'] = $parent_id;
$data['component_id'] = $componentId;
$data['img'] = (string) $child->attributes()->img ?: 'class:component';
$data['home'] = 0;
$data['params'] = '';
if ($params = $child->params) {
// Pass $params through Registry to convert to JSON.
$params = new Registry($params);
$data['params'] = $params->toString();
}
// Set the sub menu link
if ((string) $child->attributes()->link) {
$data['link'] = 'index.php?' . $child->attributes()->link;
} else {
$request = array();
if ((string) $child->attributes()->act) {
$request[] = 'act=' . $child->attributes()->act;
}
if ((string) $child->attributes()->task) {
$request[] = 'task=' . $child->attributes()->task;
}
if ((string) $child->attributes()->controller) {
$request[] = 'controller=' . $child->attributes()->controller;
}
if ((string) $child->attributes()->view) {
$request[] = 'view=' . $child->attributes()->view;
}
if ((string) $child->attributes()->layout) {
$request[] = 'layout=' . $child->attributes()->layout;
}
if ((string) $child->attributes()->sub) {
$request[] = 'sub=' . $child->attributes()->sub;
}
$qstring = \count($request) ? '&' . implode('&', $request) : '';
$data['link'] = 'index.php?option=' . $option . $qstring;
}
$submenuId = $this->_createAdminMenuItem($data, $parent_id);
if ($submenuId === false) {
return false;
}
/*
* Since we have created a menu item, we add it to the installation step stack
* so that if we have to rollback the changes we can undo it.
*/
$this->parent->pushStep(array('type' => 'menu', 'id' => $componentId));
}
return true;
}