Example #1
0
 /**
  * Show Documentation
  *
  * @param string $lang 
  * @param string $doc 
  * @param string $page 
  * @return void
  * @author Marc Neuhaus
  */
 public function indexAction($lang = "en", $doc = "Manual", $page = "index.html")
 {
     \Admin\Core\API::addTitleSegment("Documentation");
     \Admin\Core\API::addTitleSegment($page);
     if ($this->request->hasArgument("subpage1")) {
         $c = 1;
         $directories = array($page);
         while ($c < 10) {
             if ($this->request->hasArgument("subpage" . $c)) {
                 $directories[] = $this->request->getArgument("subpage" . $c);
             } else {
                 break;
             }
             $c++;
         }
         $page = implode("/", $directories);
     }
     if (!stristr($page, ".html")) {
         $page .= ".html";
     }
     $page = urldecode($page);
     if ($lang == "index") {
         $lang = "en";
     }
     $package = $this->packageManager->getPackage("Admin");
     $path = "resource://Admin/Private/Docs/";
     $template = $path . $doc . "/" . $lang . "/html/" . $page;
     $this->view->setTemplatePathAndFilename($template);
     $this->view->assign("base", "/admin/doc/en/");
     $content = $this->view->render();
     $content = preg_replace('/internal" href="([A-Za-z0-9])/', 'internal" href="/admin/doc/' . $lang . '/\\1', $content);
     $content = str_replace('href="#', 'href="/admin/doc/' . $lang . '/' . $page . '#', $content);
     $content = str_replace('{ ', '{', $content);
     return $content;
 }
 /**
  *
  * @param array $tables 
  * @param string $package
  * @return void
  * @author Marc Neuhaus
  * @Admin\Annotations\Navigation(title="Migration Generator", position="system:left", priority="10")
  * @Admin\Annotations\Access(admin="true")
  */
 public function schemaAction($tables = array(), $package = null)
 {
     if (count($tables) > 0) {
         $this->doctrineService->generateAndExecutePartialMigrationFor($tables, $package);
     }
     $schemaDiff = $this->doctrineService->getDatabaseDiff();
     $this->view->assign("schemaDiff", $schemaDiff);
     $packages = $this->packageManager->getActivePackages();
     $this->view->assign("packages", $packages);
 }
 /**
  * returns classes that are taged with all of the specified tags
  *
  * @param string $tags
  * @return void
  * @author Marc Neuhaus
  */
 public function getClassesAnnotatedWith($tags)
 {
     $cache = $this->cacheManager->getCache('Admin_ImplementationCache');
     $identifier = "ClassesTaggedWith-" . implode("_", $tags);
     if (!$cache->has($identifier)) {
         $classes = array();
         $activePackages = $this->packageManager->getActivePackages();
         foreach ($activePackages as $packageName => $package) {
             if (substr($packageName, 0, 8) === "Doctrine") {
                 continue;
             }
             foreach ($package->getClassFiles() as $class => $file) {
                 $annotations = $this->getClassConfiguration($class);
                 $tagged = true;
                 foreach ($tags as $tag) {
                     if (!isset($annotations[$tag])) {
                         $tagged = false;
                     }
                 }
                 if ($tagged) {
                     $classes[$class] = $packageName;
                 }
             }
         }
         $cache->set($identifier, $classes);
     } elseif (isset($this->runtimeCache[$identifier])) {
         $classes = $this->runtimeCache[$identifier];
     } else {
         $this->runtimeCache[$identifier] = $classes = $cache->get($identifier);
     }
     return $classes;
 }
