* @package com.woltlab.wcf * @subpackage acp.package.plugin * @category Community Framework * @since 2.2 */ class MenuItemPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin { /** * @inheritDoc */ public $className = MenuItemEditor::class; /** * @inheritDoc */ public $tagName = 'item'; /** * @inheritDoc */ protected function handleDelete(array $items) { $sql = "DELETE FROM wcf".WCF_N."_menu_item WHERE identifier = ? AND packageID = ?"; $statement = WCF::getDB()->prepareStatement($sql); WCF::getDB()->beginTransaction(); foreach ($items as $item) { $statement->execute([ $item['attributes']['identifier'], $this->installation->getPackageID() ]); } WCF::getDB()->commitTransaction(); } /** * @inheritDoc * @throws SystemException */ protected function getElement(\DOMXPath $xpath, array &$elements, \DOMElement $element) { $nodeValue = $element->nodeValue; if ($element->tagName === 'title') { if (empty($element->getAttribute('language'))) { throw new SystemException("Missing required attribute 'language' for menu item '" . $element->parentNode->getAttribute('identifier') . "'"); } // can occur multiple times using the `language` attribute if (!isset($elements['title'])) $elements['title'] = []; $elements['title'][$element->getAttribute('language')] = $element->nodeValue; } else { $elements[$element->tagName] = $nodeValue; } } /** * @inheritDoc * @throws SystemException */ protected function prepareImport(array $data) { $menuID = null; if (!empty($data['elements']['menu'])) { $sql = "SELECT menuID FROM wcf".WCF_N."_menu WHERE identifier = ?"; $statement = WCF::getDB()->prepareStatement($sql, 1); $statement->execute([$data['elements']['menu']]); $row = $statement->fetchSingleRow(); if ($row === false) { throw new SystemException("Unable to find menu '" . $data['elements']['menu'] . "' for menu item '" . $data['attributes']['identifier'] . "'"); } $menuID = $row['menuID']; } $parentItemID = null; if (!empty($data['elements']['parent'])) { if ($menuID !== null) { throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' can either have an associated menu or a parent menu item, but not both."); } $sql = "SELECT * FROM wcf".WCF_N."_menu_item WHERE identifier = ?"; $statement = WCF::getDB()->prepareStatement($sql, 1); $statement->execute([$data['elements']['parent']]); $parent = $statement->fetchObject(MenuItem::class); if ($parent === null) { throw new SystemException("Unable to find parent menu item '" . $data['elements']['parent'] . "' for menu item '" . $data['attributes']['identifier'] . "'"); } $parentItemID = $parent->itemID; $menuID = $parent->menuID; } if ($menuID === null && $parentItemID === null) { throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' must either have an associated menu or a parent menu item."); } $pageID = null; if (!empty($data['elements']['page'])) { $sql = "SELECT pageID FROM wcf".WCF_N."_page WHERE identifier = ?"; $statement = WCF::getDB()->prepareStatement($sql, 1); $statement->execute([$data['elements']['page']]); $row = $statement->fetchSingleRow(); if ($row === false) { throw new SystemException("Unable to find page '" . $data['elements']['page'] . "' for menu item '" . $data['attributes']['identifier'] . "'"); } $pageID = $row['pageID']; } $externalURL = (!empty($data['elements']['externalURL'])) ? $data['elements']['externalURL'] : ''; if ($pageID === null && empty($externalURL)) { throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' must either have an associated page or an external url set."); } else if ($pageID !== null && !empty($externalURL)) { throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' can either have an associated page or an external url, but not both."); } return [ 'externalURL' => $externalURL, 'identifier' => $data['attributes']['identifier'], 'menuID' => $menuID, 'originIsSystem' => 1, 'pageID' => $pageID, 'parentItemID' => $parentItemID, 'showOrder' => $this->getItemOrder($menuID, $parentItemID), 'title' => $this->getI18nValues($data['elements']['title']) ]; } /** * @inheritDoc */ protected function findExistingItem(array $data) { $sql = "SELECT * FROM wcf".WCF_N."_menu_item WHERE identifier = ? AND packageID = ?"; $parameters = array( $data['identifier'], $this->installation->getPackageID() ); return array( 'sql' => $sql, 'parameters' => $parameters ); } /** * @inheritDoc */ protected function import(array $row, array $data) { // updating menu items is not supported because all fields that could be modified // would potentially overwrite changes made by the user if (!empty($row)) { return new MenuItem(null, $row); } return parent::import($row, $data); } /** * Returns the show order for a new item that will append it to the current * menu or parent item. * * @param integer $menuID * @param integer $parentItemID * @return integer * @throws \wcf\system\database\DatabaseException */ protected function getItemOrder($menuID, $parentItemID = null) { $sql = "SELECT MAX(showOrder) AS showOrder FROM wcf".WCF_N."_menu_item WHERE " . ($parentItemID === null ? 'menuID' : 'parentItemID') . " = ?"; $statement = WCF::getDB()->prepareStatement($sql, 1); $statement->execute([ ($parentItemID === null ? $menuID : $parentItemID) ]); $row = $statement->fetchSingleRow(); return (!$row['showOrder']) ? 1 : $row['showOrder'] + 1; } }