1ed2ff7d8a45e7da2db1c5dcb3da9aa71ceca5dc
[GitHub/WoltLab/WCF.git] /
1 <?php
2 declare(strict_types=1);
3 namespace wcf\system\package\plugin;
4 use wcf\data\acp\search\provider\ACPSearchProviderEditor;
5 use wcf\data\acp\search\provider\ACPSearchProviderList;
6 use wcf\system\cache\builder\ACPSearchProviderCacheBuilder;
7 use wcf\system\devtools\pip\DevtoolsPipEntryList;
8 use wcf\system\devtools\pip\IDevtoolsPipEntryList;
9 use wcf\system\devtools\pip\IGuiPackageInstallationPlugin;
10 use wcf\system\devtools\pip\TXmlGuiPackageInstallationPlugin;
11 use wcf\system\form\builder\container\FormContainer;
12 use wcf\system\form\builder\field\validation\FormFieldValidationError;
13 use wcf\system\form\builder\field\validation\FormFieldValidator;
14 use wcf\system\form\builder\field\ClassNameFormField;
15 use wcf\system\form\builder\field\IntegerFormField;
16 use wcf\system\form\builder\field\TextFormField;
17 use wcf\system\form\builder\IFormDocument;
18 use wcf\system\search\acp\IACPSearchResultProvider;
19 use wcf\system\WCF;
20
21 /**
22 * Installs, updates and deletes ACP search providers.
23 *
24 * @author Alexander Ebert
25 * @copyright 2001-2018 WoltLab GmbH
26 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
27 * @package WoltLabSuite\Core\System\Package\Plugin
28 */
29 class ACPSearchProviderPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin implements IGuiPackageInstallationPlugin {
30 use TXmlGuiPackageInstallationPlugin;
31
32 /**
33 * @inheritDoc
34 */
35 public $className = ACPSearchProviderEditor::class;
36
37 /**
38 * @inheritDoc
39 */
40 protected function handleDelete(array $items) {
41 $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
42 WHERE providerName = ?
43 AND packageID = ?";
44 $statement = WCF::getDB()->prepareStatement($sql);
45
46 WCF::getDB()->beginTransaction();
47 foreach ($items as $item) {
48 $statement->execute([
49 $item['attributes']['name'],
50 $this->installation->getPackageID()
51 ]);
52 }
53 WCF::getDB()->commitTransaction();
54 }
55
56 /**
57 * @inheritDoc
58 */
59 protected function prepareImport(array $data) {
60 // get show order
61 $showOrder = isset($data['elements']['showorder']) ? $data['elements']['showorder'] : null;
62 $showOrder = $this->getShowOrder($showOrder);
63
64 return [
65 'className' => $data['elements']['classname'],
66 'providerName' => $data['attributes']['name'],
67 'showOrder' => $showOrder
68 ];
69 }
70
71 /**
72 * @inheritDoc
73 */
74 protected function findExistingItem(array $data) {
75 $sql = "SELECT *
76 FROM wcf".WCF_N."_".$this->tableName."
77 WHERE providerName = ?
78 AND packageID = ?";
79 $parameters = [
80 $data['providerName'],
81 $this->installation->getPackageID()
82 ];
83
84 return [
85 'sql' => $sql,
86 'parameters' => $parameters
87 ];
88 }
89
90 /**
91 * @inheritDoc
92 */
93 protected function cleanup() {
94 ACPSearchProviderCacheBuilder::getInstance()->reset();
95 }
96
97 /**
98 * @see \wcf\system\package\plugin\IPackageInstallationPlugin::getDefaultFilename()
99 * @since 3.0
100 */
101 public static function getDefaultFilename() {
102 return 'acpSearchProvider.xml';
103 }
104
105 /**
106 * @inheritDoc
107 * @since 3.1
108 */
109 public static function getSyncDependencies() {
110 return [];
111 }
112
113 /**
114 * @inheritDoc
115 * @since 3.2
116 */
117 protected function getElementData(\DOMElement $element, bool $saveData = false): array {
118 $data = [
119 'className' => $element->getElementsByTagName('classname')->item(0)->nodeValue,
120 'packageID' => $this->installation->getPackage()->packageID,
121 'providerName' => $element->getAttribute('name')
122 ];
123
124 $showOrder = $element->getElementsByTagName('showorder')->item(0);
125 if ($showOrder) {
126 $data['showOrder'] = $showOrder->nodeValue;
127 }
128
129 return $data;
130 }
131
132 /**
133 * @inheritDoc
134 * @since 3.2
135 */
136 public function getElementIdentifier(\DOMElement $element): string {
137 return $element->getAttribute('name');
138 }
139
140 /**
141 * @inheritDoc
142 * @since 3.2
143 */
144 public function addFormFields(IFormDocument $form) {
145 /** @var FormContainer $dataContainer */
146 $dataContainer = $form->getNodeById('data');
147
148 $dataContainer->appendChildren([
149 TextFormField::create('providerName')
150 ->objectProperty('name')
151 ->label('wcf.acp.pip.acpSearchProvider.providerName')
152 ->description('wcf.acp.pip.acpSearchProvider.providerName.description', ['project' => $this->installation->getProject()])
153 ->required()
154 ->addValidator(ObjectTypePackageInstallationPlugin::getObjectTypeAlikeValueValidator('wcf.acp.pip.acpSearchProvider.providerName'))
155 ->addValidator(new FormFieldValidator('uniqueness', function(TextFormField $formField) {
156 if (
157 $formField->getDocument()->getFormMode() === IFormDocument::FORM_MODE_CREATE ||
158 $this->editedEntry->getAttribute('name') !== $formField->getValue()
159 ) {
160 $providerList = new ACPSearchProviderList();
161 $providerList->getConditionBuilder()->add('providerName <> ?', [$formField->getValue()]);
162
163 if ($providerList->countObjects() > 0) {
164 $formField->addValidationError(
165 new FormFieldValidationError(
166 'notUnique',
167 'wcf.acp.pip.acpSearchProvider.providerName.error.notUnique'
168 )
169 );
170 }
171 }
172 })),
173
174 ClassNameFormField::create('className')
175 ->objectProperty('classname')
176 ->required()
177 ->implementedInterface(IACPSearchResultProvider::class),
178
179 IntegerFormField::create('showOrder')
180 ->objectProperty('showorder')
181 ->label('wcf.acp.pip.acpSearchProvider.showOrder')
182 ->description('wcf.acp.pip.acpSearchProvider.showOrder.description')
183 ->nullable()
184 ->minimum(1),
185 ]);
186 }
187
188 /**
189 * @inheritDoc
190 * @since 3.2
191 */
192 protected function setEntryListKeys(IDevtoolsPipEntryList $entryList) {
193 $entryList->setKeys([
194 'providerName' => 'wcf.acp.pip.acpSearchProvider.providerName',
195 'className' => 'wcf.form.field.className'
196 ]);
197 }
198
199 /**
200 * @inheritDoc
201 * @since 3.2
202 */
203 protected function sortDocument(\DOMDocument $document) {
204 $this->sortImportDelete($document);
205
206 $this->sortChildNodes($document->getElementsByTagName('import'), function(\DOMElement $element1, \DOMElement $element2) {
207 $showOrder1 = PHP_INT_MAX;
208 if ($element1->getElementsByTagName('showorder')->length === 1) {
209 $showOrder1 = $element1->getElementsByTagName('showorder')->item(0)->nodeValue;
210 }
211
212 $showOrder2 = PHP_INT_MAX;
213 if ($element2->getElementsByTagName('showorder')->length === 1) {
214 $showOrder2 = $element2->getElementsByTagName('showorder')->item(0)->nodeValue;
215 }
216
217 if ($showOrder1 !== $showOrder2) {
218 return $showOrder1 > $showOrder2;
219 }
220
221 return strcmp(
222 $element1->getAttribute('name'),
223 $element2->getAttribute('name')
224 );
225 });
226 $this->sortChildNodes($document->getElementsByTagName('delete'), function(\DOMElement $element1, \DOMElement $element2) {
227 return strcmp(
228 $element1->getAttribute('name'),
229 $element2->getAttribute('name')
230 );
231 });
232 }
233
234 /**
235 * @inheritDoc
236 * @since 3.2
237 */
238 protected function writeEntry(\DOMDocument $document, IFormDocument $form): \DOMElement {
239 $acpSearchProvider = $document->createElement('acpsearchprovider');
240 $acpSearchProvider->setAttribute('name', $form->getNodeById('providerName')->getSaveValue());
241 $acpSearchProvider->appendChild($document->createElement('classname', $form->getNodeById('className')->getSaveValue()));
242
243 /** @var IntegerFormField $showOrder */
244 $showOrder = $form->getNodeById('showOrder');
245 if ($showOrder->getSaveValue()) {
246 $acpSearchProvider->appendChild($document->createElement('showorder', (string) $showOrder->getSaveValue()));
247 }
248
249 $document->getElementsByTagName('import')->item(0)->appendChild($acpSearchProvider);
250
251 return $acpSearchProvider;
252 }
253 }