Example #4
0
 /**
  * Evaluates the absolute path and filename of the resource file specified
  * by the given path.
  *
  * @param string $requestedPath
  * @param boolean $checkForExistence Whether a (non-hash) path should be checked for existence before being returned
  * @return mixed The full path and filename or FALSE if the file doesn't exist
  * @throws \TYPO3\FLOW3\Resource\Exception
  * @throws \InvalidArgumentException
  */
 protected function evaluateResourcePath($requestedPath, $checkForExistence = TRUE)
 {
     if (substr($requestedPath, 0, strlen(self::SCHEME)) !== self::SCHEME) {
         throw new \InvalidArgumentException('The ' . __CLASS__ . ' only supports the \'' . self::SCHEME . '\' scheme.', 1256052544);
     }
     $uriParts = parse_url($requestedPath);
     if (!is_array($uriParts) || !isset($uriParts['host'])) {
         return FALSE;
     }
     if (strlen($uriParts['host']) === 40) {
         $resourcePath = $this->resourceManager->getPersistentResourcesStorageBaseUri() . $uriParts['host'];
         if ($checkForExistence === FALSE || file_exists($resourcePath)) {
             return $resourcePath;
         } else {
             return FALSE;
         }
     }
     if (!$this->packageManager->isPackageAvailable($uriParts['host'])) {
         throw new \TYPO3\FLOW3\Resource\Exception(sprintf('Invalid resource URI "%s": Package "%s" is not available.', $requestedPath, $uriParts['host']), 1309269952);
     }
     $package = $this->packageManager->getPackage($uriParts['host']);
     $resourcePath = \TYPO3\FLOW3\Utility\Files::concatenatePaths(array($package->getResourcesPath(), $uriParts['path']));
     if ($checkForExistence === FALSE || file_exists($resourcePath)) {
         return $resourcePath;
     }
     return FALSE;
 }
 /**
  * Generates a new migration file and returns the path to it.
  *
  * If $diffAgainstCurrent is TRUE, it generates a migration file with the
  * diff between current DB structure and the found mapping metadata.
  *
  * Otherwise an empty migration skeleton is generated.
  *
  * @param boolean $diffAgainstCurrent
  * @return string Path to the new file
  */
 public function generateAndExecutePartialMigrationFor($tables = array(), $package = null, $diffAgainstCurrent = TRUE)
 {
     $configuration = $this->getMigrationConfiguration();
     $up = NULL;
     $down = NULL;
     if ($diffAgainstCurrent === TRUE) {
         $connection = $this->entityManager->getConnection();
         $platform = $connection->getDatabasePlatform();
         $metadata = $this->entityManager->getMetadataFactory()->getAllMetadata();
         if (empty($metadata)) {
             return 'No mapping information to process.';
         }
         $tool = new \Doctrine\ORM\Tools\SchemaTool($this->entityManager);
         $fromSchema = $connection->getSchemaManager()->createSchema();
         $toSchema = $tool->getSchemaFromMetadata($metadata);
         $fromSchema = $this->filterSchema($fromSchema, $tables);
         $toSchema = $this->filterSchema($toSchema, $tables);
         $up = $this->buildCodeFromSql($configuration, $fromSchema->getMigrateToSql($toSchema, $platform));
         $down = $this->buildCodeFromSql($configuration, $fromSchema->getMigrateFromSql($toSchema, $platform));
         if (!$up && !$down) {
             return 'No changes detected in your mapping information.';
         }
     }
     if (!is_null($package) && $this->packageManager->isPackageActive($package)) {
         $package = $this->packageManager->getPackage($package);
         $migrationsPath = $package->getPackagePath() . "Migrations/" . ucfirst($platform->getName()) . "/";
         $configuration->setMigrationsDirectory($migrationsPath);
     }
     $migrationFile = $this->writeMigrationClassToFile($configuration, $up, $down);
     preg_match("/Version([0-9]+)\\.php/", $migrationFile, $matches);
     $version = $matches[1];
     $this->executeMigration($version);
 }
