PackageImport::importEvents()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 4
1
<?php
2
/* +**********************************************************************************
3
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
4
 * ("License"); You may not use this file except in compliance with the License
5
 * The Original Code is:  vtiger CRM Open Source
6
 * The Initial Developer of the Original Code is vtiger.
7
 * Portions created by vtiger are Copyright (C) vtiger.
8
 * All Rights Reserved.
9
 * Contributor(s): YetiForce S.A.
10
 * ********************************************************************************** */
11
12
namespace vtlib;
13
14
/**
15
 * Provides API to import module into vtiger CRM.
16
 */
17
class PackageImport extends PackageExport
18
{
19
	/**
20
	 * Module Meta XML File (Parsed).
21
	 */
22
	public $_modulexml;
23
24
	/**
25
	 * Module Fields mapped by [modulename][fieldname] which
26
	 * will be used to create customviews.
27
	 */
28
	public $_modulefields_cache = [];
29
30
	/**
31
	 * License of the package.
32
	 */
33
	public $_licensetext = false;
34
	public $_errorText = '';
35
	public $packageType = '';
36
	public $parameters = [];
37
38
	/**
39
	 * Parse the manifest file.
40
	 *
41
	 * @param \App\Zip $zip
42
	 */
43 5
	public function __parseManifestFile(\App\Zip $zip)
44
	{
45 5
		if ($content = $zip->getFromName('manifest.xml')) {
46 5
			$this->_modulexml = simplexml_load_string($content);
47
			return true;
48
		}
49
		return false;
50
	}
51
52
	/**
53 5
	 * Get type of package (as specified in manifest).
54
	 *
55 5
	 * @return false|string
56 5
	 */
57
	public function type()
58
	{
59
		if (!empty($this->_modulexml) && !empty($this->_modulexml->type)) {
60
			return (string) $this->_modulexml->type;
61
		}
62
		return false;
63
	}
64 1
65
	/**
66 1
	 * Get type of package (as specified in manifest).
67 1
	 */
68 1
	public function getTypeName()
69 1
	{
70
		if (!empty($this->_modulexml) && !empty($this->_modulexml->type)) {
71
			$type = strtolower($this->_modulexml->type);
72 1
			switch ($type) {
73
				case 'extension':
74
					$type = 'LBL_EXTENSION_MODULE';
75 1
					break;
76 1
				case 'entity':
77 1
					$type = 'LBL_BASE_MODULE';
78
					break;
79
				case 'inventory':
80
					$type = 'LBL_INVENTORY_MODULE';
81
					break;
82
				case 'language':
83
					$type = 'LBL_LANGUAGE_MODULE';
84
					break;
85 1
				default:
86
					break;
87
			}
88
89
			return $type;
90
		}
91
		return '';
92
	}
93
94
	/**
95
	 * XPath evaluation on the root module node.
96
	 *
97
	 * @param string Path expression
0 ignored issues
show
Bug introduced by
The type vtlib\Path was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
98
	 * @param mixed $path
99
	 */
100
	public function xpath($path)
101
	{
102
		return $this->_modulexml->xpath($path);
103 5
	}
104
105 5
	/**
106
	 * Are we trying to import language package?
107
	 *
108 5
	 * @param mixed|null $zipfile
109 5
	 */
110 5
	public function isLanguageType($zipfile = null)
111 5
	{
112 1
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
113
			return false;
114
		}
115 4
		$packagetype = $this->type();
116 4
		if ($packagetype) {
117 4
			$lcasetype = strtolower($packagetype);
118
			if ('language' === $lcasetype) {
119
				return true;
120
			}
121 4
		}
122
		if ($packagetype) {
123
			$lcasetype = strtolower($packagetype);
124
			if ('layout' === $lcasetype) {
125
				return true;
126
			}
127 4
		}
128
		return false;
129 4
	}
130
131
	/**
132 4
	 * Are we trying to import extension package?
133 4
	 *
134 4
	 * @param mixed|null $zipfile
135 4
	 */
136 1
	public function isExtensionType($zipfile = null)
137
	{
138
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
139 3
			return false;
140
		}
141
		$packagetype = $this->type();
142
		if ($packagetype) {
143
			$lcasetype = strtolower($packagetype);
144
			if ('extension' === $lcasetype) {
145
				return true;
146
			}
147
		}
148
		return false;
149 3
	}
150
151 3
	/**
152
	 * Checks font package type.
153
	 *
154 3
	 * @param null $zipfile
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $zipfile is correct as it would always require null to be passed?
Loading history...
155 3
	 *
156 3
	 * @return bool
157 3
	 */
158
	public function isFontType($zipfile = null)
159
	{
160
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
161 3
			return false;
162
		}
163
		$packagetype = $this->type();
164 3
		if ($packagetype) {
165
			$lcasetype = strtolower($packagetype);
166 3
			if ('font' === $lcasetype) {
167
				return true;
168
			}
169 3
		}
170
		return false;
171 3
	}
172 3
173 3
	public function isUpdateType($zipfile = null)
174
	{
175
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
176
			return false;
177 3
		}
178
		$packagetype = $this->type();
179
180
		if ($packagetype) {
181
			$lcasetype = strtolower($packagetype);
182
			if ('update' === $lcasetype) {
183 4
				return true;
184
			}
185 4
		}
186
		return false;
187
	}
188 4
189
	/**
190 4
	 * Are we trying to import language package?
191 4
	 *
192 4
	 * @param mixed|null $zipfile
193
	 */
194
	public function isLayoutType($zipfile = null)
195
	{
196 4
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
197
			return false;
198
		}
199
		$packagetype = $this->type();
200
201
		if ($packagetype) {
202
			$lcasetype = strtolower($packagetype);
203
			if ('layout' === $lcasetype) {
204
				return true;
205
			}
206 1
		}
207
		return false;
208
	}
209 1
210
	/**
211
	 * checks whether a package is module bundle or not.
212 1
	 *
213
	 * @param string $zipfile - path to the zip file
214
	 *
215
	 * @return bool - true if given zipfile is a module bundle and false otherwise
216
	 */
217
	public function isModuleBundle($zipfile = null)
218
	{
219
		// If data is not yet available
220
		if (!empty($zipfile) && !$this->checkZip($zipfile)) {
221
			return false;
222
		}
223
		return (bool) $this->_modulexml->modulebundle;
224
	}
225
226
	/**
227
	 * @return array module list available in the module bundle
228
	 */
229
	public function getAvailableModuleInfoFromModuleBundle()
230
	{
231
		$list = (array) $this->_modulexml->modulelist;
232
233
		return (array) $list['dependent_module'];
234
	}
235
236
	/**
237
	 * Get the license of this package
238
	 * NOTE: checkzip should have been called earlier.
239
	 */
240
	public function getLicense()
241
	{
242
		return $this->_licensetext;
243
	}
244
245
	public function getParameters()
246
	{
247
		$params = [];
248
		if (empty($this->_modulexml->parameters)) {
249
			return $params;
250
		}
251
		foreach ($this->_modulexml->parameters->parameter as $parameter) {
252
			$params[] = $parameter;
253
		}
254
		return $params;
255
	}
256
257
	public function initParameters(\App\Request $request)
258
	{
259
		$data = [];
260
		foreach ($request->getAll() as $name => $value) {
261 5
			if (false !== strpos($name, 'param_')) {
262
				$name = str_replace('param_', '', $name);
263 5
				$data[$name] = $value;
264 5
			}
265 5
		}
266 5
		$this->parameters = $data;
267 5
	}
