/** * @return void */ protected function writeComposerManifest() { $composerJsonFilename = Files::concatenatePaths(array($this->targetPackageData['path'], 'composer.json')); if (file_exists($composerJsonFilename)) { return; } $manifest = array(); $nameParts = explode('.', $this->targetPackageData['packageKey']); $vendor = array_shift($nameParts); $manifest['name'] = strtolower($vendor . '/' . implode('-', $nameParts)); switch ($this->targetPackageData['category']) { case 'Application': $manifest['type'] = 'typo3-flow-package'; break; default: $manifest['type'] = strtolower('typo3-flow-' . $this->targetPackageData['category']); } $manifest['description'] = $this->targetPackageData['meta']['description']; $manifest['version'] = $this->targetPackageData['meta']['version']; $manifest['require'] = array('typo3/flow' => '*'); $manifest['autoload'] = array('psr-0' => array(str_replace('.', '\\', $this->targetPackageData['packageKey']) => 'Classes')); if (defined('JSON_PRETTY_PRINT')) { file_put_contents($composerJsonFilename, json_encode($manifest, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } else { file_put_contents($composerJsonFilename, json_encode($manifest)); } }
/** * 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]; }
/** * @param Thumbnail $thumbnail * @return void * @throws Exception\NoThumbnailAvailableException */ public function refresh(Thumbnail $thumbnail) { $temporaryPathAndFilename = null; try { $filename = pathinfo($thumbnail->getOriginalAsset()->getResource()->getFilename(), PATHINFO_FILENAME); $temporaryLocalCopyFilename = $thumbnail->getOriginalAsset()->getResource()->createTemporaryLocalCopy(); $temporaryPathAndFilename = $this->environment->getPathToTemporaryDirectory() . uniqid('ProcessedFontThumbnail-') . '.' . $filename . '.jpg'; $width = 1000; $height = 1000; $im = imagecreate($width, $height); $red = imagecolorallocate($im, 0xff, 0xff, 0xff); $black = imagecolorallocate($im, 0x0, 0x0, 0x0); imagefilledrectangle($im, 0, 0, $width, $height, $red); imagefttext($im, 48, 0, 80, 150, $black, $temporaryLocalCopyFilename, 'Neos Font Preview'); imagefttext($im, 32, 0, 80, 280, $black, $temporaryLocalCopyFilename, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); imagefttext($im, 32, 0, 80, 360, $black, $temporaryLocalCopyFilename, 'abcdefghijklmopqrstuvwxyz'); imagefttext($im, 32, 0, 80, 440, $black, $temporaryLocalCopyFilename, '1234567890'); imagefttext($im, 32, 0, 80, 560, $black, $temporaryLocalCopyFilename, '+ " * ç % & / ( ) = ? @ €'); imagejpeg($im, $temporaryPathAndFilename); $resource = $this->resourceManager->importResource($temporaryPathAndFilename); $processedImageInfo = $this->resize($thumbnail, $resource); $thumbnail->setResource($processedImageInfo['resource']); $thumbnail->setWidth($processedImageInfo['width']); $thumbnail->setHeight($processedImageInfo['height']); Files::unlink($temporaryPathAndFilename); } catch (\Exception $exception) { Files::unlink($temporaryPathAndFilename); $filename = $thumbnail->getOriginalAsset()->getResource()->getFilename(); $sha1 = $thumbnail->getOriginalAsset()->getResource()->getSha1(); $message = sprintf('Unable to generate thumbnail for the given font (filename: %s, SHA1: %s)', $filename, $sha1); throw new Exception\NoThumbnailAvailableException($message, 1433109653, $exception); } }
/** * @test */ public function getPathToTemporaryDirectoryReturnsAnExistingPath() { $environment = new Environment(new ApplicationContext('Testing')); $environment->setTemporaryDirectoryBase(Files::concatenatePaths([sys_get_temp_dir(), 'FlowEnvironmentTest'])); $path = $environment->getPathToTemporaryDirectory(); $this->assertTrue(file_exists($path), 'The temporary path does not exist.'); }
/** * Builds a temporary directory to work on. * @return void */ protected function prepareTemporaryDirectory() { $this->temporaryDirectory = Files::concatenatePaths(array(FLOW_PATH_DATA, 'Temporary', 'Testing', str_replace('\\', '_', __CLASS__))); if (!file_exists($this->temporaryDirectory)) { Files::createDirectoryRecursively($this->temporaryDirectory); } }
/** * Add a warning for each HTML file that uses one of the f:uri.* or the f:format.json ViewHelpers * * @param string $packagePath * @return void */ protected function addWarningsForAffectedViewHelpers($packagePath) { $foundAffectedViewHelpers = array(); $allPathsAndFilenames = Files::readDirectoryRecursively($packagePath, null, true); foreach ($allPathsAndFilenames as $pathAndFilename) { $pathInfo = pathinfo($pathAndFilename); if (!isset($pathInfo['filename']) || $pathInfo['extension'] !== 'html') { continue; } $fileContents = file_get_contents($pathAndFilename); preg_match_all('/f\\:(uri\\.[\\w]+|format\\.json)/', $fileContents, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $viewHelperName = $match[1]; if (!isset($foundAffectedViewHelpers[$viewHelperName])) { $foundAffectedViewHelpers[$viewHelperName] = array(); } $truncatedPathAndFilename = substr($pathAndFilename, strlen($packagePath) + 1); if (!in_array($truncatedPathAndFilename, $foundAffectedViewHelpers[$viewHelperName])) { $foundAffectedViewHelpers[$viewHelperName][] = $truncatedPathAndFilename; } } } foreach ($foundAffectedViewHelpers as $viewHelperName => $filePathsAndNames) { $this->showWarning(sprintf('The behavior of the "%s" ViewHelper has been changed to produce escaped output.' . chr(10) . 'This package makes use of this ViewHelper in the following files:' . chr(10) . '- %s' . chr(10) . 'See upgrading instructions for further details.' . chr(10), $viewHelperName, implode(chr(10) . '- ', $filePathsAndNames))); } }
/** * @test */ public function modelIsReturnedCorrectlyForLocaleImplicatingChaining() { $localeImplementingChaining = new I18n\Locale('de_DE'); $cldrModel = $this->cldrRepository->getModelForLocale($localeImplementingChaining); $this->assertAttributeContains(Files::concatenatePaths([$this->cldrBasePath, 'main/root.xml']), 'sourcePaths', $cldrModel); $this->assertAttributeContains(Files::concatenatePaths([$this->cldrBasePath, 'main/de_DE.xml']), 'sourcePaths', $cldrModel); $this->assertAttributeContains(Files::concatenatePaths([$this->cldrBasePath, 'main/de.xml']), 'sourcePaths', $cldrModel); }
/** * @test */ public function importTemporaryFileSkipsFilesThatAlreadyExist() { $mockTempFile = vfsStream::newFile('SomeTemporaryFile', 0333)->withContent('fixture')->at($this->mockDirectory); $finalTargetPathAndFilename = $this->writableFileSystemStorage->_call('getStoragePathAndFilenameByHash', sha1('fixture')); Files::createDirectoryRecursively(dirname($finalTargetPathAndFilename)); file_put_contents($finalTargetPathAndFilename, 'existing file'); $this->writableFileSystemStorage->_call('importTemporaryFile', $mockTempFile->url(), 'default'); $this->assertSame('existing file', file_get_contents($finalTargetPathAndFilename)); }
/** * Applies htmlspecialchars() on the specified value. * * @param array $arguments * @param \Closure $renderChildrenClosure * @param \TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface $renderingContext * @return string */ public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) { $value = $arguments['value']; if ($value === null) { $value = $renderChildrenClosure(); } if (!is_integer($value) && !is_float($value)) { if (is_numeric($value)) { $value = (double) $value; } else { $value = 0; } } return Files::bytesToSizeString($value, $arguments['decimals'], $arguments['decimalSeparator'], $arguments['thousandsSeparator']); }
/** * @return void */ public function up() { $affectedFiles = array(); foreach (Files::getRecursiveDirectoryGenerator($this->targetPackageData['path'], null, true) as $pathAndFilename) { if (substr($pathAndFilename, -13) !== 'Converter.php') { continue; } $fileContents = file_get_contents($pathAndFilename); if (preg_match('/public\\s+function\\s+canConvertFrom\\s*\\(/', $fileContents) === 1) { $affectedFiles[] = substr($pathAndFilename, strlen($this->targetPackageData['path']) + 1); } } if ($affectedFiles !== array()) { $this->showWarning('Following TypeConverters implement the canConvertFrom() method. The element type of the $targetType argument is no longer cut off, so it might be "array<Some/Element/Type>" instead of just "array" for example. Make sure that this is not an issue or add' . PHP_EOL . ' $targetType = TypeHandling::truncateElementType($targetType);' . PHP_EOL . 'to the beginning of this method body if you\'re not sure:' . PHP_EOL . PHP_EOL . '* ' . implode(PHP_EOL . '* ', $affectedFiles)); } }
public function up() { $affectedFiles = array(); $allPathsAndFilenames = Files::readDirectoryRecursively($this->targetPackageData['path'], null, true); foreach ($allPathsAndFilenames as $pathAndFilename) { if (substr($pathAndFilename, -14) !== 'ViewHelper.php') { continue; } $fileContents = file_get_contents($pathAndFilename); if (preg_match('/\\$this->reflectionService/', $fileContents) === 1) { $affectedFiles[] = substr($pathAndFilename, strlen($this->targetPackageData['path']) + 1); } } if ($affectedFiles !== array()) { $this->showWarning('Following ViewHelpers might use a removed ReflectionService dependency from AbstractViewHelper, please inject a ReflectionService instance yourself:' . PHP_EOL . PHP_EOL . '* ' . implode(PHP_EOL . '* ', $affectedFiles)); } }
/** * Will return an array with all available packages. * * The data for each entry will be an array with the key, full path to * the package (index 'path') and a category (the packages subfolder, * index 'category'). The array is indexed by package key. * * @param string $packagesPath * @return array */ public static function getPackagesData($packagesPath) { $packagesData = array(); $packagesDirectoryIterator = new \DirectoryIterator($packagesPath); foreach ($packagesDirectoryIterator as $categoryFileInfo) { $category = $categoryFileInfo->getFilename(); if (!$categoryFileInfo->isDir() || $category[0] === '.' || $category === 'Libraries') { continue; } $categoryDirectoryIterator = new \DirectoryIterator($categoryFileInfo->getPathname()); foreach ($categoryDirectoryIterator as $packageFileInfo) { $packageKey = $packageFileInfo->getFilename(); if (!$packageFileInfo->isDir() || $packageKey[0] === '.') { continue; } $meta = self::readPackageMetaData(Files::concatenatePaths(array($packageFileInfo->getPathname(), 'Meta/Package.xml'))); $composerManifest = self::readComposerManifest(Files::concatenatePaths(array($packageFileInfo->getPathname(), 'composer.json'))); $packagesData[$packageKey] = array('packageKey' => $packageKey, 'category' => $category, 'path' => $packageFileInfo->getPathname(), 'meta' => $meta, 'composerManifest' => $composerManifest); } } return $packagesData; }
/** * @param Schema $schema * @return void */ public function up(Schema $schema) { $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); $resourcesResult = $this->connection->executeQuery('SELECT persistence_object_identifier, sha1, filename FROM typo3_flow_resource_resource'); while ($resourceInfo = $resourcesResult->fetch(\PDO::FETCH_ASSOC)) { $resourcePathAndFilename = FLOW_PATH_DATA . 'Persistent/Resources/' . wordwrap($resourceInfo['sha1'], 5, '/', true) . '/' . $resourceInfo['sha1']; $newResourcePathAndFilename = FLOW_PATH_DATA . 'Persistent/Resources/' . $resourceInfo['sha1'][0] . '/' . $resourceInfo['sha1'][1] . '/' . $resourceInfo['sha1'][2] . '/' . $resourceInfo['sha1'][3] . '/' . $resourceInfo['sha1']; if (!file_exists($newResourcePathAndFilename)) { if (!file_exists($resourcePathAndFilename)) { $this->write(sprintf('<warning>Could not move the data file of resource "%s" from its legacy location at "%s" to the correct location "%s" because the source file does not exist.', $resourceInfo['sha1'], $resourcePathAndFilename, $newResourcePathAndFilename)); continue; } if (!file_exists(dirname($newResourcePathAndFilename))) { Files::createDirectoryRecursively(dirname($newResourcePathAndFilename)); } if (@rename($resourcePathAndFilename, $newResourcePathAndFilename) === false) { $this->write(sprintf('<warning>Could not move the data file of resource "%s" from its legacy location at "%s" to the correct location "%s".', $resourceInfo['sha1'], $resourcePathAndFilename, $newResourcePathAndFilename)); } Files::removeEmptyDirectoriesOnPath(dirname($resourcePathAndFilename)); } } }
/** * Reads all Policy.yaml files below Packages, extracts the roles and prepends * them with the package key "guessed" from the path. * * @return array */ protected function loadRolesFromPolicyFiles() { $roles = array(); $yamlPathsAndFilenames = Files::readDirectoryRecursively(__DIR__ . '/../../../../../Packages', 'yaml', true); $configurationPathsAndFilenames = array_filter($yamlPathsAndFilenames, function ($pathAndFileName) { if (basename($pathAndFileName) === 'Policy.yaml') { return true; } else { return false; } }); $yamlSource = new \Neos\Flow\Configuration\Source\YamlSource(); foreach ($configurationPathsAndFilenames as $pathAndFilename) { if (preg_match('%Packages/.+/([^/]+)/Configuration/(?:Development|Production|Policy).+%', $pathAndFilename, $matches) === 0) { continue; } $packageKey = $matches[1]; $configuration = $yamlSource->load(substr($pathAndFilename, 0, -5)); if (isset($configuration['roles']) && is_array($configuration['roles'])) { foreach ($configuration['roles'] as $roleIdentifier => $parentRoles) { $roles[$packageKey . ':' . $roleIdentifier] = true; } } } return array_keys($roles); }
/** * Flushes all registered caches * * @param boolean $flushPersistentCaches If set to TRUE, even those caches which are flagged as "persistent" will be flushed * @return void * @api */ public function flushCaches($flushPersistentCaches = false) { $this->createAllCaches(); /** @var FrontendInterface $cache */ foreach ($this->caches as $identifier => $cache) { if (!$flushPersistentCaches && $this->isCachePersistent($identifier)) { continue; } $cache->flush(); } $this->configurationManager->flushConfigurationCache(); $dataTemporaryPath = $this->environment->getPathToTemporaryDirectory(); Files::unlink($dataTemporaryPath . 'AvailableProxyClasses.php'); }
/** * Generate additional folders for site packages. * * @param string $packageKey */ protected function generateAdditionalFolders($packageKey) { $resourcesPath = $this->packageManager->getPackage($packageKey)->getResourcesPath(); $publicResourcesPath = Files::concatenatePaths(array($resourcesPath, 'Public')); foreach (array('Images', 'JavaScript', 'Styles') as $publicResourceFolder) { Files::createDirectoryRecursively(Files::concatenatePaths(array($publicResourcesPath, $publicResourceFolder))); } }
/** * @test */ public function detectChangesDetectsDeletedFilesOfMonitoredDirectoriesIfPatternIsMatched() { $testPath = vfsStream::url('testDirectory'); // Initially known files per path $knownDirectoriesAndFiles = [Files::getNormalizedPath($testPath) => [$testPath . '/NodeTypes.foo.yaml' => 1]]; // Outcome of the change dection per file $changeDetectionResult = [$testPath . '/NodeTypes.foo.yaml' => ChangeDetectionStrategyInterface::STATUS_DELETED]; // Expected emitted changes for files $expectedEmittedChanges = [$testPath . '/NodeTypes.foo.yaml' => ChangeDetectionStrategyInterface::STATUS_DELETED]; $fileMonitor = $this->setUpFileMonitorForDetection($changeDetectionResult, $expectedEmittedChanges, $knownDirectoriesAndFiles); $fileMonitor->monitorDirectory($testPath, 'NodeTypes(\\..+)?\\.yaml'); $fileMonitor->detectChanges(); }
/** * @param string $autoloadType * @param string $autoloadNamespace * @param string $autoloadPath * @return string */ protected function normalizeAutoloadPath($autoloadType, $autoloadNamespace, $autoloadPath) { $normalizedAutoloadPath = $autoloadPath; if ($autoloadType === ClassLoader::MAPPING_TYPE_PSR0) { $normalizedAutoloadPath = Files::concatenatePaths([$autoloadPath, str_replace('\\', '/', $autoloadNamespace)]) . '/'; } if ($autoloadType === ClassLoader::MAPPING_TYPE_PSR4) { $normalizedAutoloadPath = rtrim($normalizedAutoloadPath, '/') . '/'; } return $normalizedAutoloadPath; }
/** * @throws Exception */ protected function configureCacheDirectory() { $cacheDirectory = $this->cacheDirectory; if ($cacheDirectory === '') { $codeOrData = $this->cache instanceof PhpFrontend ? 'Code' : 'Data'; $baseDirectory = $this->baseDirectory ?: $this->environmentConfiguration->getFileCacheBasePath(); $cacheDirectory = $baseDirectory . 'Cache/' . $codeOrData . '/' . $this->cacheIdentifier . '/'; } if (!is_writable($cacheDirectory)) { try { Files::createDirectoryRecursively($cacheDirectory); } catch (FilesException $exception) { throw new Exception('The cache directory "' . $cacheDirectory . '" could not be created.', 1264426237); } } if (!is_dir($cacheDirectory) && !is_link($cacheDirectory)) { throw new Exception('The cache directory "' . $cacheDirectory . '" does not exist.', 1203965199); } if (!is_writable($cacheDirectory)) { throw new Exception('The cache directory "' . $cacheDirectory . '" is not writable.', 1203965200); } $this->cacheDirectory = $cacheDirectory; }
/** * Reads the TypoScript file from the given path and filename. * If it doesn't exist, this function will just return an empty string. * * @param string $pathAndFilename Path and filename of the TypoScript file * @return string The content of the .fusion file, plus one chr(10) at the end */ protected function readExternalTypoScriptFile($pathAndFilename) { return is_file($pathAndFilename) ? Files::getFileContents($pathAndFilename) . chr(10) : ''; }
/** * Fetches the site with the given name and exports it as XML into the given file. * * @param array<Site> $sites * @param boolean $tidy Whether to export formatted XML * @param string $pathAndFilename Path to where the export output should be saved to * @param string $nodeTypeFilter Filter the node type of the nodes, allows complex expressions (e.g. "Neos.Neos:Page", "!Neos.Neos:Page,Neos.Neos:Text") * @return void */ public function exportToFile(array $sites, $tidy = false, $pathAndFilename, $nodeTypeFilter = null) { $this->resourcesPath = Files::concatenatePaths(array(dirname($pathAndFilename), 'Resources')); Files::createDirectoryRecursively($this->resourcesPath); $this->xmlWriter = new \XMLWriter(); $this->xmlWriter->openUri($pathAndFilename); $this->xmlWriter->setIndent($tidy); $this->exportSites($sites, $nodeTypeFilter); $this->xmlWriter->flush(); }
/** * @param PackageInterface $package * @return array */ protected function getPrimaryNamespaceAndEntryPath(PackageInterface $package) { $autoloadConfigurations = $package->getComposerManifest('autoload'); $firstAutoloadType = null; $firstAutoloadConfiguration = null; foreach ($autoloadConfigurations as $autoloadType => $autoloadConfiguration) { if (ClassLoader::isAutoloadTypeWithPredictableClassPath($autoloadType)) { $firstAutoloadType = $autoloadType; $firstAutoloadConfiguration = $autoloadConfiguration; break; } } $autoloadPaths = reset($firstAutoloadConfiguration); $firstAutoloadPath = is_array($autoloadPaths) ? reset($autoloadPaths) : $autoloadPaths; $namespace = key($firstAutoloadConfiguration); $autoloadPathPostfix = ''; if ($firstAutoloadType === ClassLoader::MAPPING_TYPE_PSR0) { $autoloadPathPostfix = str_replace('\\', '/', trim($namespace, '\\')); } return [$namespace, Files::concatenatePaths([$package->getPackagePath(), $firstAutoloadPath, $autoloadPathPostfix]), $firstAutoloadType]; }
/** * Removes the specified target file from the public directory * * This method fails silently if the given file could not be unpublished or already didn't exist anymore. * * @param string $relativeTargetPathAndFilename relative path and filename in the target directory * @return void */ protected function unpublishFile($relativeTargetPathAndFilename) { $targetPathAndFilename = $this->path . $relativeTargetPathAndFilename; if (!file_exists($targetPathAndFilename)) { return; } if (!Files::unlink($targetPathAndFilename)) { return; } Files::removeEmptyDirectoriesOnPath(dirname($targetPathAndFilename)); }
/** * Generate a new migration * * If $diffAgainstCurrent is TRUE (the default), it generates a migration file * with the diff between current DB structure and the found mapping metadata. * * Otherwise an empty migration skeleton is generated. * * Only includes tables/sequences matching the $filterExpression regexp when * diffing models and existing schema. Include delimiters in the expression! * The use of * * --filter-expression '/^acme_com/' * * would only create a migration touching tables starting with "acme_com". * * Note: A filter-expression will overrule any filter configured through the * Neos.Flow.persistence.doctrine.migrations.ignoredTables setting * * @param boolean $diffAgainstCurrent Whether to base the migration on the current schema structure * @param string $filterExpression Only include tables/sequences matching the filter expression regexp * @return void * @see neos.flow:doctrine:migrate * @see neos.flow:doctrine:migrationstatus * @see neos.flow:doctrine:migrationexecute * @see neos.flow:doctrine:migrationversion */ public function migrationGenerateCommand($diffAgainstCurrent = true, $filterExpression = null) { // "driver" is used only for Doctrine, thus we (mis-)use it here // additionally, when no host is set, skip this step, assuming no DB is needed if (!$this->isDatabaseConfigured()) { $this->outputLine('Doctrine migration generation has been SKIPPED, the driver and host backend options are not set in /Configuration/Settings.yaml.'); $this->quit(1); } // use default filter expression from settings if ($filterExpression === null) { $ignoredTables = array_keys(array_filter($this->settings['doctrine']['migrations']['ignoredTables'])); if ($ignoredTables !== array()) { $filterExpression = sprintf('/^(?!%s$).*$/xs', implode('$|', $ignoredTables)); } } list($status, $migrationClassPathAndFilename) = $this->doctrineService->generateMigration($diffAgainstCurrent, $filterExpression); $this->outputLine('<info>%s</info>', [$status]); $this->outputLine(); if ($migrationClassPathAndFilename) { $choices = ['Don\'t Move']; $packages = [null]; /** @var Package $package */ foreach ($this->packageManager->getAvailablePackages() as $package) { $type = $package->getComposerManifest('type'); if ($type === null || strpos($type, 'typo3-') !== 0 && strpos($type, 'neos-') !== 0) { continue; } $choices[] = $package->getPackageKey(); $packages[] = $package; } $selectedPackageIndex = (int) $this->output->select('Do you want to move the migration to one of these packages?', $choices, 0); $this->outputLine(); if ($selectedPackageIndex !== 0) { /** @var Package $selectedPackage */ $selectedPackage = $packages[$selectedPackageIndex]; $targetPathAndFilename = Files::concatenatePaths([$selectedPackage->getPackagePath(), 'Migrations', $this->doctrineService->getDatabasePlatformName(), basename($migrationClassPathAndFilename)]); Files::createDirectoryRecursively(dirname($targetPathAndFilename)); rename($migrationClassPathAndFilename, $targetPathAndFilename); $this->outputLine('The migration was moved to: <comment>%s</comment>', [substr($targetPathAndFilename, strlen(FLOW_PATH_PACKAGES))]); $this->outputLine(); $this->outputLine('Next Steps:'); } else { $this->outputLine('Next Steps:'); $this->outputLine(sprintf('- Move <comment>%s</comment> to YourPackage/<comment>Migrations/%s/</comment>', $migrationClassPathAndFilename, $this->doctrineService->getDatabasePlatformName())); } $this->outputLine('- Review and adjust the generated migration.'); $this->outputLine('- (optional) execute the migration using <comment>%s doctrine:migrate</comment>', [$this->getFlowInvocationString()]); } }
/** * Expands the given $patterns by adding an array element for each $replacement * replacing occurrences of $search. * * @param array $patterns * @param string $search * @param array $replacements * @return void */ protected function expandPatterns(array $patterns, $search, array $replacements) { if ($replacements === []) { return $patterns; } $patternsWithReplacements = []; foreach ($patterns as $pattern) { foreach ($replacements as $replacement) { $patternsWithReplacements[] = Files::getUnixStylePath(str_replace($search, $replacement, $pattern)); } } return $patternsWithReplacements; }
/** * Creates a dummy class file inside $package's path * and requires it for propagation * * @param PackageInterface $package * @return object The dummy object of the class which was created */ protected function createDummyObjectForPackage(PackageInterface $package) { $namespaces = $package->getNamespaces(); $dummyClassName = 'Someclass' . md5(uniqid(mt_rand(), true)); $fullyQualifiedClassName = '\\' . reset($namespaces) . '\\' . $dummyClassName; $dummyClassFilePath = Files::concatenatePaths([$package->getPackagePath(), PackageInterface::DIRECTORY_CLASSES, $dummyClassName . '.php']); file_put_contents($dummyClassFilePath, '<?php namespace ' . reset($namespaces) . '; class ' . $dummyClassName . ' {}'); require $dummyClassFilePath; return new $fullyQualifiedClassName(); }
/** * Applies all registered moveFile operations. * * @return void */ protected function applyFileOperations() { foreach ($this->operations['moveFile'] as $operation) { $oldPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); $newPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[1])); if (substr($oldPath, -1) === '*') { $oldPath = substr($oldPath, 0, -1); if (!file_exists($oldPath)) { continue; } if (!file_exists($newPath)) { Files::createDirectoryRecursively($newPath); } if (!is_dir($newPath)) { continue; } foreach (Files::getRecursiveDirectoryGenerator($this->targetPackageData['path'], null, true) as $pathAndFilename) { if (substr_compare($pathAndFilename, $oldPath, 0, strlen($oldPath)) === 0) { $relativePathAndFilename = substr($pathAndFilename, strlen($oldPath)); if (!is_dir(dirname(Files::concatenatePaths(array($newPath, $relativePathAndFilename))))) { Files::createDirectoryRecursively(dirname(Files::concatenatePaths(array($newPath, $relativePathAndFilename)))); } Git::move($pathAndFilename, Files::concatenatePaths(array($newPath, $relativePathAndFilename))); } } } else { $oldPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); $newPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[1])); Git::move($oldPath, $newPath); } } foreach ($this->operations['deleteFile'] as $operation) { $filename = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); if (file_exists($filename)) { Git::remove($filename); } } }
/** * Returns a XliffModel instance representing desired XLIFF file. * * Will return existing instance if a model for given $sourceName was already * requested before. Returns FALSE when $sourceName doesn't point to existing * file. * * @param string $packageKey Key of the package containing the source file * @param string $sourceName Relative path to existing CLDR file * @param I18n\Locale $locale Locale object * @return XliffModel New or existing instance * @throws I18n\Exception */ protected function getModel($packageKey, $sourceName, I18n\Locale $locale) { $sourcePath = Files::concatenatePaths(['resource://' . $packageKey, $this->xliffBasePath]); list($sourcePath, $foundLocale) = $this->localizationService->getXliffFilenameAndPath($sourcePath, $sourceName, $locale); if ($sourcePath === false) { throw new I18n\Exception('No XLIFF file is available for ' . $packageKey . '::' . $sourceName . '::' . $locale . ' in the locale chain.', 1334759591); } if (isset($this->models[$sourcePath])) { return $this->models[$sourcePath]; } return $this->models[$sourcePath] = new XliffModel($sourcePath, $foundLocale); }
/** * Check write permissions for folders used for writing files * * @return mixed */ protected function checkFilePermissions() { foreach ($this->requiredWritableFolders as $folder) { $folderPath = FLOW_PATH_ROOT . $folder; if (!is_dir($folderPath) && !\Neos\Utility\Files::is_link($folderPath)) { try { \Neos\Utility\Files::createDirectoryRecursively($folderPath); } catch (\Neos\Flow\Utility\Exception $exception) { return new Error('Unable to create folder "%s". Check your file permissions (did you use flow:core:setfilepermissions?).', 1330363887, [$folderPath]); } } if (!is_writable($folderPath)) { return new Error('The folder "%s" is not writable. Check your file permissions (did you use flow:core:setfilepermissions?)', 1330372964, [$folderPath]); } } return null; }
/** * Saves the current configuration into a cache file and creates a cache inclusion script * in the context's Configuration directory. * * @return void * @throws Exception */ protected function saveConfigurationCache() { // Make sure that all configuration types are loaded before writing configuration caches. foreach (array_keys($this->configurationTypes) as $configurationType) { $this->getConfiguration($configurationType); } if ($this->temporaryDirectoryPath === null) { return; } $cachePathAndFilename = $this->constructConfigurationCachePath(); if (!file_exists(dirname($cachePathAndFilename))) { Files::createDirectoryRecursively(dirname($cachePathAndFilename)); } file_put_contents($cachePathAndFilename, '<?php return ' . var_export($this->configurations, true) . ';'); OpcodeCacheHelper::clearAllActive($cachePathAndFilename); }