Example #6
0
 /**
  * @param \TYPO3\Form\Core\Model\FinisherContext $finisherContext
  * @return void
  * @throws \TYPO3\Setup\Exception
  */
 public function importSite(\TYPO3\Form\Core\Model\FinisherContext $finisherContext)
 {
     $formValues = $finisherContext->getFormRuntime()->getFormState()->getFormValues();
     if (isset($formValues['prune']) && intval($formValues['prune']) === 1) {
         $this->nodeRepository->removeAll();
         $this->workspaceRepository->removeAll();
         $this->domainRepository->removeAll();
         $this->siteRepository->removeAll();
         $this->persistenceManager->persistAll();
     }
     if (!empty($formValues['packageKey'])) {
         if ($this->packageManager->isPackageAvailable($formValues['packageKey'])) {
             throw new \TYPO3\Setup\Exception(sprintf('The package key "%s" already exists.', $formValues['packageKey']), 1346759486);
         }
         $packageKey = $formValues['packageKey'];
         $siteName = $formValues['packageKey'];
         $this->packageManager->createPackage($packageKey, NULL, Files::getUnixStylePath(Files::concatenatePaths(array(FLOW3_PATH_PACKAGES, 'Sites'))));
         $this->generatorService->generateSitesXml($packageKey, $siteName);
         $this->generatorService->generateSitesTypoScript($packageKey, $siteName);
         $this->generatorService->generateSitesTemplate($packageKey, $siteName);
         $this->packageManager->activatePackage($packageKey);
     } else {
         $packageKey = $formValues['site'];
     }
     if ($packageKey !== '') {
         try {
             $contentContext = new \TYPO3\TYPO3\Domain\Service\ContentContext('live');
             $this->nodeRepository->setContext($contentContext);
             $this->siteImportService->importFromPackage($packageKey);
         } catch (\Exception $exception) {
             $finisherContext->cancel();
             $this->flashMessageContainer->addMessage(new \TYPO3\FLOW3\Error\Error(sprintf('Error: During the import of the "Sites.xml" from the package "%s" an exception occurred: %s', $packageKey, $exception->getMessage())));
         }
     }
 }
 /**
  * Action for listing active packages
  *
  * @return string
  */
 public function listActiveAction()
 {
     $packages = $this->packageManager->getActivePackages();
     $output = 'Active packages:' . PHP_EOL;
     foreach ($packages as $package) {
         $output .= ' ' . str_pad($package->getPackageKey(), 30) . $package->getPackageMetaData()->getVersion() . PHP_EOL;
     }
     return $output . PHP_EOL;
 }
 /**
  * Processes the template files
  * 
  * @return void 
  */
 protected function processTemplateFiles()
 {
     $this->backporter->emptyTargetPath(FALSE);
     $replacePairs = array('f:form.checkbox' => 'form:form.checkbox');
     $this->backporter->setReplacePairs($replacePairs);
     $this->backporter->setFileSpecificReplacePairs(array());
     $this->backporter->setCodeProcessorClassName('TYPO3\\FormBackporter\\CodeProcessor\\TemplateCodeProcessor');
     $this->backporter->setIncludeFilePatterns(array('#^Resources/Private/Form/.*.html$#'));
     $this->backporter->processFiles($this->packageManager->getPackage('TYPO3.Form')->getPackagePath(), $this->settings['targetPath']);
 }
 /**
  * @param string $packageKey
  * @return \TYPO3\FLOW3\Error\Error|\TYPO3\FLOW3\Error\Message
  */
 protected function freezePackage($packageKey)
 {
     try {
         $this->packageManager->freezePackage($packageKey);
         $message = new \TYPO3\FLOW3\Error\Message($packageKey . ' has been frozen', 1343231689);
     } catch (\LogicException $exception) {
         $message = new \TYPO3\FLOW3\Error\Error($exception->getMessage(), 1343231690);
     } catch (\TYPO3\FLOW3\Package\Exception\UnknownPackageException $exception) {
         $message = new \TYPO3\FLOW3\Error\Error($exception->getMessage(), 1343231691);
     }
     return $message;
 }