268 5
269 5
	/**
270 5
	 * Check if zipfile is a valid package.
271 5
	 *
272 5
	 * @param mixed $zipfile
273 5
	 */
274 5
	public function checkZip($zipfile)
275 5
	{
276 5
		$manifestFound = $languagefile_found = $layoutfile_found = $updatefile_found = $extensionfile_found = $moduleVersionFound = $fontfile_found = false;
277
		$moduleName = null;
278
		$zip = \App\Zip::openFile($zipfile, ['checkFiles' => false]);
279
		if ($this->__parseManifestFile($zip)) {
280
			$manifestFound = true;
281 5
			$moduleName = (string) $this->_modulexml->name;
282 1
			$isModuleBundle = (string) $this->_modulexml->modulebundle;
283 1
			if ('true' === $isModuleBundle && (!empty($this->_modulexml))
284 4
					&& (!empty($this->_modulexml->dependencies))
285
					&& (!empty($this->_modulexml->dependencies->vtiger_version))) {
286
				$languagefile_found = true;
287 4
			}
288 1
			// Do we need to check the zip further?
289 1
			if ($this->isLanguageType()) {
290 3
				$languagefile_found = true; // No need to search for module language file.
291
			}
292
			if ($this->isLayoutType()) {
293 3
				$layoutfile_found = true; // No need to search for module language file.
294
			}
295
			if ($this->isExtensionType()) {
296
				$extensionfile_found = true; // No need to search for module language file.
297 3
			}
298
			if ($this->isUpdateType()) {
299
				$updatefile_found = true; // No need to search for module language file.
300 4
			}
301 4
			if ($this->isFontType()) {
302 4
				$fontfile_found = true; // No need to search for module language file.
303 3
			}
304
		}
305 4
		for ($i = 0; $i < $zip->numFiles; ++$i) {
306 4
			$fileName = $zip->getNameIndex($i);
307 4
			$matches = [];
308 1
			$pattern = '/languages[\/\\\]' . \App\Config::main('default_language') . '[\/\\\]([^\/]+)\.json/';
309
			preg_match($pattern, $fileName, $matches);
310
			if (\count($matches) && \in_array($moduleName, $matches)) {
311
				$languagefile_found = true;
312 5
			}
313 4
			$settingsPattern = '/languages[\/\\\]' . \App\Config::main('default_language') . '[\/\\\]Settings[\/\\\]([^\/]+)\.json/';
314 1
			preg_match($settingsPattern, $fileName, $matches);
315
			if (\count($matches) && \in_array($moduleName, $matches)) {
316
				$languagefile_found = true;
317
			}
318
		}
319 5
		// Verify module language file.
320 5
		if (!$fontfile_found && !$updatefile_found && !$layoutfile_found && !$languagefile_found) {
321 5
			$errorText = \App\Language::translate('LBL_ERROR_NO_DEFAULT_LANGUAGE', 'Settings:ModuleManager');
322 5
			$errorText = str_replace('__DEFAULTLANGUAGE__', \App\Config::main('default_language'), $errorText);
323 5
			$this->_errorText = $errorText;
324 5
		}
325 5
		if (!empty($this->_modulexml)
326
			&& !empty($this->_modulexml->dependencies)
327
			&& !empty($this->_modulexml->dependencies->vtiger_version)) {
328
			$moduleVersion = (string) $this->_modulexml->dependencies->vtiger_version;
329
			$versionCheck = \App\Version::compare(\App\Version::get(), $moduleVersion);
330
			if (false !== $versionCheck && $versionCheck >= 0) {
331
				$moduleVersionFound = true;
332
			} else {
333 5
				$errorText = \App\Language::translate('LBL_ERROR_VERSION', 'Settings:ModuleManager');
334 5
				$errorText = str_replace('__MODULEVERSION__', $moduleVersion, $errorText);
335 5
				$errorText = str_replace('__CRMVERSION__', \App\Version::get(), $errorText);
336
				$this->_errorText = $errorText;
337 5
			}
338
		}
339
		$validzip = false;
340 5
		if ($manifestFound) {
341 1
			if ($languagefile_found && $moduleVersionFound) {
342
				$validzip = true;
343 5
			}
344
			if ($layoutfile_found && $moduleVersionFound) {
345
				$validzip = true;
346 5
			}
347
			if ($extensionfile_found && $moduleVersionFound) {
348
				$validzip = true;
349 5
			}
350
			if ($updatefile_found && $moduleVersionFound) {
351
				$validzip = true;
352
			}
353 5
			if ($fontfile_found) {
354
				$validzip = true;
355
			}
356
			if ($this->isLanguageType() && false !== strpos($this->_modulexml->prefix, '/')) {
357 5
				$validzip = false;
358 1
				$this->_errorText = \App\Language::translate('LBL_ERROR_NO_VALID_PREFIX', 'Settings:ModuleManager');
359
			}
360 1
			if (!empty($moduleName) && !empty($this->_modulexml->type) && \Settings_ModuleManager_Module_Model::checkModuleName($moduleName) && \in_array(strtolower($this->_modulexml->type), ['entity', 'inventory', 'extension'])) {
361
				$validzip = false;
362
				$this->_errorText = \App\Language::translate('LBL_INVALID_MODULE_NAME', 'Settings:ModuleManager');
363
			}
364
		}
365
		if ($validzip && !empty($this->_modulexml->license)) {
366
			if (!empty($this->_modulexml->license->inline)) {
367
				$this->_licensetext = (string) $this->_modulexml->license->inline;
368
			} elseif (!empty($this->_modulexml->license->file)) {
369 5
				$licensefile = (string) $this->_modulexml->license->file;
370 5
				if ($licenseContent = $zip->getFromName($licensefile)) {
371
					$this->_licensetext = $licenseContent;
372 5
				} else {
373
					$this->_licensetext = "Missing $licensefile!";
374
				}
375
			}
376
		}
377
		if ($zip) {
0 ignored issues
show
introduced by
$zip is of type App\Zip, thus it always evaluated to true.
Loading history...
378 5
			$zip->close();
379
		}
380 5
		return $validzip;
381
	}
382
383 5
	/**
384
	 * Get module name packaged in the zip file.
385
	 *
386
	 * @param mixed $zipfile
387
	 */
388
	public function getModuleNameFromZip($zipfile)
389
	{
390
		if (!$this->checkZip($zipfile)) {
391
			return null;
392
		}
393
		return (string) $this->_modulexml->name;
394
	}
395
396
	/**
397
	 * returns the name of the module.
398
	 *
399 1
	 * @return string - name of the module as given in manifest file
400
	 */
401 1
	public function getModuleName()
402 1
	{
403
		return (string) $this->_modulexml->name;
404
	}
405
406
	/**
407
	 * Cache the field instance for re-use.
408
	 *
409
	 * @param mixed $moduleInstance
410
	 * @param mixed $fieldname
411
	 * @param mixed $fieldInstance
412
	 */
413
	public function __AddModuleFieldToCache($moduleInstance, $fieldname, $fieldInstance)
414
	{
415 2
		$this->_modulefields_cache["$moduleInstance->name"]["$fieldname"] = $fieldInstance;
416
	}
417 2
418 2
	/**
419 2
	 * Get field instance from cache.
420 2
	 *
421 2
	 * @param mixed $moduleInstance
422
	 * @param mixed $fieldname
423
	 */
