TYPO3 CMS  TYPO3_6-2
Package.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Package;
3 
4 /* *
5  * This script belongs to the TYPO3 Flow framework. *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License, either version 3 *
9  * of the License, or (at your option) any later version. *
10  * *
11  * The TYPO3 project - inspiring people to share! *
12  * */
13 
21 
22  const PATTERN_MATCH_EXTENSIONKEY = '/^[0-9a-z_-]+$/i';
23 
27  protected $extensionManagerConfiguration = array();
28 
32  protected $classAliases;
33 
37  protected $objectManagementEnabled = NULL;
38 
42  protected $ignoredClassNames = array();
43 
50  protected $partOfFactoryDefault = FALSE;
51 
58  protected $partOfMinimalUsableSystem = FALSE;
59 
73  if (!$packageManager->isPackageKeyValid($packageKey)) {
74  throw new \TYPO3\Flow\Package\Exception\InvalidPackageKeyException('"' . $packageKey . '" is not a valid package key.', 1217959511);
75  }
76  if (!(@is_dir($packagePath) || (\TYPO3\Flow\Utility\Files::is_link($packagePath) && is_dir(\TYPO3\Flow\Utility\Files::getNormalizedPath($packagePath))))) {
77  throw new \TYPO3\Flow\Package\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);
78  }
79  if (substr($packagePath, -1, 1) !== '/') {
80  throw new \TYPO3\Flow\Package\Exception\InvalidPackagePathException(sprintf('The package path "%s" provided for package "%s" has no trailing forward slash.', $packagePath, $packageKey), 1166633722);
81  }
82  if ($classesPath[1] === '/') {
83  throw new \TYPO3\Flow\Package\Exception\InvalidPackagePathException(sprintf('The package classes path provided for package "%s" has a leading forward slash.', $packageKey), 1334841321);
84  }
85  if (!@file_exists($packagePath . $manifestPath . 'ext_emconf.php')) {
86  throw new \TYPO3\Flow\Package\Exception\InvalidPackageManifestException(sprintf('No ext_emconf file found for package "%s". Please create one at "%sext_emconf.php".', $packageKey, $manifestPath), 1360403545);
87  }
88  $this->packageManager = $packageManager;
89  $this->manifestPath = $manifestPath;
90  $this->packageKey = $packageKey;
92  $this->classesPath = \TYPO3\Flow\Utility\Files::getNormalizedPath(\TYPO3\Flow\Utility\Files::concatenatePaths(array($this->packagePath, self::DIRECTORY_CLASSES)));
93  try {
94  $this->getComposerManifest();
95  } catch (\TYPO3\Flow\Package\Exception\MissingPackageManifestException $exception) {
96  $this->getExtensionEmconf($packageKey, $this->packagePath);
97  }
99  if ($this->objectManagementEnabled === NULL) {
100  $this->objectManagementEnabled = FALSE;
101  }
102  }
103 
110  protected function loadFlagsFromComposerManifest() {
111  $extraFlags = $this->getComposerManifest('extra');
112  if ($extraFlags !== NULL && isset($extraFlags->{"typo3/cms"}->{"Package"})) {
113  foreach ($extraFlags->{"typo3/cms"}->{"Package"} as $flagName => $flagValue) {
114  if (property_exists($this, $flagName)) {
115  $this->{$flagName} = $flagValue;
116  }
117  }
118  }
119  }
120 
124  public function isPartOfFactoryDefault() {
126  }
127 
131  public function isPartOfMinimalUsableSystem() {
133  }
134 
138  protected function getExtensionEmconf() {
139  $_EXTKEY = $this->packageKey;
140  $path = $this->packagePath . '/ext_emconf.php';
141  $EM_CONF = NULL;
142  if (@file_exists($path)) {
143  include $path;
144  if (is_array($EM_CONF[$_EXTKEY])) {
145  $this->extensionManagerConfiguration = $EM_CONF[$_EXTKEY];
147  }
148  }
149  return FALSE;
150  }
151 
156  if (is_array($this->extensionManagerConfiguration)) {
158  $composerManifest = $this->composerManifest = new \stdClass();
159  $composerManifest->name = $this->getPackageKey();
160  $composerManifest->type = 'typo3-cms-extension';
161  $composerManifest->description = $extensionManagerConfiguration['title'];
163  if (isset($extensionManagerConfiguration['constraints']['depends']) && is_array($extensionManagerConfiguration['constraints']['depends'])) {
164  $composerManifest->require = new \stdClass();
165  foreach ($extensionManagerConfiguration['constraints']['depends'] as $requiredPackageKey => $requiredPackageVersion) {
166  if (!empty($requiredPackageKey)) {
167  $composerManifest->require->$requiredPackageKey = $requiredPackageVersion;
168  } else {
169  // TODO: throw meaningful exception or fail silently?
170  }
171  }
172  }
173  if (isset($extensionManagerConfiguration['constraints']['conflicts']) && is_array($extensionManagerConfiguration['constraints']['conflicts'])) {
174  $composerManifest->conflict = new \stdClass();
175  foreach ($extensionManagerConfiguration['constraints']['conflicts'] as $conflictingPackageKey => $conflictingPackageVersion) {
176  if (!empty($conflictingPackageKey)) {
177  $composerManifest->conflict->$conflictingPackageKey = $conflictingPackageVersion;
178  } else {
179  // TODO: throw meaningful exception or fail silently?
180  }
181  }
182  }
183  if (isset($extensionManagerConfiguration['constraints']['suggests']) && is_array($extensionManagerConfiguration['constraints']['suggests'])) {
184  $composerManifest->suggest = new \stdClass();
185  foreach ($extensionManagerConfiguration['constraints']['suggests'] as $suggestedPackageKey => $suggestedPackageVersion) {
186  if (!empty($suggestedPackageKey)) {
187  $composerManifest->suggest->$suggestedPackageKey = $suggestedPackageVersion;
188  } else {
189  // TODO: throw meaningful exception or fail silently?
190  }
191  }
192  }
193  }
194  }
195 
201  public function getPackageMetaData() {
202  if ($this->packageMetaData === NULL) {
203  parent::getPackageMetaData();
204 
205  // Fallback to retrieve the version number from ext_emconf.php
206  // in case no version was found in the composer.json manifest.
207  $version = $this->packageMetaData->getVersion();
208  if (empty($version)) {
209  $_EXTKEY = $this->packageKey; // required to resolve $EM_CONF[$_EXTKEY] in ext_emconf.php
210  $path = $this->packagePath . 'ext_emconf.php';
211  if (@file_exists($path)) {
212  include $path;
213  if (isset($EM_CONF[$_EXTKEY]['version'])) {
214  $this->packageMetaData->setVersion($EM_CONF[$_EXTKEY]['version']);
215  }
216  }
217  }
218 
219  $suggestions = $this->getComposerManifest('suggest');
220  if ($suggestions !== NULL) {
221  foreach ($suggestions as $suggestion => $version) {
222  if ($this->packageRequirementIsComposerPackage($suggestion) === FALSE) {
223  // Skip non-package requirements
224  continue;
225  }
226  $packageKey = $this->packageManager->getPackageKeyFromComposerName($suggestion);
227  $constraint = new \TYPO3\Flow\Package\MetaData\PackageConstraint(\TYPO3\Flow\Package\MetaDataInterface::CONSTRAINT_TYPE_SUGGESTS, $packageKey);
228  $this->packageMetaData->addConstraint($constraint);
229  }
230  }
231  }
232  return $this->packageMetaData;
233  }
234 
238  public function getPackageReplacementKeys() {
239  // The cast to array is required since the manifest returns data with type mixed
240  return (array)$this->getComposerManifest('replace') ?: array();
241  }
242 
249  public function getNamespace() {
250  if(!$this->namespace) {
251  $manifest = $this->getComposerManifest();
252  if (isset($manifest->autoload->{'psr-0'})) {
253  $namespaces = $manifest->autoload->{'psr-0'};
254  if (count($namespaces) === 1) {
255  $this->namespace = key($namespaces);
256  } else {
257  throw new \TYPO3\Flow\Package\Exception\InvalidPackageStateException(sprintf('The Composer manifest of package "%s" contains multiple namespace definitions in its autoload section but Flow does only support one namespace per package.', $this->packageKey), 1348053246);
258  }
259  } else {
260  $packageKey = $this->getPackageKey();
261  if (strpos($packageKey, '.') === FALSE) {
262  // Old school with unknown vendor name
263  $this->namespace = '*\\' . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($packageKey);
264  } else {
265  $this->namespace = str_replace('.', '\\', $packageKey);
266  }
267  }
268  }
269  return $this->namespace;
270  }
271 
275  public function getClassFiles() {
276  if (!is_array($this->classFiles)) {
277  $this->classFiles = $this->filterClassFiles($this->buildArrayOfClassFiles($this->classesPath . '/', $this->namespace . '\\'));
278  }
279  return $this->classFiles;
280  }
281 
286  protected function filterClassFiles(array $classFiles) {
287  $classesNotMatchingClassRule = array_filter(array_keys($classFiles), function($className) {
288  return preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\\\x7f-\xff]*$/', $className) !== 1;
289  });
290  foreach ($classesNotMatchingClassRule as $forbiddenClassName) {
291  unset($classFiles[$forbiddenClassName]);
292  }
293  foreach ($this->ignoredClassNames as $ignoredClassName) {
294  if (isset($classFiles[$ignoredClassName])) {
295  unset($classFiles[$ignoredClassName]);
296  }
297  }
298  return $classFiles;
299  }
300 
304  public function getClassFilesFromAutoloadRegistry() {
305  $autoloadRegistryPath = $this->packagePath . 'ext_autoload.php';
306  if (@file_exists($autoloadRegistryPath)) {
307  return require $autoloadRegistryPath;
308  }
309  return array();
310  }
311 
315  public function getClassAliases() {
316  if (!is_array($this->classAliases)) {
317  try {
318  $extensionClassAliasMapPathAndFilename = \TYPO3\Flow\Utility\Files::concatenatePaths(array(
319  $this->getPackagePath(),
320  'Migrations/Code/ClassAliasMap.php'
321  ));
322  if (@file_exists($extensionClassAliasMapPathAndFilename)) {
323  $this->classAliases = require $extensionClassAliasMapPathAndFilename;
324  }
325  } catch (\BadFunctionCallException $e) {
326  }
327  if (!is_array($this->classAliases)) {
328  $this->classAliases = array();
329  }
330  }
331  return $this->classAliases;
332  }
333 
340  protected function packageRequirementIsComposerPackage($requirement) {
341  // According to http://getcomposer.org/doc/02-libraries.md#platform-packages
342  // the following regex should capture all non composer requirements.
343  // typo3 is included in the list because it's a meta package and not supported for now.
344  // typo3/cms is included since it's basically a container and cannot be detected at runtime.
345  // composer/installers is included until extensionmanager can handle composer packages natively
346  return preg_match('/^(php(-64bit)?|ext-[^\/]+|lib-(curl|iconv|libxml|openssl|pcre|uuid|xsl)|typo3|typo3\/cms|composer\/installers)$/', $requirement) !== 1;
347  }
348 
349 
350 }
mapExtensionManagerConfigurationToComposerManifest()
Definition: Package.php:155
static getNormalizedPath($path)
Definition: Files.php:41
packageRequirementIsComposerPackage($requirement)
Definition: Package.php:340
static is_link($pathAndFilename)
Definition: Files.php:277
static concatenatePaths(array $paths)
Definition: Files.php:55
getComposerManifest($key=NULL)
Definition: Package.php:384
$EM_CONF[$_EXTKEY]
Definition: ext_emconf.php:2
__construct(\TYPO3\Flow\Package\PackageManager $packageManager, $packageKey, $packagePath, $classesPath=NULL, $manifestPath='')
Definition: Package.php:72