Example #10
0
 /**
  * @return void
  */
 protected function displayHelpIndex()
 {
     $context = $this->bootstrap->getContext();
     $this->outputLine('<b>FLOW3 %s ("%s" context)</b>', array($this->packageManager->getPackage('TYPO3.FLOW3')->getPackageMetaData()->getVersion(), $context));
     $this->outputLine('<i>usage: %s <command identifier></i>', array($this->getFlow3InvocationString()));
     $this->outputLine();
     $this->outputLine('The following commands are currently available:');
     $this->displayShortHelpForCommands($this->commandManager->getAvailableCommands());
     $this->outputLine('* = compile time command');
     $this->outputLine();
     $this->outputLine('See "%s help <commandidentifier>" for more information about a specific command.', array($this->getFlow3InvocationString()));
     $this->outputLine();
 }
Example #11
0
 /**
  * Exports the internal reflection data into the ReflectionData cache
  *
  * This method is triggered by a signal which is connected to the bootstrap's
  * shutdown sequence.
  *
  * If the reflection data has previously been loaded from the runtime cache,
  * saving it is omitted as changes are not expected.
  *
  * In Production context the whole cache is written at once and then frozen in
  * order to be consistent. Frozen cache data in Development is only produced for
  * classes contained in frozen packages.
  *
  * @return void
  * @throws \TYPO3\FLOW3\Reflection\Exception if no cache has been injected
  */
 public function saveToCache()
 {
     if ($this->loadFromClassSchemaRuntimeCache === TRUE) {
         return;
     }
     if (!$this->reflectionDataCompiletimeCache instanceof \TYPO3\FLOW3\Cache\Frontend\FrontendInterface) {
         throw new \TYPO3\FLOW3\Reflection\Exception('A cache must be injected before initializing the Reflection Service.', 1232044697);
     }
     if (count($this->updatedReflectionData) > 0) {
         $this->log(sprintf('Found %s classes whose reflection data was not cached previously.', count($this->updatedReflectionData)), LOG_DEBUG);
         foreach (array_keys($this->updatedReflectionData) as $className) {
             $this->statusCache->set(str_replace('\\', '_', $className), '');
         }
         $data = array();
         $propertyNames = array('classReflectionData', 'classSchemata', 'annotatedClasses', 'classesByMethodAnnotations');
         foreach ($propertyNames as $propertyName) {
             $data[$propertyName] = $this->{$propertyName};
         }
         $this->reflectionDataCompiletimeCache->set('ReflectionData', $data);
     }
     if ($this->context->isProduction()) {
         $this->reflectionDataRuntimeCache->flush();
         $classNames = array();
         foreach ($this->classReflectionData as $className => $reflectionData) {
             $classNames[$className] = TRUE;
             $this->reflectionDataRuntimeCache->set(str_replace('\\', '_', $className), $reflectionData);
             if (isset($this->classSchemata[$className])) {
                 $this->classSchemataRuntimeCache->set(str_replace('\\', '_', $className), $this->classSchemata[$className]);
             }
         }
         $this->reflectionDataRuntimeCache->set('__classNames', $classNames);
         $this->reflectionDataRuntimeCache->set('__annotatedClasses', $this->annotatedClasses);
         $this->reflectionDataRuntimeCache->getBackend()->freeze();
         $this->classSchemataRuntimeCache->getBackend()->freeze();
         $this->log(sprintf('Built and froze reflection runtime caches (%s classes).', count($this->classReflectionData)), LOG_INFO);
     } elseif ($this->context->isDevelopment()) {
         foreach (array_keys($this->packageManager->getFrozenPackages()) as $packageKey) {
             $pathAndFilename = $this->getPrecompiledReflectionStoragePath() . $packageKey . '.dat';
             if (!file_exists($pathAndFilename)) {
                 $this->log(sprintf('Rebuilding precompiled reflection data for frozen package %s.', $packageKey), LOG_INFO);
                 $this->freezePackageReflection($packageKey);
             }
         }
     }
 }
