Commit | Line | Data |
---|---|---|
d7424422 AE |
1 | <?php |
2 | namespace wcf\data\devtools\project; | |
d7424422 AE |
3 | use wcf\data\package\installation\plugin\PackageInstallationPluginList; |
4 | use wcf\data\package\Package; | |
5 | use wcf\data\package\PackageCache; | |
e7de794a | 6 | use wcf\data\DatabaseObject; |
d7424422 AE |
7 | use wcf\system\devtools\package\DevtoolsPackageArchive; |
8 | use wcf\system\devtools\pip\DevtoolsPip; | |
9 | use wcf\system\package\validation\PackageValidationException; | |
52da8ead | 10 | use wcf\system\Regex; |
d7424422 | 11 | use wcf\system\WCF; |
52da8ead | 12 | use wcf\util\DirectoryUtil; |
d7424422 AE |
13 | |
14 | /** | |
15 | * Represents a devtools project. | |
16 | * | |
17 | * @author Alexander Ebert | |
c839bd49 | 18 | * @copyright 2001-2018 WoltLab GmbH |
d7424422 AE |
19 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
20 | * @package WoltLabSuite\Core\Devtools\Project | |
21 | * @since 3.1 | |
22 | * | |
23 | * @property-read integer $projectID unique id of the project | |
24 | * @property-read string $name internal name for display inside the ACP | |
25 | * @property-read string $path file system path | |
26 | */ | |
27 | class DevtoolsProject extends DatabaseObject { | |
28 | /** | |
29 | * @var boolean | |
30 | */ | |
31 | protected $isCore; | |
32 | ||
33 | /** | |
34 | * @var Package | |
35 | */ | |
36 | protected $package; | |
37 | ||
38 | /** | |
39 | * @var DevtoolsPackageArchive | |
40 | */ | |
41 | protected $packageArchive; | |
42 | ||
d4955651 AE |
43 | /** |
44 | * Returns a list of decorated PIPs. | |
45 | * | |
46 | * @return DevtoolsPip[] | |
47 | */ | |
d7424422 AE |
48 | public function getPips() { |
49 | $pipList = new PackageInstallationPluginList(); | |
50 | $pipList->sqlOrderBy = 'pluginName'; | |
51 | $pipList->readObjects(); | |
52 | ||
53 | $pips = []; | |
54 | foreach ($pipList as $pip) { | |
532a045a MS |
55 | $pip = new DevtoolsPip($pip); |
56 | $pip->setProject($this); | |
57 | ||
58 | $pips[] = $pip; | |
d7424422 AE |
59 | } |
60 | ||
61 | return $pips; | |
62 | } | |
63 | ||
d4955651 AE |
64 | /** |
65 | * Validates the repository and returns the first error message, or | |
66 | * an empty string on success. | |
67 | * | |
68 | * @return string | |
69 | */ | |
d7424422 AE |
70 | public function validate() { |
71 | $errorType = self::validatePath($this->path); | |
72 | if ($errorType !== '') { | |
73 | return WCF::getLanguage()->get('wcf.acp.devtools.project.path.error.' . $errorType); | |
74 | } | |
75 | ||
76 | return $this->validatePackageXml(); | |
77 | } | |
78 | ||
d4955651 AE |
79 | /** |
80 | * Returns true if this project appears to be `WoltLab Suite Core`. | |
81 | * | |
82 | * @return boolean | |
83 | */ | |
d7424422 AE |
84 | public function isCore() { |
85 | if ($this->isCore === null) { | |
86 | $this->isCore = self::pathIsCore($this->path); | |
87 | } | |
88 | ||
89 | return $this->isCore; | |
90 | } | |
91 | ||
d4955651 AE |
92 | /** |
93 | * Validates the package.xml and checks if the package is already installed. | |
94 | * | |
95 | * @return string | |
96 | */ | |
d7424422 AE |
97 | public function validatePackageXml() { |
98 | $packageXml = $this->path . ($this->isCore() ? 'com.woltlab.wcf/' : '') . 'package.xml'; | |
99 | $this->packageArchive = new DevtoolsPackageArchive($packageXml); | |
100 | try { | |
101 | $this->packageArchive->openArchive(); | |
102 | } | |
103 | catch (PackageValidationException $e) { | |
104 | return $e->getErrorMessage(); | |
105 | } | |
106 | ||
107 | $this->package = PackageCache::getInstance()->getPackageByIdentifier($this->packageArchive->getPackageInfo('name')); | |
108 | if ($this->package === null) { | |
109 | return WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.project.path.error.notInstalled', [ | |
110 | 'package' => $this->packageArchive->getPackageInfo('name') | |
111 | ]); | |
112 | } | |
113 | ||
d2b357c6 AE |
114 | $normalizeVersion = function($version) { |
115 | return preg_replace('~^(\d+)\.(\d+)\..*$~', '\\1.\\2', $version); | |
116 | }; | |
117 | ||
118 | if ($normalizeVersion($this->packageArchive->getPackageInfo('version')) !== $normalizeVersion($this->package->packageVersion)) { | |
119 | return WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.project.path.error.versionMismatch', [ | |
120 | 'version' => $this->packageArchive->getPackageInfo('version'), | |
121 | 'packageVersion' => $this->package->packageVersion | |
122 | ]); | |
123 | } | |
124 | ||
125 | if (!$this->isCore()) { | |
68e8cb7f TD |
126 | $compatibleVersions = $this->packageArchive->getCompatibleVersions(); |
127 | if (empty($compatibleVersions)) { | |
128 | return WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.project.path.error.missingCompatibility'); | |
129 | } | |
130 | $isCompatible = $isOlderVersion = false; | |
131 | foreach ($compatibleVersions as $version) { | |
132 | if (WCF::isSupportedApiVersion($version)) { | |
133 | $isCompatible = true; | |
d2b357c6 AE |
134 | break; |
135 | } | |
68e8cb7f TD |
136 | else if ($version < WSC_API_VERSION) { |
137 | $isOlderVersion = true; | |
138 | } | |
d2b357c6 AE |
139 | } |
140 | ||
68e8cb7f TD |
141 | if (!$isCompatible) { |
142 | return WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.project.path.error.unsupportedCompatibility', ['isOlderVersion' => $isOlderVersion]); | |
d2b357c6 AE |
143 | } |
144 | } | |
145 | ||
d7424422 AE |
146 | return ''; |
147 | } | |
148 | ||
149 | /** | |
150 | * @return Package | |
151 | */ | |
152 | public function getPackage() { | |
153 | return $this->package; | |
154 | } | |
155 | ||
156 | /** | |
157 | * @return DevtoolsPackageArchive | |
158 | */ | |
159 | public function getPackageArchive() { | |
160 | return $this->packageArchive; | |
161 | } | |
162 | ||
52da8ead MS |
163 | /** |
164 | * Returns the absolute paths of the language files. | |
165 | * | |
166 | * @return string[] | |
167 | */ | |
168 | public function getLanguageFiles() { | |
169 | $languageDirectory = $this->path . ($this->isCore() ? 'wcfsetup/install/lang/' : 'language/'); | |
170 | ||
171 | return array_values(DirectoryUtil::getInstance($languageDirectory)->getFiles(SORT_ASC, Regex::compile('\w+\.xml'))); | |
172 | } | |
173 | ||
d7424422 AE |
174 | /** |
175 | * Validates the provided path and returns an error code | |
176 | * if the path does not exist (`notFound`) or if there is | |
177 | * no package.xml (`packageXml`). | |
178 | * | |
179 | * @param string $path | |
180 | * @return string | |
181 | */ | |
182 | public static function validatePath($path) { | |
183 | if (!is_dir($path)) { | |
184 | return 'notFound'; | |
185 | } | |
186 | else if (!file_exists($path . 'package.xml')) { | |
187 | // check if this is `com.woltlab.wcf` | |
188 | if (!self::pathIsCore($path)) { | |
189 | return 'packageXml'; | |
190 | } | |
191 | } | |
192 | ||
193 | return ''; | |
194 | } | |
195 | ||
d4955651 AE |
196 | /** |
197 | * Returns true if the path appears to point to `WoltLab Suite Core`. | |
198 | * | |
199 | * @param string $path | |
200 | * @return boolean | |
201 | */ | |
d7424422 AE |
202 | public static function pathIsCore($path) { |
203 | return (is_dir($path . 'com.woltlab.wcf') && file_exists($path . 'com.woltlab.wcf/package.xml')); | |
204 | } | |
205 | } |