/** * 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); } }
/** * Move resource files to the new locations and adjust records. * * @param Schema $schema * @return void */ public function postUp(Schema $schema) { $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/' . $resourceInfo['sha1']; $newResourcePathAndFilename = FLOW_PATH_DATA . 'Persistent/Resources/' . $resourceInfo['sha1'][0] . '/' . $resourceInfo['sha1'][1] . '/' . $resourceInfo['sha1'][2] . '/' . $resourceInfo['sha1'][3] . '/' . $resourceInfo['sha1']; $mediaType = MediaTypes::getMediaTypeFromFilename($resourceInfo['filename']); if (file_exists($resourcePathAndFilename)) { $md5 = md5_file($resourcePathAndFilename); $filesize = filesize($resourcePathAndFilename); if (!file_exists(dirname($newResourcePathAndFilename))) { Files::createDirectoryRecursively(dirname($newResourcePathAndFilename)); } $result = @rename($resourcePathAndFilename, $newResourcePathAndFilename); } elseif (file_exists($newResourcePathAndFilename)) { $md5 = md5_file($newResourcePathAndFilename); $filesize = filesize($newResourcePathAndFilename); $result = true; } else { $this->write(sprintf('Error while migrating database for the new resource management: the resource file "%s" (original filename: %s) was not found, but the resource object with uuid %s needs this file.', $resourcePathAndFilename, $resourceInfo['filename'], $resourceInfo['persistence_object_identifier'])); continue; } $this->connection->executeUpdate('UPDATE typo3_flow_resource_resource SET collectionname = ?, mediatype = ?, md5 = ?, filesize = ? WHERE persistence_object_identifier = ?', array('persistent', $mediaType, $md5, $filesize, $resourceInfo['persistence_object_identifier'])); if ($result === false) { $this->write(sprintf('Could not move the data file of resource "%s" from its legacy location at %s to the correct location %s.', $resourceInfo['sha1'], $resourcePathAndFilename, $newResourcePathAndFilename)); } } $this->connection->exec('ALTER TABLE typo3_flow_resource_resource ALTER md5 SET NOT NULL'); $this->connection->exec('ALTER TABLE typo3_flow_resource_resource ALTER collectionname SET NOT NULL'); $this->connection->exec('ALTER TABLE typo3_flow_resource_resource ALTER mediatype SET NOT NULL'); $this->connection->exec('ALTER TABLE typo3_flow_resource_resource ALTER filesize SET NOT NULL'); }
/** * @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)); }
/** * @param array $settings */ public function injectSettings(array $settings) { if (isset($settings['yamlPersistenceManager']['savePath'])) { $this->savePath = $settings['yamlPersistenceManager']['savePath']; if (!is_dir($this->savePath)) { \Neos\Utility\Files::createDirectoryRecursively($this->savePath); } } }
/** * Make sure required paths and files are available outside of Package * Run on every Composer install or update - must be configured in root manifest * * @param Event $event * @return void */ public static function postUpdateAndInstall(Event $event) { if (!defined('FLOW_PATH_ROOT')) { define('FLOW_PATH_ROOT', Files::getUnixStylePath(getcwd()) . '/'); } if (!defined('FLOW_PATH_PACKAGES')) { define('FLOW_PATH_PACKAGES', Files::getUnixStylePath(getcwd()) . '/Packages/'); } if (!defined('FLOW_PATH_CONFIGURATION')) { define('FLOW_PATH_CONFIGURATION', Files::getUnixStylePath(getcwd()) . '/Configuration/'); } Files::createDirectoryRecursively('Configuration'); Files::createDirectoryRecursively('Data'); Files::copyDirectoryRecursively('Packages/Framework/Neos.Flow/Resources/Private/Installer/Distribution/Essentials', './', false, true); Files::copyDirectoryRecursively('Packages/Framework/Neos.Flow/Resources/Private/Installer/Distribution/Defaults', './', true, true); $packageManager = new PackageManager(); $packageManager->rescanPackages(); chmod('flow', 0755); }
/** * @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)); } } }
/** * Connect to the database * * @return void * @throws Exception if the connection cannot be established */ protected function connect() { if ($this->databaseHandle !== null) { return; } try { $splitdsn = explode(':', $this->dataSourceName, 2); $this->pdoDriver = $splitdsn[0]; if ($this->pdoDriver === 'sqlite' && !file_exists($splitdsn[1])) { if (!file_exists(dirname($splitdsn[1]))) { Files::createDirectoryRecursively(dirname($splitdsn[1])); } $this->databaseHandle = new \PDO($this->dataSourceName, $this->username, $this->password); $this->createCacheTables(); } else { $this->databaseHandle = new \PDO($this->dataSourceName, $this->username, $this->password); } $this->databaseHandle->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); if ($this->pdoDriver === 'mysql') { $this->databaseHandle->exec('SET SESSION sql_mode=\'ANSI\';'); } } catch (\PDOException $exception) { throw new Exception('Could not connect to cache table with DSN "' . $this->dataSourceName . '". PDO error: ' . $exception->getMessage(), 1334736164); } }
/** * 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) { if (!isset($this->configurations[$configurationType]) || !is_array($this->configurations[$configurationType])) { $this->loadConfiguration($configurationType, $this->packages); } } if ($this->temporaryDirectoryPath === null) { return; } $cachePathAndFilename = $this->constructConfigurationCachePath(); if (!file_exists(dirname($cachePathAndFilename))) { Files::createDirectoryRecursively(dirname($cachePathAndFilename)); } file_put_contents($cachePathAndFilename, '<?php return ' . $this->replaceVariablesInPhpString(var_export($this->unprocessedConfiguration, true)) . ';'); OpcodeCacheHelper::clearAllActive($cachePathAndFilename); $this->cacheNeedsUpdate = false; }
/** * Publishes the given source stream to this target, with the given relative path. * * @param resource $sourceStream Stream of the source to publish * @param string $relativeTargetPathAndFilename relative path and filename in the target directory * @return void * @throws TargetException */ protected function publishFile($sourceStream, $relativeTargetPathAndFilename) { $pathInfo = UnicodeFunctions::pathinfo($relativeTargetPathAndFilename); if (isset($pathInfo['extension']) && array_key_exists(strtolower($pathInfo['extension']), $this->extensionBlacklist) && $this->extensionBlacklist[strtolower($pathInfo['extension'])] === true) { throw new TargetException(sprintf('Could not publish "%s" into resource publishing target "%s" because the filename extension "%s" is blacklisted.', $sourceStream, $this->name, strtolower($pathInfo['extension'])), 1447148472); } $targetPathAndFilename = $this->path . $relativeTargetPathAndFilename; if (@fstat($sourceStream) === false) { throw new TargetException(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file is not accessible (file stat failed).', $sourceStream, $this->name), 1375258499); } if (!file_exists(dirname($targetPathAndFilename))) { Files::createDirectoryRecursively(dirname($targetPathAndFilename)); } if (!is_writable(dirname($targetPathAndFilename))) { throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the target file "%s" is not writable.', $sourceStream, $this->name, $targetPathAndFilename), 1428917322, isset($exception) ? $exception : null); } try { $targetFileHandle = fopen($targetPathAndFilename, 'w'); $result = stream_copy_to_stream($sourceStream, $targetFileHandle); fclose($targetFileHandle); } catch (\Exception $exception) { $result = false; } if ($result === false) { throw new TargetException(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file could not be copied to the target location.', $sourceStream, $this->name), 1375258399, isset($exception) ? $exception : null); } $this->systemLogger->log(sprintf('FileSystemTarget: Published file. (target: %s, file: %s)', $this->name, $relativeTargetPathAndFilename), LOG_DEBUG); }
/** * Returns the path to a local file representing this resource for use with read-only file operations such as reading or copying. * * Note that you must not store or publish file paths returned from this method as they will change with every request. * * @return string Absolute path and filename pointing to the temporary local copy of this resource * @throws Exception * @api */ public function createTemporaryLocalCopy() { if ($this->temporaryLocalCopyPathAndFilename === null) { $temporaryPathAndFilename = $this->environment->getPathToTemporaryDirectory() . 'ResourceFiles/'; try { Utility\Files::createDirectoryRecursively($temporaryPathAndFilename); } catch (Utility\Exception $e) { throw new ResourceException(sprintf('Could not create the temporary directory %s while trying to create a temporary local copy of resource %s (%s).', $temporaryPathAndFilename, $this->sha1, $this->filename), 1416221864); } $temporaryPathAndFilename .= $this->getCacheEntryIdentifier(); $temporaryPathAndFilename .= '-' . microtime(true); if (function_exists('posix_getpid')) { $temporaryPathAndFilename .= '-' . str_pad(posix_getpid(), 10); } else { $temporaryPathAndFilename .= '-' . (string) getmypid(); } $temporaryPathAndFilename = trim($temporaryPathAndFilename); $temporaryFileHandle = fopen($temporaryPathAndFilename, 'w'); if ($temporaryFileHandle === false) { throw new ResourceException(sprintf('Could not create the temporary file %s while trying to create a temporary local copy of resource %s (%s).', $temporaryPathAndFilename, $this->sha1, $this->filename), 1416221864); } $resourceStream = $this->getStream(); if ($resourceStream === false) { throw new ResourceException(sprintf('Could not open stream for resource %s ("%s") from collection "%s" while trying to create a temporary local copy.', $this->sha1, $this->filename, $this->collectionName), 1416221863); } stream_copy_to_stream($resourceStream, $temporaryFileHandle); fclose($resourceStream); fclose($temporaryFileHandle); $this->temporaryLocalCopyPathAndFilename = $temporaryPathAndFilename; } return $this->temporaryLocalCopyPathAndFilename; }
/** * 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 Configuration $configuration * @param string $up * @param string $down * @return string * @throws \RuntimeException */ protected function writeMigrationClassToFile(Configuration $configuration, $up, $down) { $namespace = $configuration->getMigrationsNamespace(); $className = 'Version' . date('YmdHis'); $up = $up === null ? '' : "\n " . implode("\n ", explode("\n", $up)); $down = $down === null ? '' : "\n " . implode("\n ", explode("\n", $down)); $path = Files::concatenatePaths([$configuration->getMigrationsDirectory(), $className . '.php']); try { Files::createDirectoryRecursively(dirname($path)); } catch (Exception $exception) { throw new \RuntimeException(sprintf('Migration target directory "%s" does not exist.', dirname($path)), 1303298536, $exception); } $code = <<<EOT <?php namespace {$namespace}; use Doctrine\\DBAL\\Migrations\\AbstractMigration; use Doctrine\\DBAL\\Schema\\Schema; /** * Auto-generated Migration: Please modify to your needs! This block will be used as the migration description if getDescription() is not used. */ class {$className} extends AbstractMigration { /** * @return string */ public function getDescription() { return ''; } /** * @param Schema \$schema * @return void */ public function up(Schema \$schema) { // this up() migration is autogenerated, please modify it to your needs{$up} } /** * @param Schema \$schema * @return void */ public function down(Schema \$schema) { // this down() migration is autogenerated, please modify it to your needs{$down} } } EOT; file_put_contents($path, $code); return $path; }
/** * Creates Flow's temporary directory - or at least asserts that it exists and is * writable. * * For each Flow Application Context, we create an extra temporary folder, * and for nested contexts, the folders are prefixed with "SubContext" to * avoid ambiguity, and look like: Data/Temporary/Production/SubContextLive * * @param string $temporaryDirectoryBase Full path to the base for the temporary directory * @return string The full path to the temporary directory * @throws UtilityException if the temporary directory could not be created or is not writable */ protected function createTemporaryDirectory($temporaryDirectoryBase) { $temporaryDirectoryBase = Files::getUnixStylePath($temporaryDirectoryBase); if (substr($temporaryDirectoryBase, -1, 1) !== '/') { $temporaryDirectoryBase .= '/'; } $temporaryDirectory = $temporaryDirectoryBase . str_replace('/', '/SubContext', (string) $this->context) . '/'; if (!is_dir($temporaryDirectory) && !is_link($temporaryDirectory)) { try { Files::createDirectoryRecursively($temporaryDirectory); } catch (ErrorException $exception) { throw new UtilityException('The temporary directory "' . $temporaryDirectory . '" could not be created. Please make sure permissions are correct for this path or define another temporary directory in your Settings.yaml with the path "Neos.Flow.utility.environment.temporaryDirectoryBase".', 1335382361); } } if (!is_writable($temporaryDirectory)) { throw new UtilityException('The temporary directory "' . $temporaryDirectory . '" is not writable. Please make this directory writable or define another temporary directory in your Settings.yaml with the path "Neos.Flow.utility.environment.temporaryDirectoryBase".', 1216287176); } return $temporaryDirectory; }
/** * Factory method which creates an EntityManager. * * @return EntityManager * @throws InvalidConfigurationException */ public function create() { $config = new Configuration(); $config->setClassMetadataFactoryName(Mapping\ClassMetadataFactory::class); $this->applySecondLevelCacheSettingsToConfiguration($this->settings['doctrine']['secondLevelCache'], $config); $cache = new CacheAdapter(); // must use ObjectManager in compile phase... $cache->setCache($this->objectManager->get(CacheManager::class)->getCache('Flow_Persistence_Doctrine')); $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); $resultCache = new CacheAdapter(); // must use ObjectManager in compile phase... $resultCache->setCache($this->objectManager->get(CacheManager::class)->getCache('Flow_Persistence_Doctrine_Results')); $config->setResultCacheImpl($resultCache); if (is_string($this->settings['doctrine']['sqlLogger']) && class_exists($this->settings['doctrine']['sqlLogger'])) { $configuredSqlLogger = $this->settings['doctrine']['sqlLogger']; $sqlLoggerInstance = new $configuredSqlLogger(); if ($sqlLoggerInstance instanceof SQLLogger) { $config->setSQLLogger($sqlLoggerInstance); } else { throw new InvalidConfigurationException(sprintf('Neos.Flow.persistence.doctrine.sqlLogger must point to a \\Doctrine\\DBAL\\Logging\\SQLLogger implementation, %s given.', get_class($sqlLoggerInstance)), 1426150388); } } $eventManager = $this->buildEventManager(); $flowAnnotationDriver = $this->objectManager->get(FlowAnnotationDriver::class); $config->setMetadataDriverImpl($flowAnnotationDriver); $proxyDirectory = Files::concatenatePaths([$this->environment->getPathToTemporaryDirectory(), 'Doctrine/Proxies']); Files::createDirectoryRecursively($proxyDirectory); $config->setProxyDir($proxyDirectory); $config->setProxyNamespace('Neos\\Flow\\Persistence\\Doctrine\\Proxies'); $config->setAutoGenerateProxyClasses(false); // Set default host to 127.0.0.1 if there is no host configured but a dbname if (empty($this->settings['backendOptions']['host']) && !empty($this->settings['backendOptions']['dbname'])) { $this->settings['backendOptions']['host'] = '127.0.0.1'; } // The following code tries to connect first, if that succeeds, all is well. If not, the platform is fetched directly from the // driver - without version checks to the database server (to which no connection can be made) - and is added to the config // which is then used to create a new connection. This connection will then return the platform directly, without trying to // detect the version it runs on, which fails if no connection can be made. But the platform is used even if no connection can // be made, which was no problem with Doctrine DBAL 2.3. And then came version-aware drivers and platforms... $connection = DriverManager::getConnection($this->settings['backendOptions'], $config, $eventManager); try { $connection->connect(); } catch (ConnectionException $exception) { $settings = $this->settings['backendOptions']; $settings['platform'] = $connection->getDriver()->getDatabasePlatform(); $connection = DriverManager::getConnection($settings, $config, $eventManager); } $entityManager = EntityManager::create($connection, $config, $eventManager); $flowAnnotationDriver->setEntityManager($entityManager); if (isset($this->settings['doctrine']['dbal']['mappingTypes']) && is_array($this->settings['doctrine']['dbal']['mappingTypes'])) { foreach ($this->settings['doctrine']['dbal']['mappingTypes'] as $typeName => $typeConfiguration) { Type::addType($typeName, $typeConfiguration['className']); $entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping($typeConfiguration['dbType'], $typeName); } } if (isset($this->settings['doctrine']['filters']) && is_array($this->settings['doctrine']['filters'])) { foreach ($this->settings['doctrine']['filters'] as $filterName => $filterClass) { $config->addFilter($filterName, $filterClass); $entityManager->getFilters()->enable($filterName); } } if (isset($this->settings['doctrine']['dql']) && is_array($this->settings['doctrine']['dql'])) { $this->applyDqlSettingsToConfiguration($this->settings['doctrine']['dql'], $config); } return $entityManager; }
/** * Stores the current reflection data related to classes of the specified package * in the PrecompiledReflectionData directory for the current context. * * This method is used by the package manager. * * @param string $packageKey * @return void */ public function freezePackageReflection($packageKey) { if (!$this->initialized) { $this->initialize(); } $package = $this->packageManager->getPackage($packageKey); $packageNamespace = $package->getNamespace() . '\\'; $reflectionData = ['classReflectionData' => $this->classReflectionData, 'classSchemata' => $this->classSchemata, 'annotatedClasses' => $this->annotatedClasses, 'classesByMethodAnnotations' => $this->classesByMethodAnnotations]; $reflectionData['classReflectionData'] = $this->filterArrayByClassesInNamespace($reflectionData['classReflectionData'], $packageNamespace); $reflectionData['classSchemata'] = $this->filterArrayByClassesInNamespace($reflectionData['classSchemata'], $packageNamespace); $reflectionData['annotatedClasses'] = $this->filterArrayByClassesInNamespace($reflectionData['annotatedClasses'], $packageNamespace); $reflectionData['classesByMethodAnnotations'] = isset($reflectionData['classesByMethodAnnotations']) ? $reflectionData['classesByMethodAnnotations'] : []; $methodAnnotationsFilters = function ($className) use($packageNamespace) { return strpos($className, $packageNamespace) === 0; }; foreach ($reflectionData['classesByMethodAnnotations'] as $annotationClassName => $classNames) { $reflectionData['classesByMethodAnnotations'][$annotationClassName] = array_filter($classNames, $methodAnnotationsFilters); } $precompiledReflectionStoragePath = $this->getPrecompiledReflectionStoragePath(); if (!is_dir($precompiledReflectionStoragePath)) { Files::createDirectoryRecursively($precompiledReflectionStoragePath); } $pathAndFilename = $precompiledReflectionStoragePath . $packageKey . '.dat'; file_put_contents($pathAndFilename, extension_loaded('igbinary') ? igbinary_serialize($reflectionData) : serialize($reflectionData)); }
/** * Carries out all actions necessary to prepare the logging backend, such as opening * the log file or opening a database connection. * * @return void * @throws CouldNotOpenResourceException * @api */ public function open() { $this->severityLabels = [LOG_EMERG => 'EMERGENCY', LOG_ALERT => 'ALERT ', LOG_CRIT => 'CRITICAL ', LOG_ERR => 'ERROR ', LOG_WARNING => 'WARNING ', LOG_NOTICE => 'NOTICE ', LOG_INFO => 'INFO ', LOG_DEBUG => 'DEBUG ']; if (file_exists($this->logFileUrl) && $this->maximumLogFileSize > 0 && filesize($this->logFileUrl) > $this->maximumLogFileSize) { $this->rotateLogFile(); } if (file_exists($this->logFileUrl)) { $this->fileHandle = fopen($this->logFileUrl, 'ab'); } else { $logPath = dirname($this->logFileUrl); if (!file_exists($logPath) || !is_dir($logPath) && !is_link($logPath)) { if ($this->createParentDirectories === false) { throw new CouldNotOpenResourceException('Could not open log file "' . $this->logFileUrl . '" for write access because the parent directory does not exist.', 1243931200); } Files::createDirectoryRecursively($logPath); } $this->fileHandle = fopen($this->logFileUrl, 'ab'); if ($this->fileHandle === false) { throw new CouldNotOpenResourceException('Could not open log file "' . $this->logFileUrl . '" for write access.', 1243588980); } $streamMeta = stream_get_meta_data($this->fileHandle); if ($streamMeta['wrapper_type'] === 'plainfile') { fclose($this->fileHandle); chmod($this->logFileUrl, 0666); $this->fileHandle = fopen($this->logFileUrl, 'ab'); } } if ($this->fileHandle === false) { throw new CouldNotOpenResourceException('Could not open log file "' . $this->logFileUrl . '" for write access.', 1229448440); } }
/** * Sets the temporaryDirectory as static variable for the lock class. * * @param string $lockDirectory * @throws LockNotAcquiredException * return void */ protected function configureLockDirectory($lockDirectory) { Utility\Files::createDirectoryRecursively($lockDirectory); $this->temporaryDirectory = $lockDirectory; }
/** * Move a temporary file to the final destination, creating missing path segments on the way. * * @param string $temporaryFile * @param string $finalTargetPathAndFilename * @return void * @throws StorageException */ protected function moveTemporaryFileToFinalDestination($temporaryFile, $finalTargetPathAndFilename) { if (!file_exists(dirname($finalTargetPathAndFilename))) { Files::createDirectoryRecursively(dirname($finalTargetPathAndFilename)); } if (copy($temporaryFile, $finalTargetPathAndFilename) === false) { throw new StorageException(sprintf('The temporary file of the file import could not be moved to the final target "%s".', $finalTargetPathAndFilename), 1381156103); } unlink($temporaryFile); $this->fixFilePermissions($finalTargetPathAndFilename); }
/** * Publishes the specified directory to this target, with the given relative path. * * @param string $sourcePath Absolute path to the source directory * @param string $relativeTargetPathAndFilename relative path and filename in the target directory * @throws TargetException * @return void */ protected function publishDirectory($sourcePath, $relativeTargetPathAndFilename) { $targetPathAndFilename = $this->path . $relativeTargetPathAndFilename; if (@stat($sourcePath) === false) { throw new TargetException(sprintf('Could not publish directory "%s" into resource publishing target "%s" because the source is not accessible (file stat failed).', $sourcePath, $this->name), 1416244512); } if (!file_exists(dirname($targetPathAndFilename))) { Files::createDirectoryRecursively(dirname($targetPathAndFilename)); } try { if (Files::is_link($targetPathAndFilename)) { Files::unlink($targetPathAndFilename); } if ($this->relativeSymlinks) { $result = Files::createRelativeSymlink($sourcePath, $targetPathAndFilename); } else { $temporaryTargetPathAndFilename = uniqid($targetPathAndFilename . '.') . '.tmp'; symlink($sourcePath, $temporaryTargetPathAndFilename); $result = rename($temporaryTargetPathAndFilename, $targetPathAndFilename); } } catch (\Exception $exception) { $result = false; } if ($result === false) { throw new TargetException(sprintf('Could not publish "%s" into resource publishing target "%s" because the source directory could not be symlinked at target location.', $sourcePath, $this->name), 1416244515, isset($exception) ? $exception : null); } $this->systemLogger->log(sprintf('FileSystemSymlinkTarget: Published directory. (target: %s, file: %s)', $this->name, $relativeTargetPathAndFilename), LOG_DEBUG); }
/** * 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))); } }
/** * 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); }
/** * 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()]); } }
/** * @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; }
/** * @test */ public function copyDirectoryRecursivelyKeepsExistingTargetFilesIfRequested() { Files::createDirectoryRecursively('vfs://Foo/source/bar/baz'); file_put_contents('vfs://Foo/source/bar/baz/file.txt', 'source content'); Files::createDirectoryRecursively('vfs://Foo/target/bar/baz'); file_put_contents('vfs://Foo/target/bar/baz/file.txt', 'target content'); Files::copyDirectoryRecursively('vfs://Foo/source', 'vfs://Foo/target', true); $this->assertEquals('target content', file_get_contents('vfs://Foo/target/bar/baz/file.txt')); }
/** * Generate a file with the given content and add it to the * generated files * * @param string $targetPathAndFilename * @param string $fileContent * @param boolean $force * @return void */ protected function generateFile($targetPathAndFilename, $fileContent, $force = false) { if (!is_dir(dirname($targetPathAndFilename))) { \Neos\Utility\Files::createDirectoryRecursively(dirname($targetPathAndFilename)); } if (substr($targetPathAndFilename, 0, 11) === 'resource://') { list($packageKey, $resourcePath) = explode('/', substr($targetPathAndFilename, 11), 2); $relativeTargetPathAndFilename = $packageKey . '/Resources/' . $resourcePath; } elseif (strpos($targetPathAndFilename, 'Tests') !== false) { $relativeTargetPathAndFilename = substr($targetPathAndFilename, strrpos(substr($targetPathAndFilename, 0, strpos($targetPathAndFilename, 'Tests/') - 1), '/') + 1); } else { $relativeTargetPathAndFilename = substr($targetPathAndFilename, strrpos(substr($targetPathAndFilename, 0, strpos($targetPathAndFilename, 'Classes/') - 1), '/') + 1); } if (!file_exists($targetPathAndFilename) || $force === true) { file_put_contents($targetPathAndFilename, $fileContent); $this->generatedFiles[] = 'Created .../' . $relativeTargetPathAndFilename; } else { $this->generatedFiles[] = 'Omitted .../' . $relativeTargetPathAndFilename; } }
/** * Persists a key to the file system * * @param string $name * @param string $password * @return void * @throws SecurityException */ protected function persistKey($name, $password) { $hashedPassword = $this->hashService->hashPassword($password, $this->passwordHashingStrategy); $keyPathAndFilename = $this->getKeyPathAndFilename($name); if (!is_dir($this->getPath())) { Utility\Files::createDirectoryRecursively($this->getPath()); } $result = file_put_contents($keyPathAndFilename, $hashedPassword); if ($result === false) { throw new SecurityException(sprintf('The key could not be stored ("%s").', $keyPathAndFilename), 1305812921); } }
/** * 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); } } }
/** * Explicitly compile proxy classes * * The compile command triggers the proxy class compilation. * Although a compilation run is triggered automatically by Flow, there might * be cases in a production context where a manual compile run is needed. * * @Flow\Internal * @param boolean $force If set, classes will be compiled even though the cache says that everything is up to date. * @return void */ public function compileCommand($force = false) { /** @var VariableFrontend $objectConfigurationCache */ $objectConfigurationCache = $this->cacheManager->getCache('Flow_Object_Configuration'); if ($force === false) { if ($objectConfigurationCache->has('allCompiledCodeUpToDate')) { return; } } /** @var PhpFrontend $classesCache */ $classesCache = $this->cacheManager->getCache('Flow_Object_Classes'); $this->proxyClassCompiler->injectClassesCache($classesCache); $this->aopProxyClassBuilder->injectObjectConfigurationCache($objectConfigurationCache); $this->aopProxyClassBuilder->build(); $this->dependencyInjectionProxyClassBuilder->build(); $classCount = $this->proxyClassCompiler->compile(); $dataTemporaryPath = $this->environment->getPathToTemporaryDirectory(); Files::createDirectoryRecursively($dataTemporaryPath); file_put_contents($dataTemporaryPath . 'AvailableProxyClasses.php', $this->proxyClassCompiler->getStoredProxyClassMap()); $objectConfigurationCache->set('allCompiledCodeUpToDate', true); $classesCacheBackend = $classesCache->getBackend(); if ($this->bootstrap->getContext()->isProduction() && $classesCacheBackend instanceof FreezableBackendInterface) { /** @var FreezableBackendInterface $backend */ $backend = $classesCache->getBackend(); $backend->freeze(); } $this->emitFinishedCompilationRun($classCount); }
/** * 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; }
/** * Moves a package from one path to another. * * @param string $fromAbsolutePath * @param string $toAbsolutePath * @return void */ protected function movePackage($fromAbsolutePath, $toAbsolutePath) { Files::createDirectoryRecursively($toAbsolutePath); Files::copyDirectoryRecursively($fromAbsolutePath, $toAbsolutePath, false, true); Files::removeDirectoryRecursively($fromAbsolutePath); }