Example #12
0
 /**
  * Return the configuration needed for Migrations.
  *
  * @return \Doctrine\DBAL\Migrations\Configuration\Configuration
  */
 protected function getMigrationConfiguration()
 {
     $this->output = array();
     $that = $this;
     $outputWriter = new \Doctrine\DBAL\Migrations\OutputWriter(function ($message) use($that) {
         $that->output[] = $message;
     });
     $configuration = new \Doctrine\DBAL\Migrations\Configuration\Configuration($this->entityManager->getConnection(), $outputWriter);
     $configuration->setMigrationsNamespace('TYPO3\\FLOW3\\Persistence\\Doctrine\\Migrations');
     $configuration->setMigrationsDirectory(\TYPO3\FLOW3\Utility\Files::concatenatePaths(array(FLOW3_PATH_DATA, 'DoctrineMigrations')));
     $configuration->setMigrationsTableName('flow3_doctrine_migrationstatus');
     $configuration->createMigrationTable();
     $databasePlatformName = $this->getDatabasePlatformName();
     foreach ($this->packageManager->getActivePackages() as $package) {
         $configuration->registerMigrationsFromDirectory(\TYPO3\FLOW3\Utility\Files::concatenatePaths(array($package->getPackagePath(), 'Migrations', $databasePlatformName)));
     }
     return $configuration;
 }
Example #13
0
 /**
  * Finds all Locale objects representing locales available in the
  * FLOW3 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()
 {
     foreach ($this->packageManager->getActivePackages() as $activePackage) {
         $packageResourcesPath = $this->localeBasePath . $activePackage->getPackageKey() . '/';
         if (!is_dir($packageResourcesPath)) {
             continue;
         }
         $directoryIterator = new \RecursiveDirectoryIterator($packageResourcesPath, \RecursiveDirectoryIterator::UNIX_PATHS);
         $recursiveIteratorIterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
         foreach ($recursiveIteratorIterator as $fileOrDirectory) {
             if ($fileOrDirectory->isFile()) {
                 $localeIdentifier = Utility::extractLocaleTagFromFilename($fileOrDirectory->getFilename());
                 if ($localeIdentifier !== FALSE) {
                     $this->localeCollection->addLocale(new Locale($localeIdentifier));
                 }
             }
         }
     }
 }
 /**
  * @param string $pathAndFilename
  * @return void
  * @throws \TYPO3\FLOW3\Package\Exception\UnknownPackageException
  * @throws \TYPO3\FLOW3\Package\Exception\InvalidPackageStateException
  */
 public function importSitesFromFile($pathAndFilename)
 {
     $contentContext = $this->nodeRepository->getContext();
     $contentContext->setInvisibleContentShown(TRUE);
     $contentContext->setInaccessibleContentShown(TRUE);
     // no file_get_contents here because it does not work on php://stdin
     $fp = fopen($pathAndFilename, 'rb');
     $xmlString = '';
     while (!feof($fp)) {
         $xmlString .= fread($fp, 4096);
     }
     fclose($fp);
     $xml = new \SimpleXMLElement($xmlString);
     foreach ($xml->site as $siteXml) {
         $site = $this->siteRepository->findOneByNodeName((string) $siteXml['nodeName']);
         if ($site === NULL) {
             $site = new \TYPO3\TYPO3\Domain\Model\Site((string) $siteXml['nodeName']);
             $this->siteRepository->add($site);
         } else {
             $this->siteRepository->update($site);
         }
         $site->setName((string) $siteXml->properties->name);
         $site->setState((int) $siteXml->properties->state);
         $siteResourcesPackageKey = (string) $siteXml->properties->siteResourcesPackageKey;
         if ($this->packageManager->isPackageAvailable($siteResourcesPackageKey) === FALSE) {
             throw new \TYPO3\FLOW3\Package\Exception\UnknownPackageException('Package "' . $siteResourcesPackageKey . '" specified in the XML as site resources package does not exist.', 1303891443);
         }
         if ($this->packageManager->isPackageActive($siteResourcesPackageKey) === FALSE) {
             throw new \TYPO3\FLOW3\Package\Exception\InvalidPackageStateException('Package "' . $siteResourcesPackageKey . '" specified in the XML as site resources package is not active.', 1303898135);
         }
         $site->setSiteResourcesPackageKey($siteResourcesPackageKey);
         $rootNode = $contentContext->getWorkspace()->getRootNode();
         if ($rootNode->getNode('/sites') === NULL) {
             $rootNode->createSingleNode('sites');
         }
         $siteNode = $rootNode->getNode('/sites/' . $site->getNodeName());
         if ($siteNode === NULL) {
             $siteNode = $rootNode->getNode('/sites')->createSingleNode($site->getNodeName());
         }
         $siteNode->setContentObject($site);
         $this->parseNodes($siteXml, $siteNode);
     }
 }
