[CLEANUP] The correct case must be used for standard PHP types in phpdoc
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Package / Package.php
1 <?php
2 namespace TYPO3\CMS\Core\Package;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * A Package representing the details of an extension and/or a composer package
21 * Adapted from FLOW for TYPO3 CMS
22 */
23 class Package implements PackageInterface
24 {
25 /**
26 * @var array
27 */
28 protected $extensionManagerConfiguration = [];
29
30 /**
31 * If this package is part of factory default, it will be activated
32 * during first installation.
33 *
34 * @var bool
35 */
36 protected $partOfFactoryDefault = false;
37
38 /**
39 * If this package is part of minimal usable system, it will be
40 * activated if PackageStates is created from scratch.
41 *
42 * @var bool
43 */
44 protected $partOfMinimalUsableSystem = false;
45
46 /**
47 * Unique key of this package.
48 * @var string
49 */
50 protected $packageKey;
51
52 /**
53 * Full path to this package's main directory
54 * @var string
55 */
56 protected $packagePath;
57
58 /**
59 * If this package is protected and therefore cannot be deactivated or deleted
60 * @var bool
61 */
62 protected $protected = false;
63
64 /**
65 * @var \stdClass
66 */
67 protected $composerManifest;
68
69 /**
70 * Meta information about this package
71 * @var MetaData
72 */
73 protected $packageMetaData;
74
75 /**
76 * @var PackageManager
77 */
78 protected $packageManager;
79
80 /**
81 * Constructor
82 *
83 * @param PackageManager $packageManager the package manager which knows this package
84 * @param string $packageKey Key of this package
85 * @param string $packagePath Absolute path to the location of the package's composer manifest
86 * @throws Exception\InvalidPackageKeyException if an invalid package key was passed
87 * @throws Exception\InvalidPackagePathException if an invalid package path was passed
88 * @throws Exception\InvalidPackageManifestException if no composer manifest file could be found
89 */
90 public function __construct(PackageManager $packageManager, $packageKey, $packagePath)
91 {
92 if (!$packageManager->isPackageKeyValid($packageKey)) {
93 throw new Exception\InvalidPackageKeyException('"' . $packageKey . '" is not a valid package key.', 1217959511);
94 }
95 if (!(@is_dir($packagePath) || (is_link($packagePath) && is_dir($packagePath)))) {
96 throw new Exception\InvalidPackagePathException(sprintf('Tried to instantiate a package object for package "%s" with a non-existing package path "%s". Either the package does not exist anymore, or the code creating this object contains an error.', $packageKey, $packagePath), 1166631890);
97 }
98 if (substr($packagePath, -1, 1) !== '/') {
99 throw new Exception\InvalidPackagePathException(sprintf('The package path "%s" provided for package "%s" has no trailing forward slash.', $packagePath, $packageKey), 1166633722);
100 }
101 $this->packageManager = $packageManager;
102 $this->packageKey = $packageKey;
103 $this->packagePath = $packagePath;
104 $this->composerManifest = $packageManager->getComposerManifest($this->packagePath);
105 $this->loadFlagsFromComposerManifest();
106 }
107
108 /**
109 * Loads package management related flags from the "extra:typo3/cms:Package" section
110 * of extensions composer.json files into local properties
111 */
112 protected function loadFlagsFromComposerManifest()
113 {
114 $extraFlags = $this->getValueFromComposerManifest('extra');
115 if ($extraFlags !== null && isset($extraFlags->{'typo3/cms'}->{'Package'})) {
116 foreach ($extraFlags->{'typo3/cms'}->{'Package'} as $flagName => $flagValue) {
117 if (property_exists($this, $flagName)) {
118 $this->{$flagName} = $flagValue;
119 }
120 }
121 }
122 }
123
124 /**
125 * @return bool
126 */
127 public function isPartOfFactoryDefault()
128 {
129 return $this->partOfFactoryDefault;
130 }
131
132 /**
133 * @return bool
134 */
135 public function isPartOfMinimalUsableSystem()
136 {
137 return $this->partOfMinimalUsableSystem;
138 }
139
140 /**
141 * Returns the package key of this package.
142 *
143 * @return string
144 * @api
145 */
146 public function getPackageKey()
147 {
148 return $this->packageKey;
149 }
150
151 /**
152 * Tells if this package is protected and therefore cannot be deactivated or deleted
153 *
154 * @return bool
155 * @api
156 */
157 public function isProtected()
158 {
159 return $this->protected;
160 }
161
162 /**
163 * Sets the protection flag of the package
164 *
165 * @param bool $protected TRUE if the package should be protected, otherwise FALSE
166 * @api
167 */
168 public function setProtected($protected)
169 {
170 $this->protected = (bool)$protected;
171 }
172
173 /**
174 * Returns the full path to this package's main directory
175 *
176 * @return string Path to this package's main directory
177 * @api
178 */
179 public function getPackagePath()
180 {
181 return $this->packagePath;
182 }
183
184 /**
185 * Returns the package meta data object of this package.
186 *
187 * @return MetaData
188 */
189 public function getPackageMetaData()
190 {
191 if ($this->packageMetaData === null) {
192 $this->packageMetaData = new MetaData($this->getPackageKey());
193 $this->packageMetaData->setDescription($this->getValueFromComposerManifest('description'));
194 $this->packageMetaData->setVersion($this->getValueFromComposerManifest('version'));
195 $requirements = $this->getValueFromComposerManifest('require');
196 if ($requirements !== null) {
197 foreach ($requirements as $requirement => $version) {
198 $packageKey = $this->packageManager->getPackageKeyFromComposerName($requirement);
199 // dynamically migrate 'cms' dependency to 'core' dependency
200 // see also \TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility::convertDependenciesToObjects
201 if ($packageKey === 'cms') {
202 GeneralUtility::deprecationLog('Extension "' . $this->packageKey . '" defines a dependency on ext:cms, which has been removed. Please remove the dependency.');
203 $packageKey = 'core';
204 }
205 $constraint = new MetaData\PackageConstraint(MetaData::CONSTRAINT_TYPE_DEPENDS, $packageKey);
206 $this->packageMetaData->addConstraint($constraint);
207 }
208 }
209 $suggestions = $this->getValueFromComposerManifest('suggest');
210 if ($suggestions !== null) {
211 foreach ($suggestions as $suggestion => $version) {
212 $packageKey = $this->packageManager->getPackageKeyFromComposerName($suggestion);
213 $constraint = new MetaData\PackageConstraint(MetaData::CONSTRAINT_TYPE_SUGGESTS, $packageKey);
214 $this->packageMetaData->addConstraint($constraint);
215 }
216 }
217 }
218 return $this->packageMetaData;
219 }
220
221 /**
222 * Returns an array of packages this package replaces
223 *
224 * @return array
225 */
226 public function getPackageReplacementKeys()
227 {
228 // The cast to array is required since the manifest returns data with type mixed
229 return (array)$this->getValueFromComposerManifest('replace') ?: [];
230 }
231
232 /**
233 * Returns contents of Composer manifest - or part there of if a key is given.
234 *
235 * @param string $key Optional. Only return the part of the manifest indexed by 'key'
236 * @return mixed|null
237 * @see json_decode for return values
238 */
239 public function getValueFromComposerManifest($key = null)
240 {
241 if ($key === null) {
242 return $this->composerManifest;
243 }
244
245 if (isset($this->composerManifest->{$key})) {
246 $value = $this->composerManifest->{$key};
247 } else {
248 $value = null;
249 }
250 return $value;
251 }
252
253 /**
254 * Added by TYPO3 CMS
255 *
256 * The package caching serializes package objects.
257 * The package manager instance may not be serialized
258 * as a fresh instance is created upon every request.
259 *
260 * This method will be removed once the package is
261 * released of the package manager dependency.
262 *
263 * @return array
264 */
265 public function __sleep()
266 {
267 $properties = get_class_vars(get_class($this));
268 unset($properties['packageManager']);
269 return array_keys($properties);
270 }
271
272 /**
273 * Added by TYPO3 CMS
274 *
275 * The package caching deserializes package objects.
276 * A fresh package manager instance has to be set
277 * during bootstrapping.
278 *
279 * This method will be removed once the package is
280 * released of the package manager dependency.
281 */
282 public function __wakeup()
283 {
284 if (isset($GLOBALS['TYPO3_currentPackageManager'])) {
285 $this->packageManager = $GLOBALS['TYPO3_currentPackageManager'];
286 }
287 }
288 }