/** */ public function setUp() { ComposerUtility::flushCaches(); vfsStream::setup('Packages'); $this->mockPackageManager = $this->getMockBuilder(\Neos\Flow\Package\PackageManager::class)->disableOriginalConstructor()->getMock(); ObjectAccess::setProperty($this->mockPackageManager, 'composerManifestData', array(), true); }
/** * Detects if the package contains a package file and returns the path and classname. * * @param string $packageKey The package key * @param string $absolutePackagePath Absolute path to the package * @return array The path to the package file and classname for this package or an empty array if none was found. * @throws Exception\CorruptPackageException * @throws Exception\InvalidPackagePathException */ public function detectFlowPackageFilePath($packageKey, $absolutePackagePath) { if (!is_dir($absolutePackagePath)) { throw new Exception\InvalidPackagePathException(sprintf('The given package path "%s" is not a readable directory.', $absolutePackagePath), 1445904440); } $composerManifest = ComposerUtility::getComposerManifest($absolutePackagePath); if (!ComposerUtility::isFlowPackageType(isset($composerManifest['type']) ? $composerManifest['type'] : '')) { return []; } $possiblePackageClassPaths = [Files::concatenatePaths(['Classes', 'Package.php']), Files::concatenatePaths(['Classes', str_replace('.', '/', $packageKey), 'Package.php'])]; $foundPackageClassPaths = array_filter($possiblePackageClassPaths, function ($packageClassPathAndFilename) use($absolutePackagePath) { $absolutePackageClassPath = Files::concatenatePaths([$absolutePackagePath, $packageClassPathAndFilename]); return is_file($absolutePackageClassPath); }); if ($foundPackageClassPaths === []) { return []; } if (count($foundPackageClassPaths) > 1) { throw new Exception\CorruptPackageException(sprintf('The package "%s" contains multiple possible "Package.php" files. Please make sure that only one "Package.php" exists in the autoload root(s) of your Flow package.', $packageKey), 1457454840); } $packageClassPathAndFilename = reset($foundPackageClassPaths); $absolutePackageClassPath = Files::concatenatePaths([$absolutePackagePath, $packageClassPathAndFilename]); $packageClassContents = file_get_contents($absolutePackageClassPath); $packageClassName = (new PhpAnalyzer($packageClassContents))->extractFullyQualifiedClassName(); if ($packageClassName === null) { throw new Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class.', $packageKey, $packageClassPathAndFilename), 1327587091); } return ['className' => $packageClassName, 'pathAndFilename' => $packageClassPathAndFilename]; }
/** * Create a new package * * This command creates a new package which contains only the mandatory * directories and files. * * @Flow\FlushesCaches * @param string $packageKey The package key of the package to create * @param string $packageType The package type of the package to create * @return string * @see neos.kickstarter:kickstart:package */ public function createCommand($packageKey, $packageType = PackageInterface::DEFAULT_COMPOSER_TYPE) { if (!$this->packageManager->isPackageKeyValid($packageKey)) { $this->outputLine('The package key "%s" is not valid.', [$packageKey]); $this->quit(1); } if ($this->packageManager->isPackageAvailable($packageKey)) { $this->outputLine('The package "%s" already exists.', [$packageKey]); $this->quit(1); } if (!ComposerUtility::isFlowPackageType($packageType)) { $this->outputLine('The package must be a Flow package, but "%s" is not a valid Flow package type.', [$packageType]); $this->quit(1); } $package = $this->packageManager->createPackage($packageKey, ['type' => $packageType], null); $this->outputLine('Created new package "' . $packageKey . '" at "' . $package->getPackagePath() . '".'); }
/** * Returns contents of Composer manifest - or part there of. * * @param string $key Optional. Only return the part of the manifest indexed by 'key' * @return array|mixed * @api */ public function getComposerManifest($key = null) { return ComposerUtility::getComposerManifest($this->packagePath, $key); }
/** * @test */ public function packageStatesConfigurationContainsRelativePaths() { $packageKeys = ['RobertLemke.Flow.NothingElse' . md5(uniqid(mt_rand(), true)), 'Neos.Flow' . md5(uniqid(mt_rand(), true)), 'TYPO3.YetAnotherTestPackage' . md5(uniqid(mt_rand(), true))]; foreach ($packageKeys as $packageKey) { $packagePath = 'vfs://Test/Packages/Application/' . $packageKey . '/'; mkdir($packagePath, 0770, true); mkdir($packagePath . 'Classes'); ComposerUtility::writeComposerManifest($packagePath, $packageKey, ['type' => 'flow-test', 'autoload' => []]); } $packageManager = $this->getAccessibleMock(PackageManager::class, ['updateShortcuts', 'emitPackageStatesUpdated'], [], '', false); $packageManager->_set('packagesBasePath', 'vfs://Test/Packages/'); $packageManager->_set('packageStatesPathAndFilename', 'vfs://Test/Configuration/PackageStates.php'); $packageFactory = new PackageFactory($packageManager); $this->inject($packageManager, 'packageFactory', $packageFactory); $packageManager->_set('packages', []); $actualPackageStatesConfiguration = $packageManager->rescanPackages(); $expectedPackageStatesConfiguration = []; foreach ($packageKeys as $packageKey) { $composerName = ComposerUtility::getComposerPackageNameFromPackageKey($packageKey); $expectedPackageStatesConfiguration[$composerName] = ['state' => 'active', 'packagePath' => 'Application/' . $packageKey . '/', 'composerName' => $composerName, 'packageClassInformation' => [], 'packageKey' => $packageKey, 'autoloadConfiguration' => []]; } $this->assertEquals($expectedPackageStatesConfiguration, $actualPackageStatesConfiguration['packages']); }
/** * Traverses through all class files of the active packages and registers collects the class names as * "all available class names". If the respective Flow settings say so, also function test classes * are registered. * * For performance reasons this function ignores classes whose name ends with "Exception". * * @param array $packages A list of packages to consider * @return array A list of class names which were discovered in the given packages * * @throws InvalidConfigurationTypeException */ protected function registerClassFiles(array $packages) { $includeClassesConfiguration = []; if (isset($this->allSettings['Neos']['Flow']['object']['includeClasses'])) { if (!is_array($this->allSettings['Neos']['Flow']['object']['includeClasses'])) { throw new InvalidConfigurationTypeException('The setting "Neos.Flow.object.includeClasses" is invalid, it must be an array if set. Check the syntax in the YAML file.', 1422357285); } $includeClassesConfiguration = $this->allSettings['Neos']['Flow']['object']['includeClasses']; } $availableClassNames = ['' => ['DateTime']]; /** @var \Neos\Flow\Package\Package $package */ foreach ($packages as $packageKey => $package) { if ($package->isObjectManagementEnabled() && (ComposerUtility::isFlowPackageType($package->getComposerManifest('type')) || isset($includeClassesConfiguration[$packageKey]))) { foreach ($package->getClassFiles() as $fullClassName => $path) { if (substr($fullClassName, -9, 9) !== 'Exception') { $availableClassNames[$packageKey][] = $fullClassName; } } if (isset($this->allSettings['Neos']['Flow']['object']['registerFunctionalTestClasses']) && $this->allSettings['Neos']['Flow']['object']['registerFunctionalTestClasses'] === true) { foreach ($package->getFunctionalTestsClassFiles() as $fullClassName => $path) { if (substr($fullClassName, -9, 9) !== 'Exception') { $availableClassNames[$packageKey][] = $fullClassName; } } } if (isset($availableClassNames[$packageKey]) && is_array($availableClassNames[$packageKey])) { $availableClassNames[$packageKey] = array_unique($availableClassNames[$packageKey]); } } } return $this->filterClassNamesFromConfiguration($availableClassNames, $includeClassesConfiguration); }
/** * Derive a flow package key from the given information. * The order of importance is: * * - package install path * - first found autoload namespace * - composer name * * @param string $composerName * @param string $packageType * @param string $packagePath * @param string $autoloadNamespace * @return string */ protected function derivePackageKey($composerName, $packageType = null, $packagePath = null, $autoloadNamespace = null) { $packageKey = ''; if ($packageType !== null && ComposerUtility::isFlowPackageType($packageType)) { $lastSegmentOfPackagePath = substr(trim($packagePath, '/'), strrpos(trim($packagePath, '/'), '/') + 1); if (strpos($lastSegmentOfPackagePath, '.') !== false) { $packageKey = $lastSegmentOfPackagePath; } } if ($autoloadNamespace !== null && ($packageKey === null || $this->isPackageKeyValid($packageKey) === false)) { $packageKey = str_replace('\\', '.', $autoloadNamespace); } if ($packageKey === null || $this->isPackageKeyValid($packageKey) === false) { $packageKey = str_replace('/', '.', $composerName); } $packageKey = trim($packageKey, '.'); $packageKey = preg_replace('/[^A-Za-z0-9.]/', '', $packageKey); return $packageKey; }