424 2
	public function __GetModuleFieldFromCache($moduleInstance, $fieldname)
425
	{
426 2
		return $this->_modulefields_cache["$moduleInstance->name"]["$fieldname"];
427 2
	}
428
429 2
	/**
430
	 * Initialize Import.
431 2
	 *
432
	 * @param mixed $zipfile
433 2
	 * @param mixed $overwrite
434
	 */
435 2
	public function initImport($zipfile, $overwrite = true)
0 ignored issues
show
Unused Code introduced by
The parameter $overwrite is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

435
	public function initImport($zipfile, /** @scrutinizer ignore-unused */ $overwrite = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
436
	{
437 2
		$module = $this->getModuleNameFromZip($zipfile);
438 2
		if (null !== $module) {
439
			$defaultLayout = \Vtiger_Viewer::getDefaultLayoutName();
440 2
			$zip = \App\Zip::openFile($zipfile, ['checkFiles' => false]);
441 2
			if ($zip->statName("$module.png")) {
442 2
				$zip->unzipFile("$module.png", "layouts/$defaultLayout/images/$module.png");
443 2
			}
444
			$zip->unzip([
445
				// Templates folder
446 2
				'templates' => "layouts/$defaultLayout/modules/$module",
447
				'public_resources' => "public_html/layouts/$defaultLayout/modules/$module/resources",
448
				// Cron folder
449
				'cron' => "cron/modules/$module",
450
				// Config
451
				'config' => 'config/Modules',
452
				// Modules folder
453
				'modules' => 'modules',
454
				// Settings folder
455
				'settings/modules' => "modules/Settings/$module",
456
				// Settings templates folder
457
				'settings/templates' => "layouts/$defaultLayout/modules/Settings/$module",
458
				'settings/public_resources' => "public_html/layouts/$defaultLayout/modules/Settings/$module/resources",
459 1
				//module images
460
				'images' => "layouts/$defaultLayout/images/$module",
461 1
				'updates' => 'cache/updates',
462
				'layouts' => 'layouts',
463
				'languages' => 'languages',
464
			]);
465
		}
466
		return $module;
467
	}
468
469
	public function getTemporaryFilePath($filepath = false)
470
	{
471
		return 'cache/' . $filepath;
472
	}
473
474
	/**
475
	 * Get dependent version.
476
	 *
477
	 * @return string
478
	 */
479
	public function getDependentVtigerVersion(): string
480
	{
481
		return $this->_modulexml->dependencies->vtiger_version ?? '';
482
	}
483
484
	/**
485
	 * Get dependent Maximum version.
486
	 */
487
	public function getDependentMaxVtigerVersion()
488
	{
489
		return $this->_modulexml->dependencies->vtiger_max_version;
490
	}
491
492
	/**
493
	 * Get package version.
494
	 */
495
	public function getVersion()
496
	{
497
		return $this->_modulexml->version;
498
	}
499
500
	/**
501
	 * Get package author name.
502
	 */
503
	public function getAuthorName()
504
	{
505
		return $this->_modulexml->authorname;
506
	}
507
508
	/**
509
	 * Get package author phone number.
510
	 */
511
	public function getAuthorPhone()
512
	{
513
		return $this->_modulexml->authorphone;
514
	}
515
516
	/**
517 3
	 * Get package author phone email.
518
	 */
519 3
	public function getAuthorEmail()
520
	{
521
		return $this->_modulexml->authoremail;
522
	}
523
524
	/**
525
	 * Get package author phone email.
526
	 */
527
	public function getDescription()
528
	{
529
		return $this->_modulexml->description;
530
	}
531
532
	/**
533
	 * Get premium.
534
	 *
535
	 * @return int
536 2
	 */
537
	public function getPremium(): int
538 2
	{
539 2
		return (int) $this->_modulexml->premium;
540 2
	}
541
542 2
	public function getUpdateInfo()
543
	{
544
		return [
545 2
			'from' => $this->_modulexml->from_version,
546 2
			'to' => $this->_modulexml->to_version,
547 2
		];
548 2
	}
549
550
	/**
551
	 * Import Module from zip file.
552
	 *
553
	 * @param string Zip file name
0 ignored issues
show
Bug introduced by
The type vtlib\Zip was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
554
	 * @param bool True for overwriting existing module
555
	 * @param mixed $zipfile
556
	 * @param mixed $overwrite
557
	 */
558
	public function import($zipfile, $overwrite = false)
559
	{
560
		$module = $this->getModuleNameFromZip($zipfile);
561
		if (null !== $module) {
562
			$zip = \App\Zip::openFile($zipfile, ['checkFiles' => false]);
563
			// If data is not yet available
564
			if (empty($this->_modulexml)) {
565
				$this->__parseManifestFile($zip);
566
			}
567 2
			$buildModuleArray = [];
568 2
			$installSequenceArray = [];
569
			$moduleBundle = (bool) $this->_modulexml->modulebundle;
570
			if (true === $moduleBundle) {
571
				$moduleList = (array) $this->_modulexml->modulelist;
572
				foreach ($moduleList as $moduleInfos) {
573
					foreach ($moduleInfos as $moduleInfo) {
574 2
						$moduleInfo = (array) $moduleInfo;
575
						$buildModuleArray[] = $moduleInfo;
576
						$installSequenceArray[] = $moduleInfo['install_sequence'];
577
					}
578 2
				}
579
				sort($installSequenceArray);
580 2
				$zip->unzip($this->getTemporaryFilePath());
581 2
				foreach ($installSequenceArray as $sequence) {
582
					foreach ($buildModuleArray as $moduleInfo) {
583
						if ($moduleInfo['install_sequence'] == $sequence) {
584
							$this->import($this->getTemporaryFilePath($moduleInfo['filepath']), $overwrite);
585 2
						}
586
					}
587
				}
588
			} else {
589
				$this->packageType = strtolower($this->_modulexml->type);
590 2
				switch ((string) $this->_modulexml->type) {
591
					case 'update':
592 2
						Functions::recurseDelete('cache/updates');
593 2
						$zip = \App\Zip::openFile($zipfile, ['checkFiles' => false]);
594 2
						$zip->extract('cache/updates');
595
						$this->importUpdate();
596 2
						break;
597 2
					case 'font':
598 2
						$this->importFont($zipfile);
599 2
						break;
600 2
					default:
601 1
						$this->initImport($zipfile, $overwrite);
602
						// Call module import function
603 2
						$this->importModule();
604 1
						break;
605
				}
606
			}
607
		}
608 2
		return $module;
609 2
	}
610
611 2
	/**
612 2
	 * Import Module.
613 2
	 */
614 2
	public function importModule()
615 2
	{
616 2
		$moduleName = (string) $this->_modulexml->name;
617 2
		$tabLabel = $this->_modulexml->label;
618 2
		$tabVersion = $this->_modulexml->version;
619 2
		$isextension = false;
620
		$moduleType = 0;
621 2
		if (!empty($this->_modulexml->type)) {
622 2
			$this->packageType = strtolower($this->_modulexml->type);
623 2
			if ('extension' == $this->packageType || 'language' == $this->packageType) {
624
				$isextension = true;
625 2
			}
626 2
			if ('inventory' == $this->packageType) {
627 2
				$moduleType = 1;
628 2
			}
629 2
		}
630 2
631 2
		$vtigerMinVersion = $this->_modulexml->dependencies->vtiger_version;
632 2
		$vtigerMaxVersion = $this->_modulexml->dependencies->vtiger_max_version;
633 2
634 2
		$moduleInstance = new Module();
635 2
		$moduleInstance->name = $moduleName;
636
		$moduleInstance->label = $tabLabel;
637
		$moduleInstance->isentitytype = (true !== $isextension);
638
		$moduleInstance->version = (!$tabVersion) ? 0 : $tabVersion;
639 2
		$moduleInstance->minversion = (!$vtigerMinVersion) ? false : $vtigerMinVersion;
640 2
		$moduleInstance->maxversion = (!$vtigerMaxVersion) ? false : $vtigerMaxVersion;
641
		$moduleInstance->type = $moduleType;
642
		$moduleInstance->premium = $this->getPremium();
643
644
		$moduleInstance->save();
645 2
		$moduleInstance->initWebservice();
646
		$this->moduleInstance = $moduleInstance;
647 2
648
		$this->importTables($this->_modulexml);
649
		$this->importBlocks($this->_modulexml, $moduleInstance);
650 2
		$this->importInventory();
651 2
		$this->importCustomViews($this->_modulexml, $moduleInstance);
652
		$this->importSharingAccess($this->_modulexml, $moduleInstance);
653
		$this->importEvents($this->_modulexml, $moduleInstance);
654 2
		$this->importActions($this->_modulexml, $moduleInstance);
655 2
		$this->importRelatedLists($this->_modulexml, $moduleInstance);
656 2
		$this->importCustomLinks($this->_modulexml, $moduleInstance);
657
		$this->importCronTasks($this->_modulexml);
658 2
		Module::fireEvent($moduleInstance->name, Module::EVENT_MODULE_POSTINSTALL);
659 2
		register_shutdown_function(function () {
660 2
			try {
661 2
				chdir(ROOT_DIRECTORY);
662 2
				(new \App\BatchMethod(['method' => '\App\UserPrivilegesFile::recalculateAll', 'params' => []]))->save();
663
			} catch (\Throwable $e) {
664
				\App\Log::error($e->getMessage() . PHP_EOL . $e->__toString());
665
				throw $e;
666
			}
667
		});
668
	}
669
670
	/**
671
	 * Import Tables of the module.
672
	 *
673
	 * @param mixed $modulenode
674 2
	 */
675 2
	public function importTables($modulenode)
676
	{
677
		if (empty($modulenode->tables) || empty($modulenode->tables->table)) {
678
			return;
679
		}
680 2
		$db = \App\Db::getInstance();
681
		$db->createCommand()->checkIntegrity(false)->execute();
682 2
683 1
		// Import the table via queries
684
		foreach ($modulenode->tables->table as $tablenode) {
685 1
			$tableName = $tablenode->name;
686 1
			$sql = (string) $tablenode->sql; // Convert to string format
687 1
			// Avoid executing SQL that will DELETE or DROP table data
688
			if (Utils::isCreateSql($sql)) {
689 1
				if (!Utils::checkTable($tableName)) {
690
					\App\Log::trace("SQL: $sql ... ", __METHOD__);
691
					$db->createCommand($sql)->execute();
692
					\App\Log::trace('DONE', __METHOD__);
693
				}
694 1
			} else {
695
				if (Utils::isDestructiveSql($sql)) {
696 1
					\App\Log::trace("SQL: $sql ... SKIPPED", __METHOD__);
697 1
				} else {
698 1
					\App\Log::trace("SQL: $sql ... ", __METHOD__);
699 1
					$db->createCommand($sql)->execute();
700 1
					\App\Log::trace('DONE', __METHOD__);
701 1
				}
702
			}
703
		}
704 1
		$db->createCommand()->checkIntegrity(true)->execute();
705 1
	}
706 1
707 1
	/**
708 1
	 * Import Blocks of the module.
709 1
	 *
710 1
	 * @param mixed $modulenode
711 1
	 * @param mixed $moduleInstance
712
	 */
713
	public function importBlocks($modulenode, $moduleInstance)
714
	{
715 1
		if (empty($modulenode->blocks) || empty($modulenode->blocks->block)) {
716
			return;
717 1
		}
718
		foreach ($modulenode->blocks->block as $blocknode) {
719
			$blockInstance = $this->importBlock($modulenode, $moduleInstance, $blocknode);
720
			$this->importFields($blocknode, $blockInstance, $moduleInstance);
721
		}
722
	}
723 1
724
	/**
725 1
	 * Import Block of the module.
726
	 *
727
	 * @param mixed $modulenode
728
	 * @param mixed $moduleInstance
729 1
	 * @param mixed $blocknode
730 1
	 */
731
	public function importBlock($modulenode, $moduleInstance, $blocknode)
0 ignored issues
show
Unused Code introduced by
The parameter $modulenode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

731
	public function importBlock(/** @scrutinizer ignore-unused */ $modulenode, $moduleInstance, $blocknode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
732 1
	{
733
		$blocklabel = $blocknode->blocklabel;
734
		$blockInstance = new Block();
735
		$blockInstance->label = $blocklabel;
736
		if (isset($blocknode->sequence, $blocknode->display_status)) {
737 1
			$blockInstance->sequence = (string) ($blocknode->sequence);
738
			if ($blockInstance->sequence = '') {
739 1
				$blockInstance->sequence = null;
740 1
			}
741 1
			$blockInstance->showtitle = (string) ($blocknode->show_title);
742 1
			$blockInstance->visible = (string) ($blocknode->visible);
743 1
			$blockInstance->increateview = (string) ($blocknode->create_view);
744 1
			$blockInstance->ineditview = (string) ($blocknode->edit_view);
745 1
			$blockInstance->indetailview = (string) ($blocknode->detail_view);
746 1
			$blockInstance->display_status = (string) ($blocknode->display_status);
747 1
			$blockInstance->iscustom = (string) ($blocknode->iscustom);
748 1
			$blockInstance->islist = (string) ($blocknode->islist);
0 ignored issues
show
Bug introduced by
The property islist does not seem to exist on vtlib\Block.
Loading history...
749 1
		} else {
750 1
			$blockInstance->display_status = null;
751 1
		}
752 1
		$moduleInstance->addBlock($blockInstance);
753 1
754 1
		return $blockInstance;
755 1
	}
756
757 1
	/**
758
	 * Import Fields of the module.
759
	 *
760
	 * @param mixed $blocknode
761 1
	 * @param mixed $blockInstance
762
	 * @param mixed $moduleInstance
763
	 */
764
	public function importFields($blocknode, $blockInstance, $moduleInstance)
765 1
	{
766 1
		if (empty($blocknode->fields) || empty($blocknode->fields->field)) {
767
			return;
768
		}
769 1
770 1
		foreach ($blocknode->fields->field as $fieldnode) {
771
			$this->importField($blocknode, $blockInstance, $moduleInstance, $fieldnode);
772
		}
773 1
	}
774
775
	/**
776
	 * Import Field of the module.
777 1
	 *
778 1
	 * @param mixed $blocknode
779 1
	 * @param mixed $blockInstance
780
	 * @param mixed $moduleInstance
781
	 * @param mixed $fieldnode
782 1
	 */
783
	public function importField($blocknode, $blockInstance, $moduleInstance, $fieldnode)
0 ignored issues
show
Unused Code introduced by
The parameter $blocknode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

783
	public function importField(/** @scrutinizer ignore-unused */ $blocknode, $blockInstance, $moduleInstance, $fieldnode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
784
	{
785 1
		$fieldInstance = new Field();
786 1
		$fieldInstance->name = (string) $fieldnode->fieldname;
787 1
		$fieldInstance->label = (string) $fieldnode->fieldlabel;
788 1
		$fieldInstance->table = (string) $fieldnode->tablename;
789
		$fieldInstance->column = (string) $fieldnode->columnname;
790
		$fieldInstance->uitype = (int) $fieldnode->uitype;
791
		$fieldInstance->generatedtype = (int) $fieldnode->generatedtype;
792 1
		$fieldInstance->readonly = (int) $fieldnode->readonly;
793
		$fieldInstance->presence = (int) $fieldnode->presence;
794
		$fieldInstance->defaultvalue = (string) $fieldnode->defaultvalue;
795
		$fieldInstance->maximumlength = (string) $fieldnode->maximumlength;
796
		$fieldInstance->sequence = (int) $fieldnode->sequence;
797
		$fieldInstance->quickcreate = (int) $fieldnode->quickcreate;
798
		$fieldInstance->quicksequence = (int) $fieldnode->quickcreatesequence;
799
		$fieldInstance->typeofdata = (string) $fieldnode->typeofdata;
800
		$fieldInstance->displaytype = (int) $fieldnode->displaytype;
801 1
		$fieldInstance->info_type = (string) $fieldnode->info_type;
802
803
		if (!empty($fieldnode->fieldparams)) {
804
			$fieldInstance->fieldparams = (string) $fieldnode->fieldparams;
805
		}
806
807
		if (!empty($fieldnode->helpinfo)) {
808
			$fieldInstance->helpinfo = (string) $fieldnode->helpinfo;
809
		}
810 1
811
		if (isset($fieldnode->masseditable)) {
812
			$fieldInstance->masseditable = (int) $fieldnode->masseditable;
813 1
		}
814
815 1
		if (isset($fieldnode->columntype) && !empty($fieldnode->columntype)) {
816
			$fieldInstance->columntype = (string) ($fieldnode->columntype);
817
		}
818
819
		if (!empty($fieldnode->tree_template)) {
820
			$templateid = $fieldInstance->setTreeTemplate($fieldnode->tree_template, $moduleInstance);
821 2
			$fieldInstance->fieldparams = $templateid;
822
		}
823 2
		if (!empty($fieldnode->numberInfo)) {
824 1
			$numberInfo = $fieldnode->numberInfo;
825
			\App\Fields\RecordNumber::getInstance($moduleInstance->id)->set('tabid', $moduleInstance->id)->set('prefix', $numberInfo->prefix)->set('leading_zeros', $numberInfo->leading_zeros)->set('postfix', $numberInfo->postfix)->set('start_id', $numberInfo->start_id)->set('cur_id', $numberInfo->cur_id)->set('reset_sequence', $numberInfo->reset_sequence)->set('cur_sequence', $numberInfo->cur_sequence)->save();
826 1
		}
827 1
828
		$blockInstance->addField($fieldInstance);
829 1
830
		// Set the field as entity identifier if marked.
831
		if (!empty($fieldnode->entityidentifier)) {
832
			$moduleInstance->entityidfield = $fieldnode->entityidentifier->entityidfield;
833
			$moduleInstance->entityidcolumn = $fieldnode->entityidentifier->entityidcolumn;
834 1
			$moduleInstance->setEntityIdentifier($fieldInstance);
835
		}
836 1
837 1
		// Check picklist values associated with field if any.
838 1
		if (!empty($fieldnode->picklistvalues) && !empty($fieldnode->picklistvalues->picklistvalue)) {
839 1
			$picklistvalues = [];
840 1
			foreach ($fieldnode->picklistvalues->picklistvalue as $picklistvaluenode) {
841 1
				$picklistvalues[] = $picklistvaluenode;
842 1
			}
843 1
			$fieldInstance->setPicklistValues($picklistvalues);
844 1
		}
845 1
846 1
		// Check related modules associated with this field
847 1
		if (!empty($fieldnode->relatedmodules) && !empty($fieldnode->relatedmodules->relatedmodule)) {
848 1
			$relatedmodules = [];
849
			foreach ($fieldnode->relatedmodules->relatedmodule as $relatedmodulenode) {
850
				$relatedmodules[] = $relatedmodulenode;
851 1
			}
852
			$fieldInstance->setRelatedModules($relatedmodules);
853 1
		}
854 1
855
		// Set summary field if marked in xml
856 1
		if (!empty($fieldnode->summaryfield)) {
857
			$fieldInstance->setSummaryField($fieldnode->summaryfield);
858
		}
859 1
		$this->__AddModuleFieldToCache($moduleInstance, $fieldnode->fieldname, $fieldInstance);
860
861
		return $fieldInstance;
862
	}
863
864 2
	/**
865
	 * Import Custom views of the module.
866 2
	 *
867 1
	 * @param mixed $modulenode
868
	 * @param mixed $moduleInstance
869
	 */
870 1
	public function importCustomViews($modulenode, $moduleInstance)
871 1
	{
872 1
		if (empty($modulenode->customviews) || empty($modulenode->customviews->customview)) {
873
			return;
874
		}
875 1
		foreach ($modulenode->customviews->customview as $customviewnode) {
876
			$this->importCustomView($modulenode, $moduleInstance, $customviewnode);
877
		}
878
	}
879
880 2
	/**
881
	 * Import Custom View of the module.
882 2
	 *
883 2
	 * @param mixed $modulenode
884
	 * @param mixed $moduleInstance
885
	 * @param mixed $customviewnode
886
	 */
887
	public function importCustomView($modulenode, $moduleInstance, $customviewnode)
0 ignored issues
show
Unused Code introduced by
The parameter $modulenode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

887
	public function importCustomView(/** @scrutinizer ignore-unused */ $modulenode, $moduleInstance, $customviewnode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
888
	{
889
		$filterInstance = new Filter();
890
		$filterInstance->name = $customviewnode->viewname;
891
		$filterInstance->isdefault = $customviewnode->setdefault;
892
		$filterInstance->inmetrics = $customviewnode->setmetrics;
893
		$filterInstance->presence = $customviewnode->presence;
894 2
		$filterInstance->privileges = $customviewnode->privileges;
895
		$filterInstance->featured = $customviewnode->featured;
896 2
		$filterInstance->sequence = $customviewnode->sequence;
0 ignored issues
show
Bug Best Practice introduced by
The property sequence does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
897 1
		$filterInstance->description = $customviewnode->description;
898
		$filterInstance->sort = $customviewnode->sort;
899 1
		$moduleInstance->addFilter($filterInstance);
900 1
		foreach ($customviewnode->fields->field as $fieldnode) {
901
			if ((string) $fieldnode->modulename === $moduleInstance->name) {
902 1
				$fieldInstance = $this->__GetModuleFieldFromCache($moduleInstance, $fieldnode->fieldname);
903
			} else {
904
				$fieldInstance = Field::getInstance((string) $fieldnode->fieldname, Module::getInstance((string) $fieldnode->modulename));
905
			}
906
			if ($sourceFieldName = (string) $fieldnode->sourcefieldname ?? '') {
907 1
				$fieldInstance->sourcefieldname = $sourceFieldName;
908
			}
909 1
			$filterInstance->addField($fieldInstance, $fieldnode->columnindex);
910 1
		}
911 1
		if (!empty($customviewnode->rules)) {
912
			$filterInstance->addRule(\App\Json::decode($customviewnode->rules));
913
		}
914
	}
915 1
916
	/**
917
	 * Import Sharing Access of the module.
918
	 *
919
	 * @param mixed $modulenode
920 2
	 * @param mixed $moduleInstance
921
	 */
922 2
	public function importSharingAccess($modulenode, $moduleInstance)
923 1
	{
924 1
		if (empty($modulenode->sharingaccess)) {
925
			return;
926
		}
927 2
928 1
		if (!empty($modulenode->sharingaccess->default)) {
929 1
			foreach ($modulenode->sharingaccess->default as $defaultnode) {
930
				$moduleInstance->setDefaultSharing($defaultnode);
931
			}
932 2
		}
933
	}
934
935
	/**
936
	 * Import Events of the module.
937 1
	 *
938
	 * @param mixed $modulenode
939 1
	 * @param mixed $moduleInstance
940 1
	 */
941 1
	public function importEvents($modulenode, $moduleInstance)
942 1
	{
943 1
		if (empty($modulenode->eventHandlers) || empty($modulenode->eventHandlers->event)) {
944 1
			return;
945 1
		}
946
		$moduleId = \App\Module::getModuleId($moduleInstance->name);
947
		foreach ($modulenode->eventHandlers->event as &$eventNode) {
948 1
			\App\EventHandler::registerHandler($eventNode->eventName, $eventNode->className, $eventNode->includeModules, $eventNode->excludeModules, $eventNode->priority, $eventNode->isActive, $moduleId);
949 1
		}
950
	}
951 1
952
	/**
953
	 * Import actions of the module.
954 1
	 *
955
	 * @param mixed $modulenode
956 1
	 * @param mixed $moduleInstance
957 1
	 */
958 1
	public function importActions($modulenode, $moduleInstance)
959 1
	{
960 1
		if (empty($modulenode->actions) || empty($modulenode->actions->action)) {
961 1
			return;
962 1
		}
963
		foreach ($modulenode->actions->action as $actionnode) {
964
			$this->importAction($modulenode, $moduleInstance, $actionnode);
965 1
		}
966 1
	}
967
968 1
	/**
969
	 * Import action of the module.
970
	 *
971
	 * @param mixed $modulenode
972
	 * @param mixed $moduleInstance
973
	 * @param mixed $actionnode
974 2
	 */
975
	public function importAction($modulenode, $moduleInstance, $actionnode)
0 ignored issues
show
Unused Code introduced by
The parameter $modulenode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

975
	public function importAction(/** @scrutinizer ignore-unused */ $modulenode, $moduleInstance, $actionnode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
976 2
	{
977 2
		$actionstatus = (string) $actionnode->status;
978
		if ('enabled' === $actionstatus) {
979
			$moduleInstance->enableTools((string) $actionnode->name);
980
		} else {
981
			$moduleInstance->disableTools((string) $actionnode->name);
982
		}
983
	}
984
985
	/**
986
	 * Import related lists of the module.
987
	 *
988
	 * @param mixed $modulenode
989
	 * @param mixed $moduleInstance
990
	 */
991
	public function importRelatedLists($modulenode, $moduleInstance)
992
	{
993
		if (!empty($modulenode->relatedlists) && !empty($modulenode->relatedlists->relatedlist)) {
994
			foreach ($modulenode->relatedlists->relatedlist as $relatedlistnode) {
995
				$this->importRelatedlist($modulenode, $moduleInstance, $relatedlistnode);
996
			}
997 2
		}
998
		if (!empty($modulenode->inrelatedlists) && !empty($modulenode->inrelatedlists->inrelatedlist)) {
999 2
			foreach ($modulenode->inrelatedlists->inrelatedlist as $inRelatedListNode) {
1000 1
				$this->importInRelatedlist($modulenode, $moduleInstance, $inRelatedListNode);
1001
			}
1002 1
		}
1003 1
	}
1004
1005
	/**
1006 1
	 * Import related list of the module.
1007
	 *
1008 1
	 * @param mixed $modulenode
1009 1
	 * @param mixed $moduleInstance
1010
	 * @param mixed $relatedlistnode
1011 1
	 */
1012
	public function importRelatedlist($modulenode, $moduleInstance, $relatedlistnode)
0 ignored issues
show
Unused Code introduced by
The parameter $modulenode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1012
	public function importRelatedlist(/** @scrutinizer ignore-unused */ $modulenode, $moduleInstance, $relatedlistnode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1013 1
	{
1014
		$relModuleInstance = Module::getInstance($relatedlistnode->relatedmodule);
1015
		$label = $relatedlistnode->label;
1016
		$actions = false;
1017
		if (!empty($relatedlistnode->actions) && !empty($relatedlistnode->actions->action)) {
1018
			$actions = [];
1019
			foreach ($relatedlistnode->actions->action as $actionnode) {
1020
				$actions[] = "$actionnode";
1021
			}
1022
		}
1023
		$fields = [];
1024
		if (!empty($relatedlistnode->fields)) {
1025
			foreach ($relatedlistnode->fields->field as $fieldNode) {
1026
				$fields[] = "$fieldNode";
1027
			}
1028
		}
1029
		if ($relModuleInstance) {
0 ignored issues
show
introduced by
$relModuleInstance is of type vtlib\Module, thus it always evaluated to true.
Loading history...
1030
			$moduleInstance->setRelatedList($relModuleInstance, "$label", $actions, "$relatedlistnode->function", "$relatedlistnode->field_name", $fields);
1031
		}
1032
		return $relModuleInstance;
1033
	}
1034
1035
	public function importInRelatedlist($modulenode, $moduleInstance, $inRelatedListNode)
0 ignored issues
show
Unused Code introduced by
The parameter $modulenode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1035
	public function importInRelatedlist(/** @scrutinizer ignore-unused */ $modulenode, $moduleInstance, $inRelatedListNode)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1036
	{
1037
		$inRelModuleInstance = Module::getInstance($inRelatedListNode->inrelatedmodule);
1038
		$label = $inRelatedListNode->label;
1039
		$actions = false;
1040
		if (!empty($inRelatedListNode->actions) && !empty($inRelatedListNode->actions->action)) {
1041
			$actions = [];
1042
			foreach ($inRelatedListNode->actions->action as $actionnode) {
1043
				$actions[] = "$actionnode";
1044
			}
1045
		}
1046
		$fields = [];
1047
		if (!empty($inRelatedListNode->fields)) {
1048
			foreach ($inRelatedListNode->fields->field as $fieldNode) {
1049
				$fields[] = "$fieldNode";
1050
			}
1051
		}
1052
		if ($inRelModuleInstance) {
0 ignored issues
show
introduced by
$inRelModuleInstance is of type vtlib\Module, thus it always evaluated to true.
Loading history...
1053
			$inRelModuleInstance->setRelatedList($moduleInstance, "$label", $actions, "$inRelatedListNode->function", "$inRelatedListNode->field_name", $fields);
1054
		}
1055
		return $inRelModuleInstance;
1056
	}
1057
1058
	/**
1059
	 * Import custom links of the module.
1060
	 *
1061
	 * @param mixed $modulenode
1062
	 * @param mixed $moduleInstance
1063
	 */
1064
	public function importCustomLinks($modulenode, $moduleInstance)
1065
	{
1066
		if (empty($modulenode->customlinks) || empty($modulenode->customlinks->customlink)) {
1067
			return;
1068
		}
1069
1070
		foreach ($modulenode->customlinks->customlink as $customlinknode) {
1071
			$handlerInfo = null;
1072
			if (isset($customlinknode->handler_path)) {
1073
				$handlerInfo = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $handlerInfo is dead and can be removed.
Loading history...
1074
				$handlerInfo = ['path' => "$customlinknode->handler_path",
1075
					'class' => "$customlinknode->handler_class",
1076
					'method' => "$customlinknode->handler", ];
1077
			}
1078 2
			$moduleInstance->addLink(
1079
				"$customlinknode->linktype", "$customlinknode->linklabel", "$customlinknode->linkurl", "$customlinknode->linkicon", "$customlinknode->sequence", $handlerInfo
1080 2
			);
1081 1
		}
1082
	}
1083 1
1084 1
	/**
1085 1
	 * Import cron jobs of the module.
1086 1
	 *
1087 1
	 * @param mixed $modulenode
1088
	 */
1089
	public function importCronTasks($modulenode)
1090
	{
1091
		if (empty($modulenode->crons) || empty($modulenode->crons->cron)) {
1092
			return;
1093
		}
1094
		foreach ($modulenode->crons->cron as $cronTask) {
1095
			if (empty($cronTask->status)) {
1096
				$cronTask->status = Cron::$STATUS_DISABLED;
1097
			} else {
1098
				$cronTask->status = Cron::$STATUS_ENABLED;
1099
			}
1100
			if ((empty($cronTask->sequence))) {
1101
				$cronTask->sequence = Cron::nextSequence();
1102
			}
1103
			Cron::register("$cronTask->name", "$cronTask->handler", "$cronTask->frequency", "$modulenode->name", "$cronTask->status", "$cronTask->sequence", "$cronTask->description");
0 ignored issues
show
Bug introduced by
$cronTask->sequence of type string is incompatible with the type integer expected by parameter $sequence of vtlib\Cron::register(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1103
			Cron::register("$cronTask->name", "$cronTask->handler", "$cronTask->frequency", "$modulenode->name", "$cronTask->status", /** @scrutinizer ignore-type */ "$cronTask->sequence", "$cronTask->description");
Loading history...
Bug introduced by
$cronTask->status of type string is incompatible with the type integer expected by parameter $status of vtlib\Cron::register(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1103
			Cron::register("$cronTask->name", "$cronTask->handler", "$cronTask->frequency", "$modulenode->name", /** @scrutinizer ignore-type */ "$cronTask->status", "$cronTask->sequence", "$cronTask->description");
Loading history...
Bug introduced by
$cronTask->frequency of type string is incompatible with the type integer expected by parameter $frequency of vtlib\Cron::register(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1103
			Cron::register("$cronTask->name", "$cronTask->handler", /** @scrutinizer ignore-type */ "$cronTask->frequency", "$modulenode->name", "$cronTask->status", "$cronTask->sequence", "$cronTask->description");
Loading history...
1104
		}
1105
	}
1106
1107
	public function importUpdate()
1108
	{
1109
		$dirName = 'cache/updates/updates';
1110
		$db = \App\Db::getInstance();
1111
		$startTime = microtime(true);
1112
		file_put_contents('cache/logs/update.log', PHP_EOL . ((string) $this->_modulexml->label) . ' - ' . date('Y-m-d H:i:s'), FILE_APPEND);
1113
		ob_start();
1114
		if (file_exists($dirName . '/init.php')) {
1115
			require_once $dirName . '/init.php';
1116
			$updateInstance = new \YetiForceUpdate($this->_modulexml);
0 ignored issues
show
Bug introduced by
The type YetiForceUpdate was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1117
			$updateInstance->package = $this;
1118
			$result = $updateInstance->preupdate();
1119
			file_put_contents('cache/logs/update.log', PHP_EOL . ' | ' . ob_get_clean(), FILE_APPEND);
1120
			ob_start();
1121
			if (false !== $result) {
1122
				$updateInstance->update();
1123
				if ($updateInstance->filesToDelete) {
1124
					foreach ($updateInstance->filesToDelete as $path) {
1125
						Functions::recurseDelete($path);
1126
					}
1127
				}
1128
				if (method_exists($updateInstance, 'afterDelete')) {
1129
					$updateInstance->afterDelete();
1130
				}
1131
				Functions::recurseCopy($dirName . '/files', '');
1132
				if (method_exists($updateInstance, 'afterCopy')) {
1133
					$updateInstance->afterCopy();
1134
				}
1135
				if ($content = ob_get_clean()) {
1136
					file_put_contents('cache/logs/update.log', $content, FILE_APPEND);
1137
				}
1138
				ob_start();
1139
				$result = $updateInstance->postupdate();
1140
			}
1141
		} else {
1142
			Functions::recurseCopy($dirName . '/files', '');
1143
			$result = true;
1144
		}
1145
		$db->createCommand()->insert('yetiforce_updates', [
1146
			'user' => \Users_Record_Model::getCurrentUserModel()->get('user_name'),
1147
			'name' => (string) $this->_modulexml->label,
1148
			'from_version' => (string) $this->_modulexml->from_version,
1149
			'to_version' => (string) $this->_modulexml->to_version,
1150
			'result' => $result,
1151
			'time' => date('Y-m-d H:i:s'),
1152
		])->execute();
1153
		if ($result) {
1154
			$db->createCommand()->update('vtiger_version', ['current_version' => (string) $this->_modulexml->to_version])->execute();
1155
		}
1156
		Functions::recurseDelete($dirName);
1157
		register_shutdown_function(function () {
1158
			try {
1159
				Functions::recurseDelete('cache/templates_c');
1160
			} catch (\Exception $e) {
1161
				\App\Log::error($e->getMessage() . PHP_EOL . $e->__toString());
1162
			}
1163
		});
1164
		\App\Module::createModuleMetaFile();
1165
		\App\Cache::clear();
1166
		\App\Cache::clearOpcache();
1167
		Functions::recurseDelete('app_data/LanguagesUpdater.json');
1168
		Functions::recurseDelete('app_data/SystemUpdater.json');
1169
		Functions::recurseDelete('app_data/cron.php');
1170
		Functions::recurseDelete('app_data/ConfReport_AllErrors.php');
1171
		Functions::recurseDelete('app_data/shop.php');
1172
		file_put_contents('cache/logs/update.log', PHP_EOL . date('Y-m-d H:i:s') . ' (' . round(microtime(true) - $startTime, 2) . ') | ' . ob_get_clean(), FILE_APPEND);
1173
	}
1174
1175
	/**
1176
	 * Import inventory fields of the module.
1177
	 */
1178
	public function importInventory()
1179
	{
1180
		if (1 !== $this->moduleInstance->type) {
0 ignored issues
show
Bug introduced by
The property type does not exist on boolean.
Loading history...
1181
			return false;
1182
		}
1183
		$module = (string) $this->moduleInstance->name;
0 ignored issues
show
Bug introduced by
The property name does not exist on boolean.
Loading history...
1184
		$inventory = \Vtiger_Inventory_Model::getInstance($module);
1185
		$inventory->createInventoryTables();
1186
		if (empty($this->_modulexml->inventory) || empty($this->_modulexml->inventory->fields->field)) {
1187
			return false;
1188
		}
1189
		foreach ($this->_modulexml->inventory->fields->field as $fieldNode) {
1190
			$fieldModel = $inventory->getFieldCleanInstance((string) $fieldNode->invtype);
1191
			$fieldModel->setDefaultDataConfig();
1192
			$fields = ['label', 'defaultValue', 'block', 'displayType', 'params', 'colSpan', 'columnName', 'sequence'];
1193
			foreach ($fields as $name) {
1194
				switch ($name) {
1195
					case 'label':
1196
						$value = \App\Purifier::purifyByType((string) $fieldNode->label, 'Text');
1197
						$fieldModel->set($name, $value);
1198
						break;
1199
					case 'defaultValue':
1200
						$value = \App\Purifier::purifyByType((string) $fieldNode->defaultvalue, 'Text');
1201
						$fieldModel->set($name, $value);
1202
						break;
1203
					case 'block':
1204
						$blockId = (int) $fieldNode->block;
1205
						if (!\in_array($blockId, $fieldModel->getBlocks())) {
1206
							throw new \App\Exceptions\IllegalValue("ERR_NOT_ALLOWED_VALUE||{$name}||" . $blockId, 406);
1207
						}
1208
						$fieldModel->set($name, $blockId);
1209
						break;
1210
					case 'displayType':
1211
						$displayType = (int) $fieldNode->displaytype;
1212
						if (!\in_array($displayType, $fieldModel->displayTypeBase())) {
1213
							throw new \App\Exceptions\IllegalValue("ERR_NOT_ALLOWED_VALUE||{$name}||" . $displayType, 406);
1214
						}
1215
						$fieldModel->set($name, $displayType);
1216
						break;
1217
					case 'params':
1218
						$value = \App\Purifier::purifyByType((string) $fieldNode->params, 'Text');
1219
						$fieldModel->set($name, $value);
1220
						break;
1221
					case 'colSpan':
1222
						$fieldModel->set($name, (int) $fieldNode->colspan);
1223
						break;
1224
					case 'columnName':
1225
						$fieldModel->set($name, \App\Purifier::purifyByType((string) $fieldNode->columnname, 'Alnum'));
1226
						break;
1227
					case 'sequence':
1228
						$fieldModel->set($name, (int) $fieldNode->sequence);
1229
						break;
1230
					default:
1231
						break;
1232
				}
1233
			}
1234
			$inventory->saveField($fieldModel);
1235
		}
1236
	}
1237
1238
	/**
1239
	 * Import font package.
1240
	 *
1241
	 * @param string $zipfile
1242
	 *
1243
	 * @throws \App\Exceptions\AppException
1244
	 */
1245
	public function importFont($zipfile)
1246
	{
1247
		$fontsDir = ROOT_DIRECTORY . '/public_html/layouts/resources/fonts';
1248
		$zip = \App\Zip::openFile($zipfile, ['onlyExtensions' => ['ttf', 'txt', 'woff']]);
0 ignored issues
show
Bug introduced by
$zipfile of type string is incompatible with the type boolean expected by parameter $fileName of App\Zip::openFile(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1248
		$zip = \App\Zip::openFile(/** @scrutinizer ignore-type */ $zipfile, ['onlyExtensions' => ['ttf', 'txt', 'woff']]);
Loading history...
1249
		$files = $zip->unzip(['fonts' => $fontsDir]);
1250
		$fonts = \App\Json::read($fontsDir . '/fonts.json');
1251
		$tempFonts = [];
1252
		foreach ($fonts as $font) {
1253
			$tempFonts[$font['family']][$font['weight']][$font['style']] = $font['file'];
1254
		}
1255
		foreach ($files as $key => &$file) {
1256
			$file = \str_replace('fonts/', '', $file);
1257
			if (empty($file)) {
1258
				unset($files[$key]);
1259
			}
1260
		}
1261
		$files = \array_flip($files);
1262
		$missing = [];
1263
		if (!empty($this->_modulexml->fonts->font)) {
1264
			foreach ($this->_modulexml->fonts->font as $font) {
1265
				if (!isset($files[(string) $font->file])) {
1266
					$missing[] = (string) $font->file;
1267
				}
1268
				if (!isset($tempFonts[(string) $font->family][(string) $font->weight][(string) $font->style])) {
1269
					$fonts[] = [
1270
						'family' => (string) $font->family,
1271
						'weight' => (string) $font->weight,
1272
						'style' => (string) $font->style,
1273
						'file' => (string) $font->file,
1274
					];
1275
				}
1276
			}
1277
		}
1278
		if ($missing) {
1279
			$this->_errorText = \App\Language::translate('LBL_ERROR_MISSING_FILES', 'Settings:ModuleManager') . ' ' . \implode(',', $missing);
1280
		}
1281
		$css = [];
1282
		foreach ($fonts as $key => $font) {
1283
			if (!\file_exists("$fontsDir/{$font['file']}")) {
1284
				unset($fonts[$key]);
1285
			} else {
1286
				$woff = pathinfo($font['file'], PATHINFO_FILENAME) . '.woff';
0 ignored issues
show
Bug introduced by
Are you sure pathinfo($font['file'], vtlib\PATHINFO_FILENAME) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1286
				$woff = /** @scrutinizer ignore-type */ pathinfo($font['file'], PATHINFO_FILENAME) . '.woff';
Loading history...
1287
				$fontCss = "@font-face {\n";
1288
				$fontCss .= "    font-family: '{$font['family']}';\n";
1289
				$fontCss .= "    font-style: {$font['style']};\n";
1290
				$fontCss .= "    font-weight: {$font['weight']};\n";
1291
				$fontCss .= "    src: local('{$font['family']}'), url({$woff}) format('woff');\n";
1292
				$fontCss .= '}';
1293
				$css[] = $fontCss;
1294
			}
1295
		}
1296
		$css[] = '@font-face {
1297
			font-family: \'DejaVu Sans\';
1298
			font-style: normal;
1299
			font-weight: 100;
1300
			src: local(\'DejaVu Sans\'), url(\'DejaVuSans-ExtraLight.woff\') format(\'woff\');
1301
		}
1302
		@font-face {
1303
			font-family: \'DejaVu Sans\';
1304
			font-style: normal;
1305
			font-weight: 400;
1306
			src: local(\'DejaVu Sans\'), url(\'DejaVuSans.woff\') format(\'woff\');
1307
		}
1308
		@font-face {
1309
			font-family: \'DejaVu Sans\';
1310
			font-style: normal;
1311
			font-weight: 700;
1312
			src: local(\'DejaVu Sans\'), url(\'DejaVuSans-Bold.woff\') format(\'woff\');
1313
		}
1314
		@font-face {
1315
			font-family: \'DejaVu Sans\';
1316
			font-style: italic;
1317
			font-weight: 700;
1318
			src: local(\'DejaVu Sans\'), url(\'DejaVuSans-BoldOblique.woff\') format(\'woff\');
1319
		}
1320
		@font-face {
1321
			font-family: \'DejaVu Sans\';
1322
			font-style: italic;
1323
			font-weight: 400;
1324
			src: local(\'DejaVu Sans\'), url(\'DejaVuSans-Oblique.woff\') format(\'woff\');
1325
		}
1326
		* {
1327
			font-family: \'DejaVu Sans\';
1328
		}';
1329
		file_put_contents($fontsDir . '/fonts.css', implode("\n", $css));
1330
		\App\Json::save($fontsDir . '/fonts.json', array_values($fonts));
1331
	}
1332
}
1333