Example #15
0
 /**
  * Refreeze a package
  *
  * Refreezes a currently frozen package: all precompiled information is removed
  * and file monitoring will consider the package exactly once, on the next
  * request. After that request, the package remains frozen again, just with the
  * updated data.
  *
  * By specifying <b>all</b> as a package key, all currently frozen packages are
  * refrozen (the default).
  *
  * @param string $packageKey Key of the package to refreeze, or 'all'
  * @return void
  * @see typo3.flow3:package:freeze
  * @see typo3.flow3:cache:flush
  */
 public function refreezeCommand($packageKey = 'all')
 {
     if (!$this->bootstrap->getContext()->isDevelopment()) {
         $this->outputLine('Package freezing is only supported in Development context.');
         $this->quit(3);
     }
     $packagesToRefreeze = array();
     if ($packageKey === 'all') {
         foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) {
             if ($this->packageManager->isPackageFrozen($packageKey)) {
                 $packagesToRefreeze[] = $packageKey;
             }
         }
         if ($packagesToRefreeze === array()) {
             $this->outputLine('Nothing to do, no packages were frozen.');
             $this->quit(0);
         }
     } else {
         if ($packageKey === NULL) {
             $this->outputLine('You must specify a package to refreeze.');
             $this->quit(1);
         }
         if (!$this->packageManager->isPackageAvailable($packageKey)) {
             $this->outputLine('Package "%s" is not available.', array($packageKey));
             $this->quit(2);
         }
         if (!$this->packageManager->isPackageFrozen($packageKey)) {
             $this->outputLine('Package "%s" was not frozen.', array($packageKey));
             $this->quit(0);
         }
         $packagesToRefreeze = array($packageKey);
     }
     foreach ($packagesToRefreeze as $packageKey) {
         $this->packageManager->refreezePackage($packageKey);
         $this->outputLine('Refroze package "%s".', array($packageKey));
     }
     Scripts::executeCommand('typo3.flow3:cache:flush', $this->settings, FALSE);
     $this->sendAndExit(0);
 }
