Overhauled manual package installation (backport from WCF 2.1)
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / package / validation / PackageValidationManager.class.php
1 <?php
2 namespace wcf\system\package\validation;
3 use wcf\data\package\installation\plugin\PackageInstallationPluginList;
4 use wcf\data\package\Package;
5 use wcf\system\package\PackageArchive;
6 use wcf\system\SingletonFactory;
7
8 /**
9 * Manages recursive validation of package archives.
10 *
11 * @author Alexander Ebert
12 * @copyright 2001-2014 WoltLab GmbH
13 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14 * @package com.woltlab.wcf
15 * @subpackage system.package.validation
16 * @category Community Framework
17 */
18 class PackageValidationManager extends SingletonFactory {
19 /**
20 * package validation archive object
21 * @var \wcf\system\package\validation\PackageValidationArchive
22 */
23 protected $packageValidationArchive = null;
24
25 /**
26 * virtual package list containing package => packageVersion
27 * @var array<string>
28 */
29 protected $virtualPackageList = array();
30
31 /**
32 * validation will only check if the primary package looks like it can be installed or updated
33 * @var integer
34 */
35 const VALIDATION_WEAK = 0;
36
37 /**
38 * validation will recursively check dependencies
39 * @var integer
40 */
41 const VALIDATION_RECURSIVE = 1;
42
43 /**
44 * validation will use the previously gathered exclusions and check them
45 * @var integer
46 */
47 const VALIDATION_EXCLUSION = 2;
48
49 /**
50 * Validates given archive for existance and ability to be installed/updated. If you set the
51 * second parameter $deepInspection to "false", the system will only check if the archive
52 * looks fine, this is useful for a rough check during upload when a more detailed check will
53 * be performed afterwards.
54 *
55 * @param string $archive
56 * @param boolean $deepInspection
57 * @return boolean
58 */
59 public function validate($archive, $deepInspection) {
60 $this->virtualPackageList = array();
61 $this->packageValidationArchive = new PackageValidationArchive($archive);
62
63 if ($deepInspection) {
64 if (!$this->packageValidationArchive->validate(self::VALIDATION_RECURSIVE)) {
65 return false;
66 }
67
68 return $this->packageValidationArchive->validate(self::VALIDATION_EXCLUSION);
69 }
70
71 return $this->packageValidationArchive->validate(self::VALIDATION_WEAK);
72 }
73
74 /**
75 * Returns package validation archive object.
76 *
77 * @return \wcf\system\package\validation\PackageValidationArchive
78 */
79 public function getPackageValidationArchive() {
80 return $this->packageValidationArchive;
81 }
82
83 /**
84 * Adds a virtual package with the corresponding version, if the package is already known,
85 * the higher version number will be stored.
86 *
87 * @param string $package
88 * @param string $packageVersion
89 * @return boolean
90 */
91 public function addVirtualPackage($package, $packageVersion) {
92 if (isset($this->virtualPackageList[$package])) {
93 if (Package::compareVersion($packageVersion, $this->virtualPackageList[$package], '<')) {
94 return false;
95 }
96 }
97
98 $this->virtualPackageList[$package] = $packageVersion;
99
100 return true;
101 }
102
103 /**
104 * Returns the version number of a virtual package or null if it doesn't exist.
105 *
106 * @param string $package
107 * @return string
108 */
109 public function getVirtualPackage($package) {
110 if (isset($this->virtualPackageList[$package])) {
111 return $this->virtualPackageList[$package];
112 }
113
114 return null;
115 }
116
117 /**
118 * Returns the iteratable package archive list.
119 *
120 * @return \RecursiveIteratorIterator
121 */
122 public function getPackageValidationArchiveList() {
123 $packageValidationArchive = new PackageValidationArchive('');
124 $packageValidationArchive->setChildren(array($this->packageValidationArchive));
125
126 return new \RecursiveIteratorIterator($packageValidationArchive, \RecursiveIteratorIterator::SELF_FIRST);
127 }
128
129 /**
130 * Recursively traverses the package validation archives and returns the first exception message.
131 *
132 * @return string
133 */
134 public function getExceptionMessage() {
135 foreach ($this->getPackageValidationArchiveList() as $packageArchive) {
136 if ($packageArchive->getExceptionMessage()) {
137 return $packageArchive->getExceptionMessage();
138 }
139 }
140
141 return '';
142 }
143
144 /**
145 * Recursively traverses the package validation archives and returns the first exception.
146 *
147 * @return \Exception
148 */
149 public function getException() {
150 foreach ($this->getPackageValidationArchiveList() as $packageArchive) {
151 if ($packageArchive->getException() !== null) {
152 return $packageArchive->getException();
153 }
154 }
155
156 return null;
157 }
158 }