Merge branch 'master' into next
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / package / plugin / MenuItemPackageInstallationPlugin.class.php
1 <?php
2 namespace wcf\system\package\plugin;
3 use wcf\data\menu\item\MenuItem;
4 use wcf\data\menu\item\MenuItemEditor;
5 use wcf\system\exception\SystemException;
6 use wcf\system\WCF;
7
8 /**
9 * Installs, updates and deletes menu items.
10 *
11 * @author Alexander Ebert
12 * @copyright 2001-2015 WoltLab GmbH
13 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14 * @package com.woltlab.wcf
15 * @subpackage acp.package.plugin
16 * @category Community Framework
17 * @since 2.2
18 */
19 class MenuItemPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin {
20 /**
21 * @inheritDoc
22 */
23 public $className = MenuItemEditor::class;
24
25 /**
26 * @inheritDoc
27 */
28 public $tagName = 'item';
29
30 /**
31 * @inheritDoc
32 */
33 protected function handleDelete(array $items) {
34 $sql = "DELETE FROM wcf".WCF_N."_menu_item
35 WHERE identifier = ?
36 AND packageID = ?";
37 $statement = WCF::getDB()->prepareStatement($sql);
38
39 WCF::getDB()->beginTransaction();
40 foreach ($items as $item) {
41 $statement->execute([
42 $item['attributes']['identifier'],
43 $this->installation->getPackageID()
44 ]);
45 }
46 WCF::getDB()->commitTransaction();
47 }
48
49 /**
50 * @inheritDoc
51 * @throws SystemException
52 */
53 protected function getElement(\DOMXPath $xpath, array &$elements, \DOMElement $element) {
54 $nodeValue = $element->nodeValue;
55
56 if ($element->tagName === 'title') {
57 if (empty($element->getAttribute('language'))) {
58 throw new SystemException("Missing required attribute 'language' for menu item '" . $element->parentNode->getAttribute('identifier') . "'");
59 }
60
61 // <title> can occur multiple times using the `language` attribute
62 if (!isset($elements['title'])) $elements['title'] = [];
63
64 $elements['title'][$element->getAttribute('language')] = $element->nodeValue;
65 }
66 else {
67 $elements[$element->tagName] = $nodeValue;
68 }
69 }
70
71 /**
72 * @inheritDoc
73 * @throws SystemException
74 */
75 protected function prepareImport(array $data) {
76 $menuID = null;
77 if (!empty($data['elements']['menu'])) {
78 $sql = "SELECT menuID
79 FROM wcf".WCF_N."_menu
80 WHERE identifier = ?";
81 $statement = WCF::getDB()->prepareStatement($sql, 1);
82 $statement->execute([$data['elements']['menu']]);
83 $row = $statement->fetchSingleRow();
84 if ($row === false) {
85 throw new SystemException("Unable to find menu '" . $data['elements']['menu'] . "' for menu item '" . $data['attributes']['identifier'] . "'");
86 }
87
88 $menuID = $row['menuID'];
89 }
90
91 $parentItemID = null;
92 if (!empty($data['elements']['parent'])) {
93 if ($menuID !== null) {
94 throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' can either have an associated menu or a parent menu item, but not both.");
95 }
96
97 $sql = "SELECT *
98 FROM wcf".WCF_N."_menu_item
99 WHERE identifier = ?";
100 $statement = WCF::getDB()->prepareStatement($sql, 1);
101 $statement->execute([$data['elements']['parent']]);
102 $parent = $statement->fetchObject(MenuItem::class);
103 if ($parent === null) {
104 throw new SystemException("Unable to find parent menu item '" . $data['elements']['parent'] . "' for menu item '" . $data['attributes']['identifier'] . "'");
105 }
106
107 $parentItemID = $parent->itemID;
108 $menuID = $parent->menuID;
109 }
110
111 if ($menuID === null && $parentItemID === null) {
112 throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' must either have an associated menu or a parent menu item.");
113 }
114
115 $pageID = null;
116 if (!empty($data['elements']['page'])) {
117 $sql = "SELECT pageID
118 FROM wcf".WCF_N."_page
119 WHERE identifier = ?";
120 $statement = WCF::getDB()->prepareStatement($sql, 1);
121 $statement->execute([$data['elements']['page']]);
122 $row = $statement->fetchSingleRow();
123 if ($row === false) {
124 throw new SystemException("Unable to find page '" . $data['elements']['page'] . "' for menu item '" . $data['attributes']['identifier'] . "'");
125 }
126
127 $pageID = $row['pageID'];
128 }
129
130 $externalURL = (!empty($data['elements']['externalURL'])) ? $data['elements']['externalURL'] : '';
131
132 if ($pageID === null && empty($externalURL)) {
133 throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' must either have an associated page or an external url set.");
134 }
135 else if ($pageID !== null && !empty($externalURL)) {
136 throw new SystemException("The menu item '" . $data['attributes']['identifier'] . "' can either have an associated page or an external url, but not both.");
137 }
138
139 return [
140 'externalURL' => $externalURL,
141 'identifier' => $data['attributes']['identifier'],
142 'menuID' => $menuID,
143 'originIsSystem' => 1,
144 'pageID' => $pageID,
145 'parentItemID' => $parentItemID,
146 'showOrder' => $this->getItemOrder($menuID, $parentItemID),
147 'title' => $this->getI18nValues($data['elements']['title'])
148 ];
149 }
150
151 /**
152 * @inheritDoc
153 */
154 protected function findExistingItem(array $data) {
155 $sql = "SELECT *
156 FROM wcf".WCF_N."_menu_item
157 WHERE identifier = ?
158 AND packageID = ?";
159 $parameters = array(
160 $data['identifier'],
161 $this->installation->getPackageID()
162 );
163
164 return array(
165 'sql' => $sql,
166 'parameters' => $parameters
167 );
168 }
169
170 /**
171 * @inheritDoc
172 */
173 protected function import(array $row, array $data) {
174 // updating menu items is not supported because all fields that could be modified
175 // would potentially overwrite changes made by the user
176 if (!empty($row)) {
177 return new MenuItem(null, $row);
178 }
179
180 return parent::import($row, $data);
181 }
182
183 /**
184 * Returns the show order for a new item that will append it to the current
185 * menu or parent item.
186 *
187 * @param integer $menuID
188 * @param integer $parentItemID
189 * @return integer
190 * @throws \wcf\system\database\DatabaseException
191 */
192 protected function getItemOrder($menuID, $parentItemID = null) {
193 $sql = "SELECT MAX(showOrder) AS showOrder
194 FROM wcf".WCF_N."_menu_item
195 WHERE " . ($parentItemID === null ? 'menuID' : 'parentItemID') . " = ?";
196 $statement = WCF::getDB()->prepareStatement($sql, 1);
197 $statement->execute([
198 ($parentItemID === null ? $menuID : $parentItemID)
199 ]);
200
201 $row = $statement->fetchSingleRow();
202
203 return (!$row['showOrder']) ? 1 : $row['showOrder'] + 1;
204 }
205 }