Example #16
0
 /**
  * Flush all caches
  *
  * The flush command flushes all caches (including code caches) which have been
  * registered with FLOW3's Cache Manager. It also removes any session data.
  *
  * If fatal errors caused by a package prevent the compile time bootstrap
  * from running, the removal of any temporary data can be forced by specifying
  * the option <b>--force</b>.
  *
  * This command does not remove the precompiled data provided by frozen
  * packages unless the <b>--force</b> option is used.
  *
  * @param boolean $force Force flushing of any temporary data
  * @return void
  * @see typo3.flow3:cache:warmup
  * @see typo3.flow3:package:freeze
  * @see typo3.flow3:package:refreeze
  */
 public function flushCommand($force = FALSE)
 {
     // Internal note: the $force option is evaluated early in the FLOW3
     // bootstrap in order to reliably flush the temporary data before any
     // other code can cause fatal errors.
     $currentSessionImplementation = $this->objectManager->getClassNameByObjectName('TYPO3\\FLOW3\\Session\\SessionInterface');
     $result = $currentSessionImplementation::destroyAll($this->bootstrap);
     if ($result === NULL) {
         $sessionDestroyMessage = ' and removed all potentially existing session data.';
     } elseif ($result > 0) {
         $sessionDestroyMessage = sprintf(' and removed data of %s.', $result === 1 ? 'the one existing session' : 'the ' . $result . ' existing sessions');
     } else {
         $sessionDestroyMessage = '.';
     }
     $this->cacheManager->flushCaches();
     $this->outputLine('Flushed all caches for "' . $this->bootstrap->getContext() . '" context' . $sessionDestroyMessage);
     if ($this->lockManager->isSiteLocked()) {
         $this->lockManager->unlockSite();
     }
     $frozenPackages = array();
     foreach (array_keys($this->packageManager->getActivePackages()) as $packageKey) {
         if ($this->packageManager->isPackageFrozen($packageKey)) {
             $frozenPackages[] = $packageKey;
         }
     }
     if ($frozenPackages !== array()) {
         $this->outputFormatted(PHP_EOL . 'Please note that the following package' . (count($frozenPackages) === 1 ? ' is' : 's are') . ' currently frozen: ' . PHP_EOL);
         $this->outputFormatted(implode(PHP_EOL, $frozenPackages) . PHP_EOL, array(), 2);
         $message = 'As code and configuration changes in these packages are not detected, the application may respond ';
         $message .= 'unexpectedly if modifications were done anyway or the remaining code relies on these changes.' . PHP_EOL . PHP_EOL;
         $message .= 'You may call <b>package:refreeze all</b> in order to refresh frozen packages or use the <b>--force</b> ';
         $message .= 'option of this <b>cache:flush</b> command to flush caches if FLOW3 becomes unresponsive.' . PHP_EOL;
         $this->outputFormatted($message, array($frozenPackages));
     }
     $this->sendAndExit(0);
 }
 /**
  * Validate the given configuration
  *
  * ./flow3 configuration:validate --type Settings --path TYPO3.FLOW3.persistence
  *
  * The schemas are searched in the path "Resources/Private/Schema" of all
  * active Packages. The schema-filenames must match the pattern
  * __type__.__path__.schema.yaml. The type and/or the path can also be
  * expressed as subdirectories of Resources/Private/Schema. So
  * Settings/TYPO3/FLOW3.persistence.schema.yaml will match the same pathes
  * like Settings.TYPO3.FLOW3.persistence.schema.yaml or
  * Settings/TYPO3.FLOW3/persistence.schema.yaml
  *
  * @param string $type Configuration type to validate
  * @param string $path path to the subconfiguration separated by "." like "TYPO3.FLOW3"
  * @return void
  */
 public function validateCommand($type = NULL, $path = NULL)
 {
     $availableConfigurationTypes = $this->configurationManager->getAvailableConfigurationTypes();
     if (in_array($type, $availableConfigurationTypes) === FALSE) {
         if ($type !== NULL) {
             $this->outputLine('<b>Configuration type "%s" was not found!</b>', array($type));
             $this->outputLine();
         }
         $this->outputLine('<b>Available configuration types:</b>');
         foreach ($availableConfigurationTypes as $availableConfigurationType) {
             $this->outputLine('  ' . $availableConfigurationType);
         }
         $this->outputLine();
         $this->outputLine('Hint: <b>%s configuration:validate --type <configurationType></b>', array($this->getFlow3InvocationString()));
         $this->outputLine('      validates the configuration of the specified type.');
         return;
     }
     $configuration = $this->configurationManager->getConfiguration($type);
     $this->outputLine('<b>Validating configuration for type: "' . $type . '"' . ($path !== NULL ? ' and path: "' . $path . '"' : '') . '</b>');
     // find schema files for the given type and path
     $schemaFileInfos = array();
     $activePackages = $this->packageManager->getActivePackages();
     foreach ($activePackages as $package) {
         $packageKey = $package->getPackageKey();
         $packageSchemaPath = \TYPO3\FLOW3\Utility\Files::concatenatePaths(array($package->getResourcesPath(), 'Private/Schema'));
         if (is_dir($packageSchemaPath)) {
             $packageSchemaFiles = \TYPO3\FLOW3\Utility\Files::readDirectoryRecursively($packageSchemaPath, '.schema.yaml');
             foreach ($packageSchemaFiles as $schemaFile) {
                 $schemaName = substr($schemaFile, strlen($packageSchemaPath) + 1, -strlen('.schema.yaml'));
                 $schemaNameParts = explode('.', str_replace('/', '.', $schemaName), 2);
                 $schemaType = $schemaNameParts[0];
                 $schemaPath = isset($schemaNameParts[1]) ? $schemaNameParts[1] : NULL;
                 if ($schemaType === $type && ($path === NULL || strpos($schemaPath, $path) === 0)) {
                     $schemaFileInfos[] = array('file' => $schemaFile, 'name' => $schemaName, 'path' => $schemaPath, 'packageKey' => $packageKey);
                 }
             }
         }
     }
     $this->outputLine();
     if (count($schemaFileInfos) > 0) {
         $this->outputLine('%s schema files were found:', array(count($schemaFileInfos)));
         $result = new \TYPO3\FLOW3\Error\Result();
         foreach ($schemaFileInfos as $schemaFileInfo) {
             if ($schemaFileInfo['path'] !== NULL) {
                 $data = \TYPO3\FLOW3\Utility\Arrays::getValueByPath($configuration, $schemaFileInfo['path']);
             } else {
                 $data = $configuration;
             }
             if (empty($data)) {
                 $result->forProperty($schemaFileInfo['path'])->addError(new \TYPO3\FLOW3\Error\Error('configuration in path ' . $schemaFileInfo['path'] . ' is empty'));
                 $this->outputLine(' - package: "' . $schemaFileInfo['packageKey'] . '" schema: "' . $schemaFileInfo['name'] . '" -> <b>configuration is empty</b>');
             } else {
                 $parsedSchema = \Symfony\Component\Yaml\Yaml::parse($schemaFileInfo['file']);
                 $schemaResult = $this->schemaValidator->validate($data, $parsedSchema);
                 if ($schemaResult->hasErrors()) {
                     $this->outputLine(' - package:"' . $schemaFileInfo['packageKey'] . '" schema:"' . $schemaFileInfo['name'] . '" -> <b>' . count($schemaResult->getFlattenedErrors()) . ' errors</b>');
                 } else {
                     $this->outputLine(' - package:"' . $schemaFileInfo['packageKey'] . '" schema:"' . $schemaFileInfo['name'] . '" -> <b>is valid</b>');
                 }
                 if ($schemaFileInfo['path'] !== NULL) {
                     $result->forProperty($schemaFileInfo['path'])->merge($schemaResult);
                 } else {
                     $result->merge($schemaResult);
                 }
             }
         }
     } else {
         $this->outputLine('No matching schema-files were found!');
         return;
     }
     $this->outputLine();
     if ($result->hasErrors()) {
         $errors = $result->getFlattenedErrors();
         $this->outputLine('<b>%s errors were found:</b>', array(count($errors)));
         foreach ($errors as $path => $pathErrors) {
             foreach ($pathErrors as $error) {
                 $this->outputLine(' - %s -> %s', array($path, $error->render()));
             }
         }
     } else {
         $this->outputLine('<b>The configuration is valid!</b>');
     }
 }