/** * 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; }
/** * 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); }
/** * @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; }
/** * @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(); }
/** * 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); } } } }
/** * 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; }
/** * 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); } }
/** * 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); }
/** * 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>'); } }