Apply PSR-12 code style (#3886)
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / devtools / package / DevtoolsPackageXmlWriter.class.php
1 <?php
2
3 namespace wcf\system\devtools\package;
4
5 use wcf\data\devtools\project\DevtoolsProject;
6 use wcf\system\language\LanguageFactory;
7 use wcf\util\XMLWriter;
8
9 /**
10 * Writes the `package.xml` file of a project.
11 *
12 * @author Matthias Schmidt
13 * @copyright 2001-2019 WoltLab GmbH
14 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
15 * @package WoltLabSuite\Core\System\Devtools\Package
16 * @since 5.2
17 */
18 class DevtoolsPackageXmlWriter
19 {
20 /**
21 * data used to write the `package.xml` file
22 * @var array
23 */
24 protected $packageXmlData;
25
26 /**
27 * devtools project whose `package.xml` file will be written
28 * @var DevtoolsProject
29 */
30 protected $project;
31
32 /**
33 * xml writer object
34 * @var XMLWriter
35 */
36 protected $xmlWriter;
37
38 /**
39 * Creates a new `DevtoolsPackageXmlWriter` object.
40 *
41 * @param DevtoolsProject $project
42 * @param array $packageXmlData
43 */
44 public function __construct(DevtoolsProject $project, array $packageXmlData)
45 {
46 $this->project = $project;
47 $this->packageXmlData = $packageXmlData;
48 }
49
50 /**
51 * Returns `true` if the given string needs to be placed in a CDATA
52 * section or `false`, otherwise.
53 *
54 * @param string $string
55 * @return bool
56 */
57 protected function requiresCdata($string)
58 {
59 return \strpos($string, '<') !== false
60 || \strpos($string, '>') !== false
61 || \strpos($string, '&') !== false;
62 }
63
64 /**
65 * Writes the `package.xml` file.
66 */
67 public function write()
68 {
69 $this->xmlWriter = new XMLWriter();
70 $this->xmlWriter->beginDocument(
71 'package',
72 'http://www.woltlab.com',
73 'http://www.woltlab.com/XSD/' . WSC_API_VERSION . '/package.xsd',
74 ['name' => $this->packageXmlData['packageIdentifier']]
75 );
76
77 $this->writePackageInformation();
78 $this->writeAuthorInformation();
79 $this->writeRequiredPackages();
80 $this->writeOptionalPackages();
81 $this->writeExcludedPackages();
82 $this->writeCompatibility();
83 $this->writeInstructions();
84
85 $this->xmlWriter->endDocument($this->project->getPackageXmlPath());
86 }
87
88 /**
89 * Writes the `authorinformation` element.
90 */
91 protected function writeAuthorInformation()
92 {
93 $this->xmlWriter->startElement('authorinformation');
94
95 $this->xmlWriter->writeElement(
96 'author',
97 $this->packageXmlData['author'],
98 [],
99 $this->requiresCdata($this->packageXmlData['author'])
100 );
101 if (isset($this->packageXmlData['authorUrl']) && $this->packageXmlData['authorUrl'] !== '') {
102 $this->xmlWriter->writeElement(
103 'authorurl',
104 $this->packageXmlData['authorUrl'],
105 [],
106 $this->requiresCdata($this->packageXmlData['authorUrl'])
107 );
108 }
109
110 $this->xmlWriter->endElement();
111 }
112
113 /**
114 * Writes the `compatibility` element.
115 */
116 protected function writeCompatibility()
117 {
118 if (empty($this->packageXmlData['apiVersions'])) {
119 return;
120 }
121
122 $this->xmlWriter->startElement('compatibility');
123
124 foreach ($this->packageXmlData['apiVersions'] as $apiVersion) {
125 $this->xmlWriter->writeElement('api', '', ['version' => $apiVersion]);
126 }
127
128 $this->xmlWriter->endElement();
129 }
130
131 /**
132 * Writes the `optionalpackages` element.
133 */
134 protected function writeExcludedPackages()
135 {
136 if (!empty($this->packageXmlData['excludedPackages'])) {
137 $this->xmlWriter->startElement('excludedpackages');
138
139 foreach ($this->packageXmlData['excludedPackages'] as $excludedPackage) {
140 $attributes = [];
141 if (!empty($excludedPackage['version'])) {
142 $attributes['version'] = $excludedPackage['version'];
143 }
144
145 $this->xmlWriter->writeElement(
146 'excludedpackage',
147 $excludedPackage['packageIdentifier'],
148 $attributes,
149 false
150 );
151 }
152
153 $this->xmlWriter->endElement();
154 }
155 }
156
157 /**
158 * Writes the `instructions` elements.
159 */
160 protected function writeInstructions()
161 {
162 if (empty($this->packageXmlData['instructions'])) {
163 return;
164 }
165
166 foreach ($this->packageXmlData['instructions'] as $instructions) {
167 $attributes = ['type' => $instructions['type']];
168 if ($instructions['type'] === 'update') {
169 $attributes['fromversion'] = $instructions['fromVersion'];
170 }
171
172 $this->xmlWriter->startElement('instructions', $attributes);
173
174 foreach ($instructions['instructions'] as $instruction) {
175 $attributes = ['type' => $instruction['pip']];
176 if (!empty($instruction['runStandalone'])) {
177 $attributes['run'] = 'standalone';
178 }
179 if (!empty($instruction['application'])) {
180 $attributes['application'] = $instruction['application'];
181 }
182
183 $this->xmlWriter->writeElement('instruction', $instruction['value'], $attributes, false);
184 }
185
186 $this->xmlWriter->endElement();
187 }
188 }
189
190 /**
191 * Writes the `optionalpackages` element.
192 */
193 protected function writeOptionalPackages()
194 {
195 if (!empty($this->packageXmlData['optionalPackages'])) {
196 $this->xmlWriter->startElement('optionalpackages');
197
198 foreach ($this->packageXmlData['optionalPackages'] as $optionalPackage) {
199 $this->xmlWriter->writeElement(
200 'optionalpackage',
201 $optionalPackage['packageIdentifier'],
202 ['file' => "optionals/{$optionalPackage['packageIdentifier']}.tar"],
203 false
204 );
205 }
206
207 $this->xmlWriter->endElement();
208 }
209 }
210
211 /**
212 * Writes a child of the `packageinformation` element with i18n data.
213 *
214 * @param string $information
215 * @param null|string $elementName is set to lowercase version of `$information` if missing
216 */
217 protected function writeI18nPackageInformation($information, $elementName = null)
218 {
219 if ($elementName === null) {
220 $elementName = \strtolower($information);
221 }
222
223 $english = LanguageFactory::getInstance()->getLanguageByCode('en');
224
225 if (isset($this->packageXmlData[$information . '_i18n'])) {
226 $defaultLanguageID = null;
227 if ($english !== null && isset($this->packageXmlData[$information . '_i18n'][$english->languageID])) {
228 $defaultLanguageID = $english->languageID;
229 } else {
230 \reset($this->packageXmlData[$information . '_i18n']);
231 $defaultLanguageID = \key($this->packageXmlData[$information . '_i18n']);
232 }
233
234 $this->xmlWriter->writeElement(
235 $elementName,
236 $this->packageXmlData[$information . '_i18n'][$defaultLanguageID],
237 [],
238 $this->requiresCdata($this->packageXmlData[$information . '_i18n'][$defaultLanguageID])
239 );
240
241 foreach ($this->packageXmlData[$information . '_i18n'] as $languageID => $informationValue) {
242 if ($languageID !== $defaultLanguageID) {
243 $this->xmlWriter->writeElement(
244 $elementName,
245 $informationValue,
246 ['language' => LanguageFactory::getInstance()->getLanguage($languageID)->languageCode],
247 $this->requiresCdata($informationValue)
248 );
249 }
250 }
251 } else {
252 $this->xmlWriter->writeElement(
253 $elementName,
254 $this->packageXmlData[$information],
255 [],
256 $this->requiresCdata($this->packageXmlData[$information])
257 );
258 }
259 }
260
261 /**
262 * Writes the `packageinformation` element.
263 */
264 protected function writePackageInformation()
265 {
266 $this->xmlWriter->startElement('packageinformation');
267
268 $this->xmlWriter->writeComment(" {$this->packageXmlData['packageIdentifier']} ");
269
270 $this->writeI18nPackageInformation('packageName');
271 $this->writeI18nPackageInformation('packageDescription');
272
273 if (!empty($this->packageXmlData['isApplication'])) {
274 $this->xmlWriter->writeElement(
275 'isapplication',
276 \intval($this->packageXmlData['isApplication']),
277 [],
278 false
279 );
280 }
281 if (!empty($this->packageXmlData['applicationDirectory'])) {
282 $this->xmlWriter->writeElement(
283 'applicationdirectory',
284 $this->packageXmlData['applicationDirectory'],
285 [],
286 false
287 );
288 }
289 $this->xmlWriter->writeElement(
290 'version',
291 $this->packageXmlData['version'],
292 [],
293 false
294 );
295 $this->xmlWriter->writeElement(
296 'date',
297 $this->packageXmlData['date'],
298 [],
299 false
300 );
301 if (!empty($this->packageXmlData['packageUrl'])) {
302 $this->xmlWriter->writeElement(
303 'packageurl',
304 $this->packageXmlData['packageUrl'],
305 [],
306 $this->requiresCdata($this->packageXmlData['packageUrl'])
307 );
308 }
309 $this->writeI18nPackageInformation('license');
310
311 $this->xmlWriter->endElement();
312 }
313
314 /**
315 * Writes the `optionalpackages` element.
316 */
317 protected function writeRequiredPackages()
318 {
319 if (!empty($this->packageXmlData['requiredPackages'])) {
320 $this->xmlWriter->startElement('requiredpackages');
321
322 foreach ($this->packageXmlData['requiredPackages'] as $requiredPackage) {
323 $attributes = [];
324 if (!empty($requiredPackage['minVersion'])) {
325 $attributes['minversion'] = $requiredPackage['minVersion'];
326 }
327 if (!empty($requiredPackage['file'])) {
328 $attributes['file'] = "requirements/{$requiredPackage['packageIdentifier']}.tar";
329 }
330
331 $this->xmlWriter->writeElement(
332 'requiredpackage',
333 $requiredPackage['packageIdentifier'],
334 $attributes,
335 false
336 );
337 }
338
339 $this->xmlWriter->endElement();
340 }
341 }
342 }