/** * Returns a package instance. * * @param string $packagesBasePath the base install path of packages, * @param string $packagePath path to package, relative to base path * @param string $packageKey key / name of the package * @param string $classesPath path to the classes directory, relative to the package path * @param string $manifestPath path to the package's Composer manifest, relative to package path, defaults to same path * @return \TYPO3\Flow\Package\PackageInterface * @throws \TYPO3\Flow\Package\Exception\CorruptPackageException */ public function create($packagesBasePath, $packagePath, $packageKey, $classesPath, $manifestPath = '') { $packagePath = Files::getNormalizedPath(Files::concatenatePaths(array($packagesBasePath, $packagePath))); $packageClassPathAndFilename = Files::concatenatePaths(array($packagePath, 'Classes/' . str_replace('.', '/', $packageKey) . '/Package.php')); $alternativeClassPathAndFilename = Files::concatenatePaths(array($packagePath, 'Classes/Package.php')); $packageClassPathAndFilename = @file_exists($alternativeClassPathAndFilename) ? $alternativeClassPathAndFilename : $packageClassPathAndFilename; if (@file_exists($packageClassPathAndFilename)) { require_once $packageClassPathAndFilename; if (substr($packagePath, 0, strlen(PATH_typo3)) === PATH_typo3 && strpos($packageKey, '.') === FALSE) { //TODO Remove this exception once the systextension are renamed to proper Flow naming scheme packages $packageClassName = 'TYPO3\\CMS\\' . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($packageKey) . '\\Package'; } else { $packageClassName = str_replace('.', '\\', $packageKey) . '\\Package'; } if (!class_exists($packageClassName, FALSE)) { throw new \TYPO3\Flow\Package\Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class called "%s".', $packageKey, $packageClassPathAndFilename, $packageClassName), 1327587092); } } else { $emConfPath = Files::concatenatePaths(array($packagePath, 'ext_emconf.php')); $packageClassName = @file_exists($emConfPath) ? 'TYPO3\\CMS\\Core\\Package\\Package' : 'TYPO3\\Flow\\Package\\Package'; } /** @var $package \TYPO3\Flow\Package\PackageInterface */ $package = new $packageClassName($this->packageManager, $packageKey, $packagePath, $classesPath, $manifestPath); return $package; }
/** * Constructor * * @param \TYPO3\Flow\Package\PackageManager $packageManager the package manager which knows this package * @param string $packageKey Key of this package * @param string $packagePath Absolute path to the location of the package's composer manifest * @param string $classesPath Path the classes of the package are in, relative to $packagePath. Optional, read from Composer manifest if not set. * @param string $manifestPath Path the composer manifest of the package, relative to $packagePath. Optional, defaults to ''. * @throws \TYPO3\Flow\Package\Exception\InvalidPackageKeyException if an invalid package key was passed * @throws \TYPO3\Flow\Package\Exception\InvalidPackagePathException if an invalid package path was passed * @throws \TYPO3\Flow\Package\Exception\InvalidPackageManifestException if no composer manifest file could be found */ public function __construct(\TYPO3\Flow\Package\PackageManager $packageManager, $packageKey, $packagePath, $classesPath = NULL, $manifestPath = '') { if (!\TYPO3\CMS\Core\Package\PackageManager::isPackageKeyValid($packageKey)) { throw new \TYPO3\Flow\Package\Exception\InvalidPackageKeyException('"' . $packageKey . '" is not a valid package key.', 1217959511); } if (!(@is_dir($packagePath) || \TYPO3\Flow\Utility\Files::is_link($packagePath) && is_dir(\TYPO3\Flow\Utility\Files::getNormalizedPath($packagePath)))) { 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); } if (substr($packagePath, -1, 1) !== '/') { throw new \TYPO3\Flow\Package\Exception\InvalidPackagePathException(sprintf('The package path "%s" provided for package "%s" has no trailing forward slash.', $packagePath, $packageKey), 1166633722); } if ($classesPath[1] === '/') { throw new \TYPO3\Flow\Package\Exception\InvalidPackagePathException(sprintf('The package classes path provided for package "%s" has a leading forward slash.', $packageKey), 1334841321); } if (!@file_exists($packagePath . $manifestPath . 'ext_emconf.php')) { 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); } $this->packageManager = $packageManager; $this->manifestPath = $manifestPath; $this->packageKey = $packageKey; $this->packagePath = \TYPO3\Flow\Utility\Files::getNormalizedPath($packagePath); $this->classesPath = \TYPO3\Flow\Utility\Files::getNormalizedPath(\TYPO3\Flow\Utility\Files::concatenatePaths(array($this->packagePath, self::DIRECTORY_CLASSES))); try { $this->getComposerManifest(); } catch (\TYPO3\Flow\Package\Exception\MissingPackageManifestException $exception) { $this->getExtensionEmconf($packageKey, $this->packagePath); } $this->loadFlagsFromComposerManifest(); if ($this->objectManagementEnabled === NULL) { $this->objectManagementEnabled = FALSE; } }
/** * @param string $filename * @return string * @throws \TYPO3\Flow\Utility\Exception */ public function getDocumentAbsolutePath($filename = null) { $path = str_replace('\\', '/', get_called_class()); $documentAbsolutePath = $this->temporaryDirectoryBase . $path . '/'; Files::createDirectoryRecursively($documentAbsolutePath); return Files::getNormalizedPath($documentAbsolutePath) . $filename; }
/** * Return the json array for a given locale, sourceCatalog, xliffPath and package. * The json will be cached. * * @param Locale $locale The locale * @return Result * @throws Exception */ public function getCachedJson(Locale $locale) { $cacheIdentifier = md5($locale); if ($this->xliffToJsonTranslationsCache->has($cacheIdentifier)) { $json = $this->xliffToJsonTranslationsCache->get($cacheIdentifier); } else { $labels = []; $localeChain = $this->localizationService->getLocaleChain($locale); foreach ($this->packagesRegisteredForAutoInclusion as $packageKey => $sourcesToBeIncluded) { if (!is_array($sourcesToBeIncluded)) { continue; } $translationBasePath = Files::concatenatePaths([$this->packageManager->getPackage($packageKey)->getResourcesPath(), $this->xliffBasePath]); // We merge labels in the chain from the worst choice to best choice foreach (array_reverse($localeChain) as $allowedLocale) { $localeSourcePath = Files::getNormalizedPath(Files::concatenatePaths([$translationBasePath, $allowedLocale])); foreach ($sourcesToBeIncluded as $sourceName) { foreach (glob($localeSourcePath . $sourceName . '.xlf') as $xliffPathAndFilename) { $xliffPathInfo = pathinfo($xliffPathAndFilename); $sourceName = str_replace($localeSourcePath, '', $xliffPathInfo['dirname'] . '/' . $xliffPathInfo['filename']); $labels = Arrays::arrayMergeRecursiveOverrule($labels, $this->parseXliffToArray($xliffPathAndFilename, $packageKey, $sourceName)); } } } } $json = json_encode($labels); $this->xliffToJsonTranslationsCache->set($cacheIdentifier, $json); } return $json; }
/** * Collects the manifest data for all packages in the given package states array * * @param array $packageStates * @return array */ protected function collectPackageManifestData(array $packageStates) { return array_map(function ($packageState) { return ComposerUtility::getComposerManifest(Files::getNormalizedPath(Files::concatenatePaths([$this->packagesBasePath, $packageState['packagePath']]))); }, $packageStates['packages']); }
/** * Returns the full path to the package's classes namespace entry path, * e.g. "My.Package/ClassesPath/My/Package/" * * @return string Path to this package's Classes directory * @api */ public function getClassesNamespaceEntryPath() { $pathifiedNamespace = str_replace('\\', '/', $this->getNamespace()); return Files::getNormalizedPath($this->classesPath . trim($pathifiedNamespace, '/')); }
/** * Tries to remove a possibly existing namespace to class path map entry. * * @param string $namespace A namespace mapped to a class path. * @param string $classPath The class path to be removed. * @param string $mappingType The mapping type for this mapping entry. Currently one of self::MAPPING_TYPE_PSR0 or self::MAPPING_TYPE_PSR4 will work. Defaults to self::MAPPING_TYPE_PSR0 * @return void */ protected function removeNamespaceMapEntry($namespace, $classPath, $mappingType = self::MAPPING_TYPE_PSR0) { $unifiedClassPath = Files::getNormalizedPath($classPath); $entryIdentifier = md5($unifiedClassPath . '-' . $mappingType); $currentArray =& $this->packageNamespaces; foreach (explode('\\', rtrim($namespace, '\\')) as $namespacePart) { if (!isset($currentArray[$namespacePart])) { return; } $currentArray =& $currentArray[$namespacePart]; } if (!isset($currentArray['_pathData'])) { return; } if (isset($currentArray['_pathData'][$entryIdentifier])) { unset($currentArray['_pathData'][$entryIdentifier]); if (empty($currentArray['_pathData'])) { unset($currentArray['_pathData']); } } }
/** * Constructor * * @param string $packageKey Key of this package * @param string $composerName * @param string $packagePath Absolute path to the location of the package's composer manifest * @param array $autoloadConfiguration * @throws Exception\InvalidPackageKeyException */ public function __construct($packageKey, $composerName, $packagePath, array $autoloadConfiguration = []) { $this->autoloadConfiguration = $autoloadConfiguration; $this->packagePath = Files::getNormalizedPath($packagePath); $this->packageKey = $packageKey; $this->composerName = $composerName; }
/** * @test */ public function detectChangesDetectsDeletedFilesOfMonitoredDirectoriesIfPatternIsMatched() { $testPath = vfsStream::url('testDirectory'); // Initially known files per path $knownDirectoriesAndFiles = array(Files::getNormalizedPath($testPath) => array($testPath . '/NodeTypes.foo.yaml' => 1)); // Outcome of the change dection per file $changeDetectionResult = array($testPath . '/NodeTypes.foo.yaml' => ChangeDetectionStrategyInterface::STATUS_DELETED); // Expected emitted changes for files $expectedEmittedChanges = array($testPath . '/NodeTypes.foo.yaml' => ChangeDetectionStrategyInterface::STATUS_DELETED); $fileMonitor = $this->setUpFileMonitorForDetection($changeDetectionResult, $expectedEmittedChanges, $knownDirectoriesAndFiles); $fileMonitor->monitorDirectory($testPath, 'NodeTypes(\\..+)?\\.yaml'); $fileMonitor->detectChanges(); }
/** * Finds all Locale objects representing locales available in the * Flow installation. This is done by scanning all Private and Public * resource files of all active packages, in order to find localized files. * * Localized files have a locale identifier added before their extension * (or at the end of filename, if no extension exists). For example, a * localized file for foobar.png, can be foobar.en.png, fobar.en_GB.png, etc. * * Just one localized resource file causes the corresponding locale to be * regarded as available (installed, supported). * * Note: result of this method invocation is cached * * @return void */ protected function generateAvailableLocalesCollectionByScanningFilesystem() { $whitelistPaths = array_keys(array_filter((array) $this->settings['scan']['includePaths'])); if ($whitelistPaths === []) { return; } $blacklistPattern = $this->getScanBlacklistPattern(); /** @var PackageInterface $activePackage */ foreach ($this->packageManager->getActivePackages() as $activePackage) { $packageResourcesPath = Files::getNormalizedPath($activePackage->getResourcesPath()); if (!is_dir($packageResourcesPath)) { continue; } $directories = []; foreach ($whitelistPaths as $path) { $scanPath = Files::concatenatePaths(array($packageResourcesPath, $path)); if (is_dir($scanPath)) { array_push($directories, Files::getNormalizedPath($scanPath)); } } while ($directories !== []) { $currentDirectory = array_pop($directories); $relativeDirectory = '/' . str_replace($packageResourcesPath, '', $currentDirectory); if ($blacklistPattern !== '' && preg_match($blacklistPattern, $relativeDirectory) === 1) { continue; } if ($handle = opendir($currentDirectory)) { while (false !== ($filename = readdir($handle))) { if ($filename[0] === '.') { continue; } $pathAndFilename = Files::concatenatePaths(array($currentDirectory, $filename)); if (is_dir($pathAndFilename)) { array_push($directories, Files::getNormalizedPath($pathAndFilename)); } else { $localeIdentifier = Utility::extractLocaleTagFromFilename($filename); if ($localeIdentifier !== false) { $this->localeCollection->addLocale(new Locale($localeIdentifier)); } } } closedir($handle); } } } }
/** * Read a monitored directory recursively, taking into account filename patterns * * @param string $path The path of a monitored directory * @param string $filenamePattern * @return \Generator<string> A generator returning filenames with full path */ protected function readMonitoredDirectoryRecursively($path, $filenamePattern) { $directories = array(Files::getNormalizedPath($path)); while ($directories !== array()) { $currentDirectory = array_pop($directories); if (is_file($currentDirectory . '.flowFileMonitorIgnore')) { continue; } if ($handle = opendir($currentDirectory)) { while (false !== ($filename = readdir($handle))) { if ($filename[0] === '.') { continue; } $pathAndFilename = $currentDirectory . $filename; if (is_dir($pathAndFilename)) { array_push($directories, $pathAndFilename . DIRECTORY_SEPARATOR); } elseif ($filenamePattern === null || preg_match('|' . $filenamePattern . '|', $filename) === 1) { (yield $pathAndFilename); } } closedir($handle); } } }
private function getNamespaceBaseDirectory($packageKey) { $package = $this->packageManager->getPackage($packageKey); if ($package->getAutoloadType() === Package::AUTOLOADER_TYPE_PSR4) { // WORKAROUND to support PSR4 properly return Files::getNormalizedPath($package->getClassesPath()); } else { return $package->getClassesNamespaceEntryPath(); } }
/** * @param string $jobIdentifier * @param string $path */ public function deleteAction($jobIdentifier, $path) { /** @var DocumentJobTrait $jobConfiguration */ $jobConfiguration = $this->jobConfigurationRepository->findOneByIdentifier($jobIdentifier); $dirname = Files::getNormalizedPath(Files::getUnixStylePath(dirname($path))); if ($jobConfiguration->getDocumentAbsolutePath() !== $dirname) { $this->addFlashMessage(sprintf('The current job (%s) path does not match the requested path (%s)', $jobIdentifier, $path), '', Message::SEVERITY_ERROR); $this->redirect('downloadCenter', null, null, ['jobIdentifier' => $jobIdentifier]); } unlink($path); $this->redirect('downloadCenter', null, null, ['jobIdentifier' => $jobIdentifier]); }
/** * Finds all Locale objects representing locales available in the * Flow installation. This is done by scanning all Private and Public * resource files of all active packages, in order to find localized files. * * Localized files have a locale identifier added before their extension * (or at the end of filename, if no extension exists). For example, a * localized file for foobar.png, can be foobar.en.png, fobar.en_GB.png, etc. * * Just one localized resource file causes the corresponding locale to be * regarded as available (installed, supported). * * Note: result of this method invocation is cached * * @return void */ protected function generateAvailableLocalesCollectionByScanningFilesystem() { /** @var PackageInterface $activePackage */ foreach ($this->packageManager->getActivePackages() as $activePackage) { $packageResourcesPath = $activePackage->getResourcesPath(); if (!is_dir($packageResourcesPath)) { continue; } $directories = array(Files::getNormalizedPath($packageResourcesPath)); while ($directories !== array()) { $currentDirectory = array_pop($directories); if ($handle = opendir($currentDirectory)) { while (false !== ($filename = readdir($handle))) { if ($filename[0] === '.') { continue; } $pathAndFilename = Files::concatenatePaths(array($currentDirectory, $filename)); if (is_dir($pathAndFilename)) { array_push($directories, Files::getNormalizedPath($pathAndFilename)); } else { $localeIdentifier = Utility::extractLocaleTagFromFilename($filename); if ($localeIdentifier !== false) { $this->localeCollection->addLocale(new Locale($localeIdentifier)); } } } closedir($handle); } } } }
/** * Gets the directory for package where .SQL file will be stored * * @param string $packageKey * @param bool $createDirectoryStructure * @return string * @throws \TYPO3\Flow\Utility\Exception */ protected function getContentDirectoryForPackageKey($packageKey, $createDirectoryStructure = FALSE) { $resourcesPath = $this->packageManager->getPackage($packageKey)->getResourcesPath(); $dir = Files::concatenatePaths(array($resourcesPath, 'Private/Content/')); if ($createDirectoryStructure) { Files::createDirectoryRecursively($dir); } return Files::getNormalizedPath($dir); }