Upgrade 1-11.38

This commit is contained in:
xesmyd
2026-03-30 14:10:30 +02:00
parent f2a7e6d1fc
commit ac648ef29d
24665 changed files with 69682 additions and 2205004 deletions
@@ -27,6 +27,7 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
{
protected function listBundles($output)
{
$title = 'Available registered bundles with their extension alias if available';
$headers = array('Bundle name', 'Extension alias');
$rows = array();
@@ -41,9 +42,10 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
}
if ($output instanceof StyleInterface) {
$output->title($title);
$output->table($headers, $rows);
} else {
$output->writeln('Available registered bundles with their extension alias if available:');
$output->writeln($title);
$table = new Table($output);
$table->setHeaders($headers)->setRows($rows)->render();
}
@@ -52,6 +54,8 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
protected function findExtension($name)
{
$bundles = $this->initializeBundles();
$minScore = INF;
foreach ($bundles as $bundle) {
if ($name === $bundle->getName()) {
if (!$bundle->getContainerExtension()) {
@@ -61,16 +65,37 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
return $bundle->getContainerExtension();
}
$distance = levenshtein($name, $bundle->getName());
if ($distance < $minScore) {
$guess = $bundle->getName();
$minScore = $distance;
}
$extension = $bundle->getContainerExtension();
if ($extension && $name === $extension->getAlias()) {
return $extension;
if ($extension) {
if ($name === $extension->getAlias()) {
return $extension;
}
$distance = levenshtein($name, $extension->getAlias());
if ($distance < $minScore) {
$guess = $extension->getAlias();
$minScore = $distance;
}
}
}
if ('Bundle' !== substr($name, -6)) {
$message = sprintf('No extensions with configuration available for "%s"', $name);
$message = sprintf('No extensions with configuration available for "%s".', $name);
} else {
$message = sprintf('No extension with alias "%s" is enabled', $name);
$message = sprintf('No extension with alias "%s" is enabled.', $name);
}
if (isset($guess) && $minScore < 3) {
$message .= sprintf("\n\nDid you mean \"%s\"?", $guess);
}
throw new \LogicException($message);
@@ -92,7 +117,7 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
// Re-build bundle manually to initialize DI extensions that can be extended by other bundles in their build() method
// as this method is not called when the container is loaded from the cache.
$container = $this->getContainerBuilder();
$bundles = $this->getContainer()->get('kernel')->registerBundles();
$bundles = $this->getContainer()->get('kernel')->getBundles();
foreach ($bundles as $bundle) {
if ($extension = $bundle->getContainerExtension()) {
$container->registerExtension($extension);
@@ -110,13 +110,16 @@ EOT
$rows = array();
$copyUsed = false;
$exitCode = 0;
$validAssetDirs = array();
/** @var BundleInterface $bundle */
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
if (!is_dir($originDir = $bundle->getPath().'/Resources/public')) {
continue;
}
$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));
$assetDir = preg_replace('/bundle$/', '', strtolower($bundle->getName()));
$targetDir = $bundlesDir.$assetDir;
$validAssetDirs[] = $assetDir;
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
@@ -149,6 +152,9 @@ EOT
$rows[] = array(sprintf('<fg=red;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage());
}
}
// remove the assets of the bundles that no longer exist
$dirsToRemove = Finder::create()->depth(0)->directories()->exclude($validAssetDirs)->in($bundlesDir);
$this->filesystem->remove($dirsToRemove);
$io->table(array('', 'Bundle', 'Method / Error'), $rows);
+19 -26
View File
@@ -147,7 +147,7 @@ EOF
$safeTempKernel = str_replace('\\', '\\\\', get_class($tempKernel));
$realKernelFQN = get_class($realKernel);
foreach (Finder::create()->files()->name('*.meta')->in($warmupDir) as $file) {
foreach (Finder::create()->files()->depth('<3')->name('*.meta')->in($warmupDir) as $file) {
file_put_contents($file, preg_replace(
'/(C\:\d+\:)"'.$safeTempKernel.'"/',
sprintf('$1"%s"', $realKernelFQN),
@@ -159,26 +159,19 @@ EOF
$search = array($warmupDir, str_replace('\\', '\\\\', $warmupDir));
$replace = str_replace('\\', '/', $realCacheDir);
foreach (Finder::create()->files()->in($warmupDir) as $file) {
$content = str_replace($search, $replace, file_get_contents($file));
file_put_contents($file, $content);
$content = str_replace($search, $replace, file_get_contents($file), $count);
if ($count) {
file_put_contents($file, $content);
}
}
// fix references to kernel/container related classes
$fileSearch = $tempKernel->getName().ucfirst($tempKernel->getEnvironment()).'*';
$search = array(
$tempKernel->getName().ucfirst($tempKernel->getEnvironment()),
sprintf('\'kernel.name\' => \'%s\'', $tempKernel->getName()),
sprintf('key="kernel.name">%s<', $tempKernel->getName()),
);
$replace = array(
$realKernel->getName().ucfirst($realKernel->getEnvironment()),
sprintf('\'kernel.name\' => \'%s\'', $realKernel->getName()),
sprintf('key="kernel.name">%s<', $realKernel->getName()),
);
foreach (Finder::create()->files()->name($fileSearch)->in($warmupDir) as $file) {
$content = str_replace($search, $replace, file_get_contents($file));
file_put_contents(str_replace($search, $replace, $file), $content);
unlink($file);
// fix references to container's class
$tempContainerClass = get_class($tempKernel->getContainer());
$realContainerClass = get_class($realKernel->getContainer());
foreach (Finder::create()->files()->depth('<2')->name($tempContainerClass.'*')->in($warmupDir) as $file) {
$content = str_replace($tempContainerClass, $realContainerClass, file_get_contents($file));
file_put_contents($file, $content);
rename($file, str_replace(DIRECTORY_SEPARATOR.$tempContainerClass, DIRECTORY_SEPARATOR.$realContainerClass, $file));
}
// remove temp kernel file after cache warmed up
@@ -201,8 +194,8 @@ EOF
// the temp kernel class name must have the same length than the real one
// to avoid the many problems in serialized resources files
$class = substr($parentClass, 0, -1).'_';
// the temp kernel name must be changed too
$name = var_export(substr($parent->getName(), 0, -1).'_', true);
// the temp container class must be changed too
$containerClass = var_export(substr(get_class($parent->getContainer()), 0, -1).'_', true);
$code = <<<EOF
<?php
@@ -215,11 +208,6 @@ namespace $namespace
return $cacheDir;
}
public function getName()
{
return $name;
}
public function getRootDir()
{
return $rootDir;
@@ -230,6 +218,11 @@ namespace $namespace
return $logDir;
}
protected function getContainerClass()
{
return $containerClass;
}
protected function buildContainer()
{
\$container = parent::buildContainer();
@@ -16,6 +16,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Yaml\Yaml;
/**
@@ -34,9 +35,10 @@ class ConfigDebugCommand extends AbstractConfigCommand
->setName('debug:config')
->setDefinition(array(
new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'),
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
))
->setDescription('Dumps the current configuration for an extension')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> command dumps the current configuration for an
extension/bundle.
@@ -45,6 +47,10 @@ Either the extension alias or bundle name can be used:
<info>php %command.full_name% framework</info>
<info>php %command.full_name% FrameworkBundle</info>
For dumping a specific option, add its path as second argument:
<info>php %command.full_name% framework serializer.enabled</info>
EOF
)
;
@@ -56,12 +62,11 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
if (empty($name)) {
$io->comment('Provide the name of a bundle as the first argument of this command to dump its configuration.');
$io->newLine();
$this->listBundles($output);
if (null === $name = $input->getArgument('name')) {
$this->listBundles($io);
$io->comment('Provide the name of a bundle as the first argument of this command to dump its configuration. (e.g. <comment>debug:config FrameworkBundle</comment>)');
$io->comment('For dumping a specific option, add its path as the second argument of this command. (e.g. <comment>debug:config FrameworkBundle serializer</comment> to dump the <comment>framework.serializer</comment> configuration)');
return;
}
@@ -69,23 +74,38 @@ EOF
$extension = $this->findExtension($name);
$container = $this->compileContainer();
$configs = $container->getExtensionConfig($extension->getAlias());
$extensionAlias = $extension->getAlias();
$configs = $container->getExtensionConfig($extensionAlias);
$configuration = $extension->getConfiguration($configs, $container);
$this->validateConfiguration($extension, $configuration);
$configs = $container->getParameterBag()->resolveValue($configs);
$configs = $container->resolveEnvPlaceholders($container->getParameterBag()->resolveValue($configs));
$processor = new Processor();
$config = $processor->processConfiguration($configuration, $configs);
$config = $container->resolveEnvPlaceholders($container->getParameterBag()->resolveValue($processor->processConfiguration($configuration, $configs)));
if ($name === $extension->getAlias()) {
$io->title(sprintf('Current configuration for extension with alias "%s"', $name));
} else {
$io->title(sprintf('Current configuration for "%s"', $name));
if (null === $path = $input->getArgument('path')) {
$io->title(
sprintf('Current configuration for %s', ($name === $extensionAlias ? sprintf('extension with alias "%s"', $extensionAlias) : sprintf('"%s"', $name)))
);
$io->writeln(Yaml::dump(array($extensionAlias => $config), 10));
return;
}
$io->writeln(Yaml::dump(array($extension->getAlias() => $config), 10));
try {
$config = $this->getConfigForPath($config, $path, $extensionAlias);
} catch (LogicException $e) {
$io->error($e->getMessage());
return;
}
$io->title(sprintf('Current configuration for "%s.%s"', $extensionAlias, $path));
$io->writeln(Yaml::dump($config, 10));
}
private function compileContainer()
@@ -100,4 +120,28 @@ EOF
return $container;
}
/**
* Iterate over configuration until the last step of the given path.
*
* @param array $config A bundle configuration
*
* @throws LogicException If the configuration does not exist
*
* @return mixed
*/
private function getConfigForPath(array $config, $path, $alias)
{
$steps = explode('.', $path);
foreach ($steps as $step) {
if (!array_key_exists($step, $config)) {
throw new LogicException(sprintf('Unable to find configuration for "%s.%s"', $alias, $path));
}
$config = $config[$step];
}
return $config;
}
}
@@ -68,12 +68,10 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
if (empty($name)) {
$io->comment('Provide the name of a bundle as the first argument of this command to dump its default configuration.');
$io->newLine();
$this->listBundles($output);
if (null === $name = $input->getArgument('name')) {
$this->listBundles($io);
$io->comment('Provide the name of a bundle as the first argument of this command to dump its default configuration. (e.g. <comment>config:dump-reference FrameworkBundle</comment>)');
return;
}
@@ -19,6 +19,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\Config\FileLocator;
/**
@@ -96,7 +97,11 @@ EOF
$object = $this->getContainerBuilder();
if ($input->getOption('parameters')) {
$object = $object->getParameterBag();
$parameters = array();
foreach ($object->getParameterBag()->all() as $k => $v) {
$parameters[$k] = $object->resolveEnvPlaceholders($v);
}
$object = new ParameterBag($parameters);
$options = array();
} elseif ($parameter = $input->getOption('parameter')) {
$options = array('parameter' => $parameter);
@@ -168,11 +173,11 @@ EOF
}
if (!$this->getApplication()->getKernel()->isDebug()) {
throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.'));
throw new \LogicException('Debug information about the container is only available in debug mode.');
}
if (!is_file($cachedFile = $this->getContainer()->getParameter('debug.container.dump'))) {
throw new \LogicException(sprintf('Debug information about the container could not be found. Please clear the cache and try again.'));
throw new \LogicException('Debug information about the container could not be found. Please clear the cache and try again.');
}
$container = new ContainerBuilder();
@@ -194,7 +199,9 @@ EOF
throw new \InvalidArgumentException(sprintf('No services found that match "%s".', $name));
}
return $io->choice('Select one of the following services to display its information', $matchingServices);
$default = 1 === count($matchingServices) ? $matchingServices[0] : null;
return $io->choice('Select one of the following services to display its information', $matchingServices, $default);
}
private function findServiceIdsContaining(ContainerBuilder $builder, $name)
@@ -39,7 +39,7 @@ class EventDispatcherDebugCommand extends ContainerAwareCommand
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
))
->setDescription('Displays configured listeners for an application')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays all configured listeners:
<info>php %command.full_name%</info>
@@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -78,10 +79,10 @@ EOF
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
$helper = new DescriptorHelper();
$routes = $this->getContainer()->get('router')->getRouteCollection();
if ($name) {
$route = $this->getContainer()->get('router')->getRouteCollection()->get($name);
if (!$route) {
if (!$route = $routes->get($name)) {
throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
}
@@ -94,8 +95,6 @@ EOF
'output' => $io,
));
} else {
$routes = $this->getContainer()->get('router')->getRouteCollection();
foreach ($routes as $route) {
$this->convertController($route);
}
@@ -111,7 +110,7 @@ EOF
private function convertController(Route $route)
{
$nameParser = $this->getContainer()->get('controller_name_converter');
$nameParser = new ControllerNameParser($this->getApplication()->getKernel());
if ($route->hasDefault('_controller')) {
try {
$route->setDefault('_controller', $nameParser->build($route->getDefault('_controller')));
+3 -1
View File
@@ -54,7 +54,9 @@ abstract class ServerCommand extends ContainerAwareCommand
return true;
}
list($hostname, $port) = explode(':', $address);
$pos = strrpos($address, ':');
$hostname = substr($address, 0, $pos);
$port = substr($address, $pos + 1);
$fp = @fsockopen($hostname, $port, $errno, $errstr, 5);
@@ -15,9 +15,12 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
use Symfony\Component\Process\Exception\RuntimeException;
/**
* Runs Symfony application using PHP built-in web server.
@@ -113,14 +116,23 @@ EOF
$builder->setWorkingDirectory($documentRoot);
$builder->setTimeout(null);
$process = $builder->getProcess();
$callback = null;
if (OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) {
if (OutputInterface::VERBOSITY_NORMAL > $output->getVerbosity()) {
$process->disableOutput();
} else {
try {
$process->setTty(true);
} catch (RuntimeException $e) {
$callback = function ($type, $buffer) use ($output) {
if (Process::ERR === $type && $output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$output->write($buffer, false, OutputInterface::OUTPUT_RAW);
};
}
}
$this
->getHelper('process')
->run($output, $process, null, null, OutputInterface::VERBOSITY_VERBOSE);
$process->run($callback);
if (!$process->isSuccessful()) {
$errorMessages = array('Built-in server terminated unexpectedly.');
@@ -41,7 +41,7 @@ class ServerStartCommand extends ServerCommand
))
->setName('server:start')
->setDescription('Starts PHP built-in web server in the background')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> runs PHP's built-in web server:
<info>php %command.full_name%</info>
@@ -32,7 +32,7 @@ class ServerStatusCommand extends ServerCommand
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
))
->setName('server:status')
@@ -36,7 +36,7 @@ class ServerStopCommand extends ServerCommand
))
->setName('server:stop')
->setDescription('Stops PHP\'s built-in web server that was started with the server:start command')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> stops PHP's built-in web server:
<info>php %command.full_name%</info>
@@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\DataCollectorTranslator;
use Symfony\Component\Translation\LoggingTranslator;
/**
* Helps finding unused or missing translation messages in a given locale
@@ -50,7 +52,7 @@ class TranslationDebugCommand extends ContainerAwareCommand
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
))
->setDescription('Displays translation messages information')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> command helps finding unused or missing translation
messages and comparing them with the fallback ones by inspecting the
templates and translation files of a given bundle or the app folder.
@@ -84,6 +86,18 @@ EOF
;
}
/**
* {@inheritdoc}
*/
public function isEnabled()
{
if (!class_exists('Symfony\Component\Translation\Translator')) {
return false;
}
return parent::isEnabled();
}
/**
* {@inheritdoc}
*/
@@ -295,7 +309,7 @@ EOF
{
$fallbackCatalogues = array();
$translator = $this->getContainer()->get('translator');
if ($translator instanceof Translator) {
if ($translator instanceof Translator || $translator instanceof DataCollectorTranslator || $translator instanceof LoggingTranslator) {
foreach ($translator->getFallbackLocales() as $fallbackLocale) {
if ($fallbackLocale === $locale) {
continue;
@@ -39,11 +39,13 @@ class TranslationUpdateCommand extends ContainerAwareCommand
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'),
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
new InputOption('no-prefix', null, InputOption::VALUE_NONE, 'If set, no prefix is added to the translations'),
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'yml'),
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'),
new InputOption('no-backup', null, InputOption::VALUE_NONE, 'Should backup be disabled'),
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'Specify the domain to update'),
))
->setDescription('Updates the translation file')
->setHelp(<<<'EOF'
@@ -65,6 +67,18 @@ EOF
;
}
/**
* {@inheritdoc}
*/
public function isEnabled()
{
if (!class_exists('Symfony\Component\Translation\Translator')) {
return false;
}
return parent::isEnabled();
}
/**
* {@inheritdoc}
*/
@@ -120,7 +134,7 @@ EOF
$extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
$io->comment('Parsing templates...');
$extractor = $this->getContainer()->get('translation.extractor');
$extractor->setPrefix($input->getOption('prefix'));
$extractor->setPrefix($input->getOption('no-prefix') ? '' : $input->getOption('prefix'));
foreach ($transPaths as $path) {
$path .= 'views';
if (is_dir($path)) {
@@ -139,6 +153,11 @@ EOF
}
}
if (null !== $domain = $input->getOption('domain')) {
$currentCatalogue = $this->filterCatalogue($currentCatalogue, $domain);
$extractedCatalogue = $this->filterCatalogue($extractedCatalogue, $domain);
}
// process catalogues
$operation = $input->getOption('clean')
? new TargetOperation($currentCatalogue, $extractedCatalogue)
@@ -160,11 +179,8 @@ EOF
foreach ($operation->getDomains() as $domain) {
$newKeys = array_keys($operation->getNewMessages($domain));
$allKeys = array_keys($operation->getMessages($domain));
$domainMessagesCount = count($newKeys) + count($allKeys);
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d messages)', $domain, $domainMessagesCount));
$io->listing(array_merge(
$list = array_merge(
array_diff($allKeys, $newKeys),
array_map(function ($id) {
return sprintf('<fg=green>%s</>', $id);
@@ -172,7 +188,12 @@ EOF
array_map(function ($id) {
return sprintf('<fg=red>%s</>', $id);
}, array_keys($operation->getObsoleteMessages($domain)))
));
);
$domainMessagesCount = count($list);
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : ''));
$io->listing($list);
$extractedMessagesCount += $domainMessagesCount;
}
@@ -181,7 +202,7 @@ EOF
$io->comment('Xliff output version is <info>1.2</info>');
}
$resultMessage = sprintf('%d messages were successfully extracted', $extractedMessagesCount);
$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
}
if ($input->getOption('no-backup') === true) {
@@ -213,4 +234,23 @@ EOF
$io->success($resultMessage.'.');
}
private function filterCatalogue(MessageCatalogue $catalogue, $domain)
{
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
if ($messages = $catalogue->all($domain)) {
$filteredCatalogue->add($messages, $domain);
}
foreach ($catalogue->getResources() as $resource) {
$filteredCatalogue->addResource($resource);
}
if ($metadata = $catalogue->getMetadata('', $domain)) {
foreach ($metadata as $k => $v) {
$filteredCatalogue->setMetadata($k, $v, $domain);
}
}
return $filteredCatalogue;
}
}
+41 -127
View File
@@ -13,153 +13,67 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Command\LintCommand as BaseLintCommand;
/**
* Validates YAML files syntax and outputs encountered errors.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class YamlLintCommand extends Command
{
private $command;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('lint:yaml');
if (!$this->isEnabled()) {
return;
}
$directoryIteratorProvider = function ($directory, $default) {
if (!is_dir($directory)) {
$directory = $this->getApplication()->getKernel()->locateResource($directory);
}
return $default($directory);
};
$isReadableProvider = function ($fileOrDirectory, $default) {
return 0 === strpos($fileOrDirectory, '@') || $default($fileOrDirectory);
};
$this->command = new BaseLintCommand(null, $directoryIteratorProvider, $isReadableProvider);
$this
->setName('lint:yaml')
->setDescription('Lints a file and outputs encountered errors')
->addArgument('filename', null, 'A file or a directory or STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
->setHelp(<<<EOF
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
the first encountered syntax error.
->setDescription($this->command->getDescription())
->setDefinition($this->command->getDefinition())
->setHelp($this->command->getHelp().<<<'EOF'
You can validate the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
<info>php %command.full_name% dirname --format=json</info>
Or all YAML files in a bundle:
Or find all files in a bundle:
<info>php %command.full_name% @AcmeDemoBundle</info>
You can also pass the YAML contents from STDIN:
<info>cat filename | php %command.full_name%</info>
EOF
)
;
);
}
/**
* {@inheritdoc}
*/
public function isEnabled()
{
return class_exists(BaseLintCommand::class) && parent::isEnabled();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$filename = $input->getArgument('filename');
if (!$filename) {
if (0 !== ftell(STDIN)) {
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
$content = '';
while (!feof(STDIN)) {
$content .= fread(STDIN, 1024);
}
return $this->display($input, $output, $io, array($this->validate($content)));
}
if (0 !== strpos($filename, '@') && !is_readable($filename)) {
throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
}
$files = array();
if (is_file($filename)) {
$files = array($filename);
} elseif (is_dir($filename)) {
$files = Finder::create()->files()->in($filename)->name('*.yml');
} else {
$dir = $this->getApplication()->getKernel()->locateResource($filename);
$files = Finder::create()->files()->in($dir)->name('*.yml');
}
$filesInfo = array();
foreach ($files as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $file);
}
return $this->display($input, $output, $io, $filesInfo);
}
private function validate($content, $file = null)
{
$parser = new Parser();
try {
$parser->parse($content);
} catch (ParseException $e) {
return array('file' => $file, 'valid' => false, 'message' => $e->getMessage());
}
return array('file' => $file, 'valid' => true);
}
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files)
{
switch ($input->getOption('format')) {
case 'txt':
return $this->displayTxt($output, $io, $files);
case 'json':
return $this->displayJson($io, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
}
}
private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo)
{
$errors = 0;
foreach ($filesInfo as $info) {
if ($info['valid'] && $output->isVerbose()) {
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$errors;
$io->text(sprintf('<error> ERROR </error> in %s', $info['file']));
$io->text(sprintf('<error> >> %s</error>', $info['message']));
}
}
if ($errors === 0) {
$io->success(sprintf('All %d YAML files contain valid syntax.', count($filesInfo)));
} else {
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', count($filesInfo) - $errors, $errors));
}
return min($errors, 1);
}
private function displayJson(OutputInterface $output, $filesInfo)
{
$errors = 0;
array_walk($filesInfo, function (&$v) use (&$errors) {
$v['file'] = (string) $v['file'];
if (!$v['valid']) {
++$errors;
}
});
$output->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT));
return min($errors, 1);
return $this->command->execute($input, $output);
}
}