Ajout des vendor
This commit is contained in:
136
vendor/symfony/framework-bundle/Command/AboutCommand.php
vendored
Normal file
136
vendor/symfony/framework-bundle/Command/AboutCommand.php
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Helper;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* A console command to display information about the current installation.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AboutCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'about';
|
||||
protected static $defaultDescription = 'Display information about the current project';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOT'
|
||||
The <info>%command.name%</info> command displays information about the current Symfony project.
|
||||
|
||||
The <info>PHP</info> section displays important configuration that could affect your application. The values might
|
||||
be different between web and CLI.
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
if (method_exists($kernel, 'getBuildDir')) {
|
||||
$buildDir = $kernel->getBuildDir();
|
||||
} else {
|
||||
$buildDir = $kernel->getCacheDir();
|
||||
}
|
||||
|
||||
$rows = [
|
||||
['<info>Symfony</>'],
|
||||
new TableSeparator(),
|
||||
['Version', Kernel::VERSION],
|
||||
['Long-Term Support', 4 === Kernel::MINOR_VERSION ? 'Yes' : 'No'],
|
||||
['End of maintenance', Kernel::END_OF_MAINTENANCE.(self::isExpired(Kernel::END_OF_MAINTENANCE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_MAINTENANCE).'</>)')],
|
||||
['End of life', Kernel::END_OF_LIFE.(self::isExpired(Kernel::END_OF_LIFE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_LIFE).'</>)')],
|
||||
new TableSeparator(),
|
||||
['<info>Kernel</>'],
|
||||
new TableSeparator(),
|
||||
['Type', \get_class($kernel)],
|
||||
['Environment', $kernel->getEnvironment()],
|
||||
['Debug', $kernel->isDebug() ? 'true' : 'false'],
|
||||
['Charset', $kernel->getCharset()],
|
||||
['Cache directory', self::formatPath($kernel->getCacheDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getCacheDir()).'</>)'],
|
||||
['Build directory', self::formatPath($buildDir, $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($buildDir).'</>)'],
|
||||
['Log directory', self::formatPath($kernel->getLogDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getLogDir()).'</>)'],
|
||||
new TableSeparator(),
|
||||
['<info>PHP</>'],
|
||||
new TableSeparator(),
|
||||
['Version', \PHP_VERSION],
|
||||
['Architecture', (\PHP_INT_SIZE * 8).' bits'],
|
||||
['Intl locale', class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a'],
|
||||
['Timezone', date_default_timezone_get().' (<comment>'.(new \DateTime())->format(\DateTime::W3C).'</>)'],
|
||||
['OPcache', \extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false'],
|
||||
['APCu', \extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false'],
|
||||
['Xdebug', \extension_loaded('xdebug') ? 'true' : 'false'],
|
||||
];
|
||||
|
||||
$io->table([], $rows);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static function formatPath(string $path, string $baseDir): string
|
||||
{
|
||||
return preg_replace('~^'.preg_quote($baseDir, '~').'~', '.', $path);
|
||||
}
|
||||
|
||||
private static function formatFileSize(string $path): string
|
||||
{
|
||||
if (is_file($path)) {
|
||||
$size = filesize($path) ?: 0;
|
||||
} else {
|
||||
$size = 0;
|
||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)) as $file) {
|
||||
if ($file->isReadable()) {
|
||||
$size += $file->getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Helper::formatMemory($size);
|
||||
}
|
||||
|
||||
private static function isExpired(string $date): bool
|
||||
{
|
||||
$date = \DateTime::createFromFormat('d/m/Y', '01/'.$date);
|
||||
|
||||
return false !== $date && new \DateTime() > $date->modify('last day of this month 23:59:59');
|
||||
}
|
||||
|
||||
private static function daysBeforeExpiration(string $date): string
|
||||
{
|
||||
$date = \DateTime::createFromFormat('d/m/Y', '01/'.$date);
|
||||
|
||||
return (new \DateTime())->diff($date->modify('last day of this month 23:59:59'))->format('in %R%a days');
|
||||
}
|
||||
}
|
159
vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php
vendored
Normal file
159
vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\StyleInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
abstract class AbstractConfigCommand extends ContainerDebugCommand
|
||||
{
|
||||
/**
|
||||
* @param OutputInterface|StyleInterface $output
|
||||
*/
|
||||
protected function listBundles($output)
|
||||
{
|
||||
$title = 'Available registered bundles with their extension alias if available';
|
||||
$headers = ['Bundle name', 'Extension alias'];
|
||||
$rows = [];
|
||||
|
||||
$bundles = $this->getApplication()->getKernel()->getBundles();
|
||||
usort($bundles, function ($bundleA, $bundleB) {
|
||||
return strcmp($bundleA->getName(), $bundleB->getName());
|
||||
});
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
$extension = $bundle->getContainerExtension();
|
||||
$rows[] = [$bundle->getName(), $extension ? $extension->getAlias() : ''];
|
||||
}
|
||||
|
||||
if ($output instanceof StyleInterface) {
|
||||
$output->title($title);
|
||||
$output->table($headers, $rows);
|
||||
} else {
|
||||
$output->writeln($title);
|
||||
$table = new Table($output);
|
||||
$table->setHeaders($headers)->setRows($rows)->render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExtensionInterface
|
||||
*/
|
||||
protected function findExtension(string $name)
|
||||
{
|
||||
$bundles = $this->initializeBundles();
|
||||
$minScore = \INF;
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($kernel instanceof ExtensionInterface && ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)) {
|
||||
if ($name === $kernel->getAlias()) {
|
||||
return $kernel;
|
||||
}
|
||||
|
||||
if ($kernel->getAlias()) {
|
||||
$distance = levenshtein($name, $kernel->getAlias());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $kernel->getAlias();
|
||||
$minScore = $distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
if ($name === $bundle->getName()) {
|
||||
if (!$bundle->getContainerExtension()) {
|
||||
throw new \LogicException(sprintf('Bundle "%s" does not have a container extension.', $name));
|
||||
}
|
||||
|
||||
return $bundle->getContainerExtension();
|
||||
}
|
||||
|
||||
$distance = levenshtein($name, $bundle->getName());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $bundle->getName();
|
||||
$minScore = $distance;
|
||||
}
|
||||
|
||||
$extension = $bundle->getContainerExtension();
|
||||
|
||||
if ($extension) {
|
||||
if ($name === $extension->getAlias()) {
|
||||
return $extension;
|
||||
}
|
||||
|
||||
$distance = levenshtein($name, $extension->getAlias());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $extension->getAlias();
|
||||
$minScore = $distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!str_ends_with($name, 'Bundle')) {
|
||||
$message = sprintf('No extensions with configuration available for "%s".', $name);
|
||||
} else {
|
||||
$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);
|
||||
}
|
||||
|
||||
public function validateConfiguration(ExtensionInterface $extension, $configuration)
|
||||
{
|
||||
if (!$configuration) {
|
||||
throw new \LogicException(sprintf('The extension with alias "%s" does not have its getConfiguration() method setup.', $extension->getAlias()));
|
||||
}
|
||||
|
||||
if (!$configuration instanceof ConfigurationInterface) {
|
||||
throw new \LogicException(sprintf('Configuration class "%s" should implement ConfigurationInterface in order to be dumpable.', get_debug_type($configuration)));
|
||||
}
|
||||
}
|
||||
|
||||
private function initializeBundles()
|
||||
{
|
||||
// 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.
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$container = $this->getContainerBuilder($kernel);
|
||||
$bundles = $kernel->getBundles();
|
||||
foreach ($bundles as $bundle) {
|
||||
if ($extension = $bundle->getContainerExtension()) {
|
||||
$container->registerExtension($extension);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
$bundle->build($container);
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
}
|
279
vendor/symfony/framework-bundle/Command/AssetsInstallCommand.php
vendored
Normal file
279
vendor/symfony/framework-bundle/Command/AssetsInstallCommand.php
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* Command that places bundle web assets into a given directory.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Gábor Egyed <gabor.egyed@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AssetsInstallCommand extends Command
|
||||
{
|
||||
public const METHOD_COPY = 'copy';
|
||||
public const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
|
||||
public const METHOD_RELATIVE_SYMLINK = 'relative symlink';
|
||||
|
||||
protected static $defaultName = 'assets:install';
|
||||
protected static $defaultDescription = 'Install bundle\'s web assets under a public directory';
|
||||
|
||||
private $filesystem;
|
||||
private $projectDir;
|
||||
|
||||
public function __construct(Filesystem $filesystem, string $projectDir)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->filesystem = $filesystem;
|
||||
$this->projectDir = $projectDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null),
|
||||
])
|
||||
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlink the assets instead of copying them')
|
||||
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
|
||||
->addOption('no-cleanup', null, InputOption::VALUE_NONE, 'Do not remove the assets of the bundles that no longer exist')
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOT'
|
||||
The <info>%command.name%</info> command installs bundle assets into a given
|
||||
directory (e.g. the <comment>public</comment> directory).
|
||||
|
||||
<info>php %command.full_name% public</info>
|
||||
|
||||
A "bundles" directory will be created inside the target directory and the
|
||||
"Resources/public" directory of each bundle will be copied into it.
|
||||
|
||||
To create a symlink to each bundle instead of copying its assets, use the
|
||||
<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible:
|
||||
|
||||
<info>php %command.full_name% public --symlink</info>
|
||||
|
||||
To make symlink relative, add the <info>--relative</info> option:
|
||||
|
||||
<info>php %command.full_name% public --symlink --relative</info>
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$targetArg = rtrim($input->getArgument('target') ?? '', '/');
|
||||
if (!$targetArg) {
|
||||
$targetArg = $this->getPublicDirectory($kernel->getContainer());
|
||||
}
|
||||
|
||||
if (!is_dir($targetArg)) {
|
||||
$targetArg = $kernel->getProjectDir().'/'.$targetArg;
|
||||
|
||||
if (!is_dir($targetArg)) {
|
||||
throw new InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $targetArg));
|
||||
}
|
||||
}
|
||||
|
||||
$bundlesDir = $targetArg.'/bundles/';
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->newLine();
|
||||
|
||||
if ($input->getOption('relative')) {
|
||||
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
|
||||
$io->text('Trying to install assets as <info>relative symbolic links</info>.');
|
||||
} elseif ($input->getOption('symlink')) {
|
||||
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
|
||||
$io->text('Trying to install assets as <info>absolute symbolic links</info>.');
|
||||
} else {
|
||||
$expectedMethod = self::METHOD_COPY;
|
||||
$io->text('Installing assets as <info>hard copies</info>.');
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
$rows = [];
|
||||
$copyUsed = false;
|
||||
$exitCode = 0;
|
||||
$validAssetDirs = [];
|
||||
/** @var BundleInterface $bundle */
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
if (!is_dir($originDir = $bundle->getPath().'/Resources/public') && !is_dir($originDir = $bundle->getPath().'/public')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$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);
|
||||
} else {
|
||||
$message = $bundle->getName();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->filesystem->remove($targetDir);
|
||||
|
||||
if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
|
||||
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
|
||||
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
|
||||
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
|
||||
} else {
|
||||
$method = $this->hardCopy($originDir, $targetDir);
|
||||
}
|
||||
|
||||
if (self::METHOD_COPY === $method) {
|
||||
$copyUsed = true;
|
||||
}
|
||||
|
||||
if ($method === $expectedMethod) {
|
||||
$rows[] = [sprintf('<fg=green;options=bold>%s</>', '\\' === \DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method];
|
||||
} else {
|
||||
$rows[] = [sprintf('<fg=yellow;options=bold>%s</>', '\\' === \DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$exitCode = 1;
|
||||
$rows[] = [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
|
||||
if (!$input->getOption('no-cleanup') && is_dir($bundlesDir)) {
|
||||
$dirsToRemove = Finder::create()->depth(0)->directories()->exclude($validAssetDirs)->in($bundlesDir);
|
||||
$this->filesystem->remove($dirsToRemove);
|
||||
}
|
||||
|
||||
if ($rows) {
|
||||
$io->table(['', 'Bundle', 'Method / Error'], $rows);
|
||||
}
|
||||
|
||||
if (0 !== $exitCode) {
|
||||
$io->error('Some errors occurred while installing assets.');
|
||||
} else {
|
||||
if ($copyUsed) {
|
||||
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
|
||||
}
|
||||
$io->success($rows ? 'All assets were successfully installed.' : 'No assets were provided by any bundle.');
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create relative symlink.
|
||||
*
|
||||
* Falling back to absolute symlink and finally hard copy.
|
||||
*/
|
||||
private function relativeSymlinkWithFallback(string $originDir, string $targetDir): string
|
||||
{
|
||||
try {
|
||||
$this->symlink($originDir, $targetDir, true);
|
||||
$method = self::METHOD_RELATIVE_SYMLINK;
|
||||
} catch (IOException $e) {
|
||||
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
|
||||
}
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create absolute symlink.
|
||||
*
|
||||
* Falling back to hard copy.
|
||||
*/
|
||||
private function absoluteSymlinkWithFallback(string $originDir, string $targetDir): string
|
||||
{
|
||||
try {
|
||||
$this->symlink($originDir, $targetDir);
|
||||
$method = self::METHOD_ABSOLUTE_SYMLINK;
|
||||
} catch (IOException $e) {
|
||||
// fall back to copy
|
||||
$method = $this->hardCopy($originDir, $targetDir);
|
||||
}
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
*
|
||||
* @throws IOException if link cannot be created
|
||||
*/
|
||||
private function symlink(string $originDir, string $targetDir, bool $relative = false)
|
||||
{
|
||||
if ($relative) {
|
||||
$this->filesystem->mkdir(\dirname($targetDir));
|
||||
$originDir = $this->filesystem->makePathRelative($originDir, realpath(\dirname($targetDir)));
|
||||
}
|
||||
$this->filesystem->symlink($originDir, $targetDir);
|
||||
if (!file_exists($targetDir)) {
|
||||
throw new IOException(sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir), 0, null, $targetDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies origin to target.
|
||||
*/
|
||||
private function hardCopy(string $originDir, string $targetDir): string
|
||||
{
|
||||
$this->filesystem->mkdir($targetDir, 0777);
|
||||
// We use a custom iterator to ignore VCS files
|
||||
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
|
||||
|
||||
return self::METHOD_COPY;
|
||||
}
|
||||
|
||||
private function getPublicDirectory(ContainerInterface $container): string
|
||||
{
|
||||
$defaultPublicDir = 'public';
|
||||
|
||||
if (null === $this->projectDir && !$container->hasParameter('kernel.project_dir')) {
|
||||
return $defaultPublicDir;
|
||||
}
|
||||
|
||||
$composerFilePath = ($this->projectDir ?? $container->getParameter('kernel.project_dir')).'/composer.json';
|
||||
|
||||
if (!file_exists($composerFilePath)) {
|
||||
return $defaultPublicDir;
|
||||
}
|
||||
|
||||
$composerConfig = json_decode(file_get_contents($composerFilePath), true);
|
||||
|
||||
return $composerConfig['extra']['public-dir'] ?? $defaultPublicDir;
|
||||
}
|
||||
}
|
64
vendor/symfony/framework-bundle/Command/BuildDebugContainerTrait.php
vendored
Normal file
64
vendor/symfony/framework-bundle/Command/BuildDebugContainerTrait.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
trait BuildDebugContainerTrait
|
||||
{
|
||||
protected $containerBuilder;
|
||||
|
||||
/**
|
||||
* Loads the ContainerBuilder from the cache.
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilder
|
||||
{
|
||||
if ($this->containerBuilder) {
|
||||
return $this->containerBuilder;
|
||||
}
|
||||
|
||||
if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
|
||||
$buildContainer = \Closure::bind(function () {
|
||||
$this->initializeBundles();
|
||||
|
||||
return $this->buildContainer();
|
||||
}, $kernel, \get_class($kernel));
|
||||
$container = $buildContainer();
|
||||
$container->getCompilerPassConfig()->setRemovingPasses([]);
|
||||
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
|
||||
$container->compile();
|
||||
} else {
|
||||
(new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
|
||||
$locatorPass = new ServiceLocatorTagPass();
|
||||
$locatorPass->process($container);
|
||||
|
||||
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
|
||||
}
|
||||
|
||||
return $this->containerBuilder = $container;
|
||||
}
|
||||
}
|
261
vendor/symfony/framework-bundle/Command/CacheClearCommand.php
vendored
Normal file
261
vendor/symfony/framework-bundle/Command/CacheClearCommand.php
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
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\DependencyInjection\Dumper\Preloader;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
|
||||
use Symfony\Component\HttpKernel\RebootableInterface;
|
||||
|
||||
/**
|
||||
* Clear and Warmup the cache.
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CacheClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:clear';
|
||||
protected static $defaultDescription = 'Clear the cache';
|
||||
|
||||
private $cacheClearer;
|
||||
private $filesystem;
|
||||
|
||||
public function __construct(CacheClearerInterface $cacheClearer, Filesystem $filesystem = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->cacheClearer = $cacheClearer;
|
||||
$this->filesystem = $filesystem ?? new Filesystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputOption('no-warmup', '', InputOption::VALUE_NONE, 'Do not warm up the cache'),
|
||||
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command clears and warms up the application cache for a given environment
|
||||
and debug mode:
|
||||
|
||||
<info>php %command.full_name% --env=dev</info>
|
||||
<info>php %command.full_name% --env=prod --no-debug</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$fs = $this->filesystem;
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$realCacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir');
|
||||
$realBuildDir = $kernel->getContainer()->hasParameter('kernel.build_dir') ? $kernel->getContainer()->getParameter('kernel.build_dir') : $realCacheDir;
|
||||
// the old cache dir name must not be longer than the real one to avoid exceeding
|
||||
// the maximum length of a directory or file path within it (esp. Windows MAX_PATH)
|
||||
$oldCacheDir = substr($realCacheDir, 0, -1).(str_ends_with($realCacheDir, '~') ? '+' : '~');
|
||||
$fs->remove($oldCacheDir);
|
||||
|
||||
if (!is_writable($realCacheDir)) {
|
||||
throw new RuntimeException(sprintf('Unable to write in the "%s" directory.', $realCacheDir));
|
||||
}
|
||||
|
||||
$useBuildDir = $realBuildDir !== $realCacheDir;
|
||||
$oldBuildDir = substr($realBuildDir, 0, -1).('~' === substr($realBuildDir, -1) ? '+' : '~');
|
||||
if ($useBuildDir) {
|
||||
$fs->remove($oldBuildDir);
|
||||
|
||||
if (!is_writable($realBuildDir)) {
|
||||
throw new RuntimeException(sprintf('Unable to write in the "%s" directory.', $realBuildDir));
|
||||
}
|
||||
|
||||
if ($this->isNfs($realCacheDir)) {
|
||||
$fs->remove($realCacheDir);
|
||||
} else {
|
||||
$fs->rename($realCacheDir, $oldCacheDir);
|
||||
}
|
||||
$fs->mkdir($realCacheDir);
|
||||
}
|
||||
|
||||
$io->comment(sprintf('Clearing the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
if ($useBuildDir) {
|
||||
$this->cacheClearer->clear($realBuildDir);
|
||||
}
|
||||
$this->cacheClearer->clear($realCacheDir);
|
||||
|
||||
// The current event dispatcher is stale, let's not use it anymore
|
||||
$this->getApplication()->setDispatcher(new EventDispatcher());
|
||||
|
||||
$containerFile = (new \ReflectionObject($kernel->getContainer()))->getFileName();
|
||||
$containerDir = basename(\dirname($containerFile));
|
||||
|
||||
// the warmup cache dir name must have the same length as the real one
|
||||
// to avoid the many problems in serialized resources files
|
||||
$warmupDir = substr($realBuildDir, 0, -1).('_' === substr($realBuildDir, -1) ? '-' : '_');
|
||||
|
||||
if ($output->isVerbose() && $fs->exists($warmupDir)) {
|
||||
$io->comment('Clearing outdated warmup directory...');
|
||||
}
|
||||
$fs->remove($warmupDir);
|
||||
|
||||
if ($_SERVER['REQUEST_TIME'] <= filemtime($containerFile) && filemtime($containerFile) <= time()) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Cache is fresh.');
|
||||
}
|
||||
if (!$input->getOption('no-warmup') && !$input->getOption('no-optional-warmers')) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Warming up optional cache...');
|
||||
}
|
||||
$warmer = $kernel->getContainer()->get('cache_warmer');
|
||||
// non optional warmers already ran during container compilation
|
||||
$warmer->enableOnlyOptionalWarmers();
|
||||
$preload = (array) $warmer->warmUp($realCacheDir);
|
||||
|
||||
if ($preload && file_exists($preloadFile = $realCacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
|
||||
Preloader::append($preloadFile, $preload);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fs->mkdir($warmupDir);
|
||||
|
||||
if (!$input->getOption('no-warmup')) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Warming up cache...');
|
||||
}
|
||||
$this->warmup($warmupDir, $realCacheDir, !$input->getOption('no-optional-warmers'));
|
||||
}
|
||||
|
||||
if (!$fs->exists($warmupDir.'/'.$containerDir)) {
|
||||
$fs->rename($realBuildDir.'/'.$containerDir, $warmupDir.'/'.$containerDir);
|
||||
touch($warmupDir.'/'.$containerDir.'.legacy');
|
||||
}
|
||||
|
||||
if ($this->isNfs($realBuildDir)) {
|
||||
$io->note('For better performances, you should move the cache and log directories to a non-shared folder of the VM.');
|
||||
$fs->remove($realBuildDir);
|
||||
} else {
|
||||
$fs->rename($realBuildDir, $oldBuildDir);
|
||||
}
|
||||
|
||||
$fs->rename($warmupDir, $realBuildDir);
|
||||
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Removing old build and cache directory...');
|
||||
}
|
||||
|
||||
if ($useBuildDir) {
|
||||
try {
|
||||
$fs->remove($oldBuildDir);
|
||||
} catch (IOException $e) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->warning($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$fs->remove($oldCacheDir);
|
||||
} catch (IOException $e) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->warning($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Finished');
|
||||
}
|
||||
|
||||
$io->success(sprintf('Cache for the "%s" environment (debug=%s) was successfully cleared.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function isNfs(string $dir): bool
|
||||
{
|
||||
static $mounts = null;
|
||||
|
||||
if (null === $mounts) {
|
||||
$mounts = [];
|
||||
if ('/' === \DIRECTORY_SEPARATOR && $files = @file('/proc/mounts')) {
|
||||
foreach ($files as $mount) {
|
||||
$mount = \array_slice(explode(' ', $mount), 1, -3);
|
||||
if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) {
|
||||
continue;
|
||||
}
|
||||
$mounts[] = implode(' ', $mount).'/';
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($mounts as $mount) {
|
||||
if (0 === strpos($dir, $mount)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function warmup(string $warmupDir, string $realBuildDir, bool $enableOptionalWarmers = true)
|
||||
{
|
||||
// create a temporary kernel
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if (!$kernel instanceof RebootableInterface) {
|
||||
throw new \LogicException('Calling "cache:clear" with a kernel that does not implement "Symfony\Component\HttpKernel\RebootableInterface" is not supported.');
|
||||
}
|
||||
$kernel->reboot($warmupDir);
|
||||
|
||||
// warmup temporary dir
|
||||
if ($enableOptionalWarmers) {
|
||||
$warmer = $kernel->getContainer()->get('cache_warmer');
|
||||
// non optional warmers already ran during container compilation
|
||||
$warmer->enableOnlyOptionalWarmers();
|
||||
$preload = (array) $warmer->warmUp($warmupDir);
|
||||
|
||||
if ($preload && file_exists($preloadFile = $warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
|
||||
Preloader::append($preloadFile, $preload);
|
||||
}
|
||||
}
|
||||
|
||||
// fix references to cached files with the real cache directory name
|
||||
$search = [$warmupDir, str_replace('\\', '\\\\', $warmupDir)];
|
||||
$replace = str_replace('\\', '/', $realBuildDir);
|
||||
foreach (Finder::create()->files()->in($warmupDir) as $file) {
|
||||
$content = str_replace($search, $replace, file_get_contents($file), $count);
|
||||
if ($count) {
|
||||
file_put_contents($file, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
vendor/symfony/framework-bundle/Command/CachePoolClearCommand.php
vendored
Normal file
131
vendor/symfony/framework-bundle/Command/CachePoolClearCommand.php
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
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\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
|
||||
/**
|
||||
* Clear cache pools.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class CachePoolClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:pool:clear';
|
||||
protected static $defaultDescription = 'Clear cache pools';
|
||||
|
||||
private $poolClearer;
|
||||
private $poolNames;
|
||||
|
||||
/**
|
||||
* @param string[]|null $poolNames
|
||||
*/
|
||||
public function __construct(Psr6CacheClearer $poolClearer, array $poolNames = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->poolClearer = $poolClearer;
|
||||
$this->poolNames = $poolNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('pools', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'A list of cache pools or cache pool clearers'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command clears the given cache pools or cache pool clearers.
|
||||
|
||||
%command.full_name% <cache pool or clearer 1> [...<cache pool or clearer N>]
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$pools = [];
|
||||
$clearers = [];
|
||||
|
||||
foreach ($input->getArgument('pools') as $id) {
|
||||
if ($this->poolClearer->hasPool($id)) {
|
||||
$pools[$id] = $id;
|
||||
} else {
|
||||
$pool = $kernel->getContainer()->get($id);
|
||||
|
||||
if ($pool instanceof CacheItemPoolInterface) {
|
||||
$pools[$id] = $pool;
|
||||
} elseif ($pool instanceof Psr6CacheClearer) {
|
||||
$clearers[$id] = $pool;
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($clearers as $id => $clearer) {
|
||||
$io->comment(sprintf('Calling cache clearer: <info>%s</info>', $id));
|
||||
$clearer->clear($kernel->getContainer()->getParameter('kernel.cache_dir'));
|
||||
}
|
||||
|
||||
$failure = false;
|
||||
foreach ($pools as $id => $pool) {
|
||||
$io->comment(sprintf('Clearing cache pool: <info>%s</info>', $id));
|
||||
|
||||
if ($pool instanceof CacheItemPoolInterface) {
|
||||
if (!$pool->clear()) {
|
||||
$io->warning(sprintf('Cache pool "%s" could not be cleared.', $pool));
|
||||
$failure = true;
|
||||
}
|
||||
} else {
|
||||
if (false === $this->poolClearer->clearPool($id)) {
|
||||
$io->warning(sprintf('Cache pool "%s" could not be cleared.', $pool));
|
||||
$failure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($failure) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success('Cache was successfully cleared.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (\is_array($this->poolNames) && $input->mustSuggestArgumentValuesFor('pools')) {
|
||||
$suggestions->suggestValues($this->poolNames);
|
||||
}
|
||||
}
|
||||
}
|
98
vendor/symfony/framework-bundle/Command/CachePoolDeleteCommand.php
vendored
Normal file
98
vendor/symfony/framework-bundle/Command/CachePoolDeleteCommand.php
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
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\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
|
||||
/**
|
||||
* Delete an item from a cache pool.
|
||||
*
|
||||
* @author Pierre du Plessis <pdples@gmail.com>
|
||||
*/
|
||||
final class CachePoolDeleteCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:pool:delete';
|
||||
protected static $defaultDescription = 'Delete an item from a cache pool';
|
||||
|
||||
private $poolClearer;
|
||||
private $poolNames;
|
||||
|
||||
/**
|
||||
* @param string[]|null $poolNames
|
||||
*/
|
||||
public function __construct(Psr6CacheClearer $poolClearer, array $poolNames = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->poolClearer = $poolClearer;
|
||||
$this->poolNames = $poolNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('pool', InputArgument::REQUIRED, 'The cache pool from which to delete an item'),
|
||||
new InputArgument('key', InputArgument::REQUIRED, 'The cache key to delete from the pool'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> deletes an item from a given cache pool.
|
||||
|
||||
%command.full_name% <pool> <key>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$pool = $input->getArgument('pool');
|
||||
$key = $input->getArgument('key');
|
||||
$cachePool = $this->poolClearer->getPool($pool);
|
||||
|
||||
if (!$cachePool->hasItem($key)) {
|
||||
$io->note(sprintf('Cache item "%s" does not exist in cache pool "%s".', $key, $pool));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$cachePool->deleteItem($key)) {
|
||||
throw new \Exception(sprintf('Cache item "%s" could not be deleted.', $key));
|
||||
}
|
||||
|
||||
$io->success(sprintf('Cache item "%s" was successfully deleted.', $key));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (\is_array($this->poolNames) && $input->mustSuggestArgumentValuesFor('pool')) {
|
||||
$suggestions->suggestValues($this->poolNames);
|
||||
}
|
||||
}
|
||||
}
|
68
vendor/symfony/framework-bundle/Command/CachePoolListCommand.php
vendored
Normal file
68
vendor/symfony/framework-bundle/Command/CachePoolListCommand.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* List available cache pools.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
final class CachePoolListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:pool:list';
|
||||
protected static $defaultDescription = 'List available cache pools';
|
||||
|
||||
private $poolNames;
|
||||
|
||||
/**
|
||||
* @param string[] $poolNames
|
||||
*/
|
||||
public function __construct(array $poolNames)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->poolNames = $poolNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command lists all available cache pools.
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->table(['Pool name'], array_map(function ($pool) {
|
||||
return [$pool];
|
||||
}, $this->poolNames));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
74
vendor/symfony/framework-bundle/Command/CachePoolPruneCommand.php
vendored
Normal file
74
vendor/symfony/framework-bundle/Command/CachePoolPruneCommand.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Cache pool pruner command.
|
||||
*
|
||||
* @author Rob Frawley 2nd <rmf@src.run>
|
||||
*/
|
||||
final class CachePoolPruneCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:pool:prune';
|
||||
protected static $defaultDescription = 'Prune cache pools';
|
||||
|
||||
private $pools;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, PruneableInterface> $pools
|
||||
*/
|
||||
public function __construct(iterable $pools)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->pools = $pools;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command deletes all expired items from all pruneable pools.
|
||||
|
||||
%command.full_name%
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
foreach ($this->pools as $name => $pool) {
|
||||
$io->comment(sprintf('Pruning cache pool: <info>%s</info>', $name));
|
||||
$pool->prune();
|
||||
}
|
||||
|
||||
$io->success('Successfully pruned cache pool(s).');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
92
vendor/symfony/framework-bundle/Command/CacheWarmupCommand.php
vendored
Normal file
92
vendor/symfony/framework-bundle/Command/CacheWarmupCommand.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
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\DependencyInjection\Dumper\Preloader;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
|
||||
|
||||
/**
|
||||
* Warmup the cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CacheWarmupCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:warmup';
|
||||
protected static $defaultDescription = 'Warm up an empty cache';
|
||||
|
||||
private $cacheWarmer;
|
||||
|
||||
public function __construct(CacheWarmerAggregate $cacheWarmer)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->cacheWarmer = $cacheWarmer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command warms up the cache.
|
||||
|
||||
Before running this command, the cache must be empty.
|
||||
|
||||
This command does not generate the classes cache (as when executing this
|
||||
command, too many classes that should be part of the cache are already loaded
|
||||
in memory). Use <comment>curl</comment> or any other similar tool to warm up
|
||||
the classes cache if you want.
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$io->comment(sprintf('Warming up the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
if (!$input->getOption('no-optional-warmers')) {
|
||||
$this->cacheWarmer->enableOptionalWarmers();
|
||||
}
|
||||
|
||||
$preload = $this->cacheWarmer->warmUp($cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir'));
|
||||
|
||||
if ($preload && file_exists($preloadFile = $cacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
|
||||
Preloader::append($preloadFile, $preload);
|
||||
}
|
||||
|
||||
$io->success(sprintf('Cache for the "%s" environment (debug=%s) was successfully warmed.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
240
vendor/symfony/framework-bundle/Command/ConfigDebugCommand.php
vendored
Normal file
240
vendor/symfony/framework-bundle/Command/ConfigDebugCommand.php
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
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\DependencyInjection\Compiler\ValidateEnvPlaceholdersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ConfigDebugCommand extends AbstractConfigCommand
|
||||
{
|
||||
protected static $defaultName = 'debug:config';
|
||||
protected static $defaultDescription = 'Dump the current configuration for an extension';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'),
|
||||
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command dumps the current configuration for an
|
||||
extension/bundle.
|
||||
|
||||
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
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
if (null === $name = $input->getArgument('name')) {
|
||||
$this->listBundles($errorIo);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($kernel instanceof ExtensionInterface
|
||||
&& ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)
|
||||
&& $kernel->getAlias()
|
||||
) {
|
||||
$errorIo->table(['Kernel Extension'], [[$kernel->getAlias()]]);
|
||||
}
|
||||
|
||||
$errorIo->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>)');
|
||||
$errorIo->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 0;
|
||||
}
|
||||
|
||||
$extension = $this->findExtension($name);
|
||||
$extensionAlias = $extension->getAlias();
|
||||
$container = $this->compileContainer();
|
||||
|
||||
$config = $this->getConfig($extension, $container);
|
||||
|
||||
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([$extensionAlias => $config], 10));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
$config = $this->getConfigForPath($config, $path, $extensionAlias);
|
||||
} catch (LogicException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->title(sprintf('Current configuration for "%s.%s"', $extensionAlias, $path));
|
||||
|
||||
$io->writeln(Yaml::dump($config, 10));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function compileContainer(): ContainerBuilder
|
||||
{
|
||||
$kernel = clone $this->getApplication()->getKernel();
|
||||
$kernel->boot();
|
||||
|
||||
$method = new \ReflectionMethod($kernel, 'buildContainer');
|
||||
$method->setAccessible(true);
|
||||
$container = $method->invoke($kernel);
|
||||
$container->getCompiler()->compile($container);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over configuration until the last step of the given path.
|
||||
*
|
||||
* @throws LogicException If the configuration does not exist
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getConfigForPath(array $config, string $path, string $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;
|
||||
}
|
||||
|
||||
private function getConfigForExtension(ExtensionInterface $extension, ContainerBuilder $container): array
|
||||
{
|
||||
$extensionAlias = $extension->getAlias();
|
||||
|
||||
$extensionConfig = [];
|
||||
foreach ($container->getCompilerPassConfig()->getPasses() as $pass) {
|
||||
if ($pass instanceof ValidateEnvPlaceholdersPass) {
|
||||
$extensionConfig = $pass->getExtensionConfig();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($extensionConfig[$extensionAlias])) {
|
||||
return $extensionConfig[$extensionAlias];
|
||||
}
|
||||
|
||||
// Fall back to default config if the extension has one
|
||||
|
||||
if (!$extension instanceof ConfigurationExtensionInterface) {
|
||||
throw new \LogicException(sprintf('The extension with alias "%s" does not have configuration.', $extensionAlias));
|
||||
}
|
||||
|
||||
$configs = $container->getExtensionConfig($extensionAlias);
|
||||
$configuration = $extension->getConfiguration($configs, $container);
|
||||
$this->validateConfiguration($extension, $configuration);
|
||||
|
||||
return (new Processor())->processConfiguration($configuration, $configs);
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues($this->getAvailableBundles(!preg_match('/^[A-Z]/', $input->getCompletionValue())));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('path') && null !== $name = $input->getArgument('name')) {
|
||||
try {
|
||||
$config = $this->getConfig($this->findExtension($name), $this->compileContainer());
|
||||
$paths = array_keys(self::buildPathsCompletion($config));
|
||||
$suggestions->suggestValues($paths);
|
||||
} catch (LogicException $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getAvailableBundles(bool $alias): array
|
||||
{
|
||||
$availableBundles = [];
|
||||
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
|
||||
$availableBundles[] = $alias ? $bundle->getContainerExtension()->getAlias() : $bundle->getName();
|
||||
}
|
||||
|
||||
return $availableBundles;
|
||||
}
|
||||
|
||||
private function getConfig(ExtensionInterface $extension, ContainerBuilder $container)
|
||||
{
|
||||
return $container->resolveEnvPlaceholders(
|
||||
$container->getParameterBag()->resolveValue(
|
||||
$this->getConfigForExtension($extension, $container)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static function buildPathsCompletion(array $paths, string $prefix = ''): array
|
||||
{
|
||||
$completionPaths = [];
|
||||
foreach ($paths as $key => $values) {
|
||||
if (\is_array($values)) {
|
||||
$completionPaths = $completionPaths + self::buildPathsCompletion($values, $prefix.$key.'.');
|
||||
} else {
|
||||
$completionPaths[$prefix.$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $completionPaths;
|
||||
}
|
||||
}
|
190
vendor/symfony/framework-bundle/Command/ConfigDumpReferenceCommand.php
vendored
Normal file
190
vendor/symfony/framework-bundle/Command/ConfigDumpReferenceCommand.php
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
|
||||
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ConfigDumpReferenceCommand extends AbstractConfigCommand
|
||||
{
|
||||
protected static $defaultName = 'config:dump-reference';
|
||||
protected static $defaultDescription = 'Dump the default configuration for an extension';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle name or the extension alias'),
|
||||
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (yaml or xml)', 'yaml'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command dumps the default configuration for an
|
||||
extension/bundle.
|
||||
|
||||
Either the extension alias or bundle name can be used:
|
||||
|
||||
<info>php %command.full_name% framework</info>
|
||||
<info>php %command.full_name% FrameworkBundle</info>
|
||||
|
||||
With the <info>--format</info> option specifies the format of the configuration,
|
||||
this is either <comment>yaml</comment> or <comment>xml</comment>.
|
||||
When the option is not provided, <comment>yaml</comment> is used.
|
||||
|
||||
<info>php %command.full_name% FrameworkBundle --format=xml</info>
|
||||
|
||||
For dumping a specific option, add its path as second argument (only available for the yaml format):
|
||||
|
||||
<info>php %command.full_name% framework profiler.matcher</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
if (null === $name = $input->getArgument('name')) {
|
||||
$this->listBundles($errorIo);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($kernel instanceof ExtensionInterface
|
||||
&& ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)
|
||||
&& $kernel->getAlias()
|
||||
) {
|
||||
$errorIo->table(['Kernel Extension'], [[$kernel->getAlias()]]);
|
||||
}
|
||||
|
||||
$errorIo->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>)',
|
||||
'For dumping a specific option, add its path as the second argument of this command. (e.g. <comment>config:dump-reference FrameworkBundle profiler.matcher</comment> to dump the <comment>framework.profiler.matcher</comment> configuration)',
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$extension = $this->findExtension($name);
|
||||
|
||||
if ($extension instanceof ConfigurationInterface) {
|
||||
$configuration = $extension;
|
||||
} else {
|
||||
$configuration = $extension->getConfiguration([], $this->getContainerBuilder($this->getApplication()->getKernel()));
|
||||
}
|
||||
|
||||
$this->validateConfiguration($extension, $configuration);
|
||||
|
||||
$format = $input->getOption('format');
|
||||
|
||||
if ('yaml' === $format && !class_exists(Yaml::class)) {
|
||||
$errorIo->error('Setting the "format" option to "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=xml" instead.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$path = $input->getArgument('path');
|
||||
|
||||
if (null !== $path && 'yaml' !== $format) {
|
||||
$errorIo->error('The "path" option is only available for the "yaml" format.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($name === $extension->getAlias()) {
|
||||
$message = sprintf('Default configuration for extension with alias: "%s"', $name);
|
||||
} else {
|
||||
$message = sprintf('Default configuration for "%s"', $name);
|
||||
}
|
||||
|
||||
if (null !== $path) {
|
||||
$message .= sprintf(' at path "%s"', $path);
|
||||
}
|
||||
|
||||
switch ($format) {
|
||||
case 'yaml':
|
||||
$io->writeln(sprintf('# %s', $message));
|
||||
$dumper = new YamlReferenceDumper();
|
||||
break;
|
||||
case 'xml':
|
||||
$io->writeln(sprintf('<!-- %s -->', $message));
|
||||
$dumper = new XmlReferenceDumper();
|
||||
break;
|
||||
default:
|
||||
$io->writeln($message);
|
||||
throw new InvalidArgumentException('Only the yaml and xml formats are supported.');
|
||||
}
|
||||
|
||||
$io->writeln(null === $path ? $dumper->dump($configuration, $extension->getNamespace()) : $dumper->dumpAtPath($configuration, $path));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues($this->getAvailableBundles());
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function getAvailableBundles(): array
|
||||
{
|
||||
$bundles = [];
|
||||
|
||||
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
|
||||
$bundles[] = $bundle->getName();
|
||||
$bundles[] = $bundle->getContainerExtension()->getAlias();
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return ['yaml', 'xml'];
|
||||
}
|
||||
}
|
313
vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php
vendored
Normal file
313
vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about services.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ContainerDebugCommand extends Command
|
||||
{
|
||||
use BuildDebugContainerTrait;
|
||||
|
||||
protected static $defaultName = 'debug:container';
|
||||
protected static $defaultDescription = 'Display current services for an application';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'A service name (foo)'),
|
||||
new InputOption('show-arguments', null, InputOption::VALUE_NONE, 'Show arguments in services'),
|
||||
new InputOption('show-hidden', null, InputOption::VALUE_NONE, 'Show hidden (internal) services'),
|
||||
new InputOption('tag', null, InputOption::VALUE_REQUIRED, 'Show all services with a specific tag'),
|
||||
new InputOption('tags', null, InputOption::VALUE_NONE, 'Display tagged services for an application'),
|
||||
new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Display a specific parameter for an application'),
|
||||
new InputOption('parameters', null, InputOption::VALUE_NONE, 'Display parameters for an application'),
|
||||
new InputOption('types', null, InputOption::VALUE_NONE, 'Display types (classes/interfaces) available in the container'),
|
||||
new InputOption('env-var', null, InputOption::VALUE_REQUIRED, 'Display a specific environment variable used in the container'),
|
||||
new InputOption('env-vars', null, InputOption::VALUE_NONE, 'Display environment variables used in the container'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
|
||||
new InputOption('deprecations', null, InputOption::VALUE_NONE, 'Display deprecations generated when compiling and warming up the container'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays all configured <comment>public</comment> services:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
To see deprecations generated during container compilation and cache warmup, use the <info>--deprecations</info> option:
|
||||
|
||||
<info>php %command.full_name% --deprecations</info>
|
||||
|
||||
To get specific information about a service, specify its name:
|
||||
|
||||
<info>php %command.full_name% validator</info>
|
||||
|
||||
To get specific information about a service including all its arguments, use the <info>--show-arguments</info> flag:
|
||||
|
||||
<info>php %command.full_name% validator --show-arguments</info>
|
||||
|
||||
To see available types that can be used for autowiring, use the <info>--types</info> flag:
|
||||
|
||||
<info>php %command.full_name% --types</info>
|
||||
|
||||
To see environment variables used by the container, use the <info>--env-vars</info> flag:
|
||||
|
||||
<info>php %command.full_name% --env-vars</info>
|
||||
|
||||
Display a specific environment variable by specifying its name with the <info>--env-var</info> option:
|
||||
|
||||
<info>php %command.full_name% --env-var=APP_ENV</info>
|
||||
|
||||
Use the --tags option to display tagged <comment>public</comment> services grouped by tag:
|
||||
|
||||
<info>php %command.full_name% --tags</info>
|
||||
|
||||
Find all services with a specific tag by specifying the tag name with the <info>--tag</info> option:
|
||||
|
||||
<info>php %command.full_name% --tag=form.type</info>
|
||||
|
||||
Use the <info>--parameters</info> option to display all parameters:
|
||||
|
||||
<info>php %command.full_name% --parameters</info>
|
||||
|
||||
Display a specific parameter by specifying its name with the <info>--parameter</info> option:
|
||||
|
||||
<info>php %command.full_name% --parameter=kernel.debug</info>
|
||||
|
||||
By default, internal services are hidden. You can display them
|
||||
using the <info>--show-hidden</info> flag:
|
||||
|
||||
<info>php %command.full_name% --show-hidden</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
$this->validateInput($input);
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$object = $this->getContainerBuilder($kernel);
|
||||
|
||||
if ($input->getOption('env-vars')) {
|
||||
$options = ['env-vars' => true];
|
||||
} elseif ($envVar = $input->getOption('env-var')) {
|
||||
$options = ['env-vars' => true, 'name' => $envVar];
|
||||
} elseif ($input->getOption('types')) {
|
||||
$options = [];
|
||||
$options['filter'] = [$this, 'filterToServiceTypes'];
|
||||
} elseif ($input->getOption('parameters')) {
|
||||
$parameters = [];
|
||||
foreach ($object->getParameterBag()->all() as $k => $v) {
|
||||
$parameters[$k] = $object->resolveEnvPlaceholders($v);
|
||||
}
|
||||
$object = new ParameterBag($parameters);
|
||||
$options = [];
|
||||
} elseif ($parameter = $input->getOption('parameter')) {
|
||||
$options = ['parameter' => $parameter];
|
||||
} elseif ($input->getOption('tags')) {
|
||||
$options = ['group_by' => 'tags'];
|
||||
} elseif ($tag = $input->getOption('tag')) {
|
||||
$options = ['tag' => $tag];
|
||||
} elseif ($name = $input->getArgument('name')) {
|
||||
$name = $this->findProperServiceName($input, $errorIo, $object, $name, $input->getOption('show-hidden'));
|
||||
$options = ['id' => $name];
|
||||
} elseif ($input->getOption('deprecations')) {
|
||||
$options = ['deprecations' => true];
|
||||
} else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
$helper = new DescriptorHelper();
|
||||
$options['format'] = $input->getOption('format');
|
||||
$options['show_arguments'] = $input->getOption('show-arguments');
|
||||
$options['show_hidden'] = $input->getOption('show-hidden');
|
||||
$options['raw_text'] = $input->getOption('raw');
|
||||
$options['output'] = $io;
|
||||
$options['is_debug'] = $kernel->isDebug();
|
||||
|
||||
try {
|
||||
$helper->describe($io, $object, $options);
|
||||
|
||||
if (isset($options['id']) && isset($kernel->getContainer()->getRemovedIds()[$options['id']])) {
|
||||
$errorIo->note(sprintf('The "%s" service or alias has been removed or inlined when the container was compiled.', $options['id']));
|
||||
}
|
||||
} catch (ServiceNotFoundException $e) {
|
||||
if ('' !== $e->getId() && '@' === $e->getId()[0]) {
|
||||
throw new ServiceNotFoundException($e->getId(), $e->getSourceId(), null, [substr($e->getId(), 1)]);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && !$input->getOption('env-vars') && !$input->getOption('env-var') && $input->isInteractive()) {
|
||||
if ($input->getOption('tags')) {
|
||||
$errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. <comment>debug:container --tag=form.type</comment>)');
|
||||
} elseif ($input->getOption('parameters')) {
|
||||
$errorIo->comment('To search for a specific parameter, re-run this command with a search term. (e.g. <comment>debug:container --parameter=kernel.debug</comment>)');
|
||||
} elseif (!$input->getOption('deprecations')) {
|
||||
$errorIo->comment('To search for a specific service, re-run this command with a search term. (e.g. <comment>debug:container log</comment>)');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$helper = new DescriptorHelper();
|
||||
$suggestions->suggestValues($helper->getFormats());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$object = $this->getContainerBuilder($kernel);
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('name')
|
||||
&& !$input->getOption('tag') && !$input->getOption('tags')
|
||||
&& !$input->getOption('parameter') && !$input->getOption('parameters')
|
||||
&& !$input->getOption('env-var') && !$input->getOption('env-vars')
|
||||
&& !$input->getOption('types') && !$input->getOption('deprecations')
|
||||
) {
|
||||
$suggestions->suggestValues($this->findServiceIdsContaining(
|
||||
$object,
|
||||
$input->getCompletionValue(),
|
||||
(bool) $input->getOption('show-hidden')
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('tag')) {
|
||||
$suggestions->suggestValues($object->findTags());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('parameter')) {
|
||||
$suggestions->suggestValues(array_keys($object->getParameterBag()->all()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates input arguments and options.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function validateInput(InputInterface $input)
|
||||
{
|
||||
$options = ['tags', 'tag', 'parameters', 'parameter'];
|
||||
|
||||
$optionsCount = 0;
|
||||
foreach ($options as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
++$optionsCount;
|
||||
}
|
||||
}
|
||||
|
||||
$name = $input->getArgument('name');
|
||||
if ((null !== $name) && ($optionsCount > 0)) {
|
||||
throw new InvalidArgumentException('The options tags, tag, parameters & parameter cannot be combined with the service name argument.');
|
||||
} elseif ((null === $name) && $optionsCount > 1) {
|
||||
throw new InvalidArgumentException('The options tags, tag, parameters & parameter cannot be combined together.');
|
||||
}
|
||||
}
|
||||
|
||||
private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $builder, string $name, bool $showHidden): string
|
||||
{
|
||||
$name = ltrim($name, '\\');
|
||||
|
||||
if ($builder->has($name) || !$input->isInteractive()) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$matchingServices = $this->findServiceIdsContaining($builder, $name, $showHidden);
|
||||
if (empty($matchingServices)) {
|
||||
throw new InvalidArgumentException(sprintf('No services found that match "%s".', $name));
|
||||
}
|
||||
|
||||
if (1 === \count($matchingServices)) {
|
||||
return $matchingServices[0];
|
||||
}
|
||||
|
||||
return $io->choice('Select one of the following services to display its information', $matchingServices);
|
||||
}
|
||||
|
||||
private function findServiceIdsContaining(ContainerBuilder $builder, string $name, bool $showHidden): array
|
||||
{
|
||||
$serviceIds = $builder->getServiceIds();
|
||||
$foundServiceIds = $foundServiceIdsIgnoringBackslashes = [];
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
if (!$showHidden && str_starts_with($serviceId, '.')) {
|
||||
continue;
|
||||
}
|
||||
if (false !== stripos(str_replace('\\', '', $serviceId), $name)) {
|
||||
$foundServiceIdsIgnoringBackslashes[] = $serviceId;
|
||||
}
|
||||
if ('' === $name || false !== stripos($serviceId, $name)) {
|
||||
$foundServiceIds[] = $serviceId;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundServiceIds ?: $foundServiceIdsIgnoringBackslashes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function filterToServiceTypes(string $serviceId): bool
|
||||
{
|
||||
// filter out things that could not be valid class names
|
||||
if (!preg_match('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))^(?&V)(?:\\\\(?&V))*+(?: \$(?&V))?$/', $serviceId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the id has a \, assume it is a class
|
||||
if (str_contains($serviceId, '\\')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return class_exists($serviceId) || interface_exists($serviceId, false);
|
||||
}
|
||||
}
|
134
vendor/symfony/framework-bundle/Command/ContainerLintCommand.php
vendored
Normal file
134
vendor/symfony/framework-bundle/Command/ContainerLintCommand.php
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
final class ContainerLintCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'lint:container';
|
||||
protected static $defaultDescription = 'Ensure that arguments injected into services match type declarations';
|
||||
|
||||
/**
|
||||
* @var ContainerBuilder
|
||||
*/
|
||||
private $containerBuilder;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp('This command parses service definitions and ensures that injected values match the type declarations of each services\' class.')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
try {
|
||||
$container = $this->getContainerBuilder();
|
||||
} catch (RuntimeException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
$container->setParameter('container.build_time', time());
|
||||
|
||||
try {
|
||||
$container->compile();
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success('The container was linted successfully: all services are injected with values that are compatible with their type declarations.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getContainerBuilder(): ContainerBuilder
|
||||
{
|
||||
if ($this->containerBuilder) {
|
||||
return $this->containerBuilder;
|
||||
}
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$kernelContainer = $kernel->getContainer();
|
||||
|
||||
if (!$kernel->isDebug() || !(new ConfigCache($kernelContainer->getParameter('debug.container.dump'), true))->isFresh()) {
|
||||
if (!$kernel instanceof Kernel) {
|
||||
throw new RuntimeException(sprintf('This command does not support the application kernel: "%s" does not extend "%s".', get_debug_type($kernel), Kernel::class));
|
||||
}
|
||||
|
||||
$buildContainer = \Closure::bind(function (): ContainerBuilder {
|
||||
$this->initializeBundles();
|
||||
|
||||
return $this->buildContainer();
|
||||
}, $kernel, \get_class($kernel));
|
||||
$container = $buildContainer();
|
||||
|
||||
$skippedIds = [];
|
||||
} else {
|
||||
if (!$kernelContainer instanceof Container) {
|
||||
throw new RuntimeException(sprintf('This command does not support the application container: "%s" does not extend "%s".', get_debug_type($kernelContainer), Container::class));
|
||||
}
|
||||
|
||||
(new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernelContainer->getParameter('debug.container.dump'));
|
||||
|
||||
$refl = new \ReflectionProperty($parameterBag, 'resolved');
|
||||
$refl->setAccessible(true);
|
||||
$refl->setValue($parameterBag, true);
|
||||
|
||||
$skippedIds = [];
|
||||
foreach ($container->getServiceIds() as $serviceId) {
|
||||
if (str_starts_with($serviceId, '.errored.')) {
|
||||
$skippedIds[$serviceId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
|
||||
}
|
||||
|
||||
$container->setParameter('container.build_hash', 'lint_container');
|
||||
$container->setParameter('container.build_id', 'lint_container');
|
||||
|
||||
$container->addCompilerPass(new CheckTypeDeclarationsPass(true, $skippedIds), PassConfig::TYPE_AFTER_REMOVING, -100);
|
||||
|
||||
return $this->containerBuilder = $container;
|
||||
}
|
||||
}
|
177
vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php
vendored
Normal file
177
vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\Descriptor;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\HttpKernel\Debug\FileLinkFormatter;
|
||||
|
||||
/**
|
||||
* A console command for autowiring information.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DebugAutowiringCommand extends ContainerDebugCommand
|
||||
{
|
||||
protected static $defaultName = 'debug:autowiring';
|
||||
protected static $defaultDescription = 'List classes/interfaces you can use for autowiring';
|
||||
|
||||
private $supportsHref;
|
||||
private $fileLinkFormatter;
|
||||
|
||||
public function __construct(string $name = null, FileLinkFormatter $fileLinkFormatter = null)
|
||||
{
|
||||
$this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref');
|
||||
$this->fileLinkFormatter = $fileLinkFormatter;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('search', InputArgument::OPTIONAL, 'A search filter'),
|
||||
new InputOption('all', null, InputOption::VALUE_NONE, 'Show also services that are not aliased'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays the classes and interfaces that
|
||||
you can use as type-hints for autowiring:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
You can also pass a search term to filter the list:
|
||||
|
||||
<info>php %command.full_name% log</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
$builder = $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
$serviceIds = $builder->getServiceIds();
|
||||
$serviceIds = array_filter($serviceIds, [$this, 'filterToServiceTypes']);
|
||||
|
||||
if ($search = $input->getArgument('search')) {
|
||||
$searchNormalized = preg_replace('/[^a-zA-Z0-9\x7f-\xff $]++/', '', $search);
|
||||
|
||||
$serviceIds = array_filter($serviceIds, function ($serviceId) use ($searchNormalized) {
|
||||
return false !== stripos(str_replace('\\', '', $serviceId), $searchNormalized) && !str_starts_with($serviceId, '.');
|
||||
});
|
||||
|
||||
if (empty($serviceIds)) {
|
||||
$errorIo->error(sprintf('No autowirable classes or interfaces found matching "%s"', $search));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uasort($serviceIds, 'strnatcmp');
|
||||
|
||||
$io->title('Autowirable Types');
|
||||
$io->text('The following classes & interfaces can be used as type-hints when autowiring:');
|
||||
if ($search) {
|
||||
$io->text(sprintf('(only showing classes/interfaces matching <comment>%s</comment>)', $search));
|
||||
}
|
||||
$hasAlias = [];
|
||||
$all = $input->getOption('all');
|
||||
$previousId = '-';
|
||||
$serviceIdsNb = 0;
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
$text = [];
|
||||
$resolvedServiceId = $serviceId;
|
||||
if (!str_starts_with($serviceId, $previousId)) {
|
||||
$text[] = '';
|
||||
if ('' !== $description = Descriptor::getClassDescription($serviceId, $resolvedServiceId)) {
|
||||
if (isset($hasAlias[$serviceId])) {
|
||||
continue;
|
||||
}
|
||||
$text[] = $description;
|
||||
}
|
||||
$previousId = $serviceId.' $';
|
||||
}
|
||||
|
||||
$serviceLine = sprintf('<fg=yellow>%s</>', $serviceId);
|
||||
if ($this->supportsHref && '' !== $fileLink = $this->getFileLink($serviceId)) {
|
||||
$serviceLine = sprintf('<fg=yellow;href=%s>%s</>', $fileLink, $serviceId);
|
||||
}
|
||||
|
||||
if ($builder->hasAlias($serviceId)) {
|
||||
$hasAlias[$serviceId] = true;
|
||||
$serviceAlias = $builder->getAlias($serviceId);
|
||||
$serviceLine .= ' <fg=cyan>('.$serviceAlias.')</>';
|
||||
|
||||
if ($serviceAlias->isDeprecated()) {
|
||||
$serviceLine .= ' - <fg=magenta>deprecated</>';
|
||||
}
|
||||
} elseif (!$all) {
|
||||
++$serviceIdsNb;
|
||||
continue;
|
||||
}
|
||||
$text[] = $serviceLine;
|
||||
$io->text($text);
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
if (0 < $serviceIdsNb) {
|
||||
$io->text(sprintf('%s more concrete service%s would be displayed when adding the "--all" option.', $serviceIdsNb, $serviceIdsNb > 1 ? 's' : ''));
|
||||
}
|
||||
if ($all) {
|
||||
$io->text('Pro-tip: use interfaces in your type-hints instead of classes to benefit from the dependency inversion principle.');
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getFileLink(string $class): string
|
||||
{
|
||||
if (null === $this->fileLinkFormatter
|
||||
|| (null === $r = $this->getContainerBuilder($this->getApplication()->getKernel())->getReflectionClass($class, false))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('search')) {
|
||||
$builder = $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
|
||||
$suggestions->suggestValues(array_filter($builder->getServiceIds(), [$this, 'filterToServiceTypes']));
|
||||
}
|
||||
}
|
||||
}
|
164
vendor/symfony/framework-bundle/Command/EventDispatcherDebugCommand.php
vendored
Normal file
164
vendor/symfony/framework-bundle/Command/EventDispatcherDebugCommand.php
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about event dispatcher.
|
||||
*
|
||||
* @author Matthieu Auger <mail@matthieuauger.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class EventDispatcherDebugCommand extends Command
|
||||
{
|
||||
private const DEFAULT_DISPATCHER = 'event_dispatcher';
|
||||
|
||||
protected static $defaultName = 'debug:event-dispatcher';
|
||||
protected static $defaultDescription = 'Display configured listeners for an application';
|
||||
private $dispatchers;
|
||||
|
||||
public function __construct(ContainerInterface $dispatchers)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->dispatchers = $dispatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('event', InputArgument::OPTIONAL, 'An event name or a part of the event name'),
|
||||
new InputOption('dispatcher', null, InputOption::VALUE_REQUIRED, 'To view events of a specific event dispatcher', self::DEFAULT_DISPATCHER),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays all configured listeners:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
To get specific listeners for an event, specify its name:
|
||||
|
||||
<info>php %command.full_name% kernel.request</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$options = [];
|
||||
$dispatcherServiceName = $input->getOption('dispatcher');
|
||||
if (!$this->dispatchers->has($dispatcherServiceName)) {
|
||||
$io->getErrorStyle()->error(sprintf('Event dispatcher "%s" is not available.', $dispatcherServiceName));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$dispatcher = $this->dispatchers->get($dispatcherServiceName);
|
||||
|
||||
if ($event = $input->getArgument('event')) {
|
||||
if ($dispatcher->hasListeners($event)) {
|
||||
$options = ['event' => $event];
|
||||
} else {
|
||||
// if there is no direct match, try find partial matches
|
||||
$events = $this->searchForEvent($dispatcher, $event);
|
||||
if (0 === \count($events)) {
|
||||
$io->getErrorStyle()->warning(sprintf('The event "%s" does not have any registered listeners.', $event));
|
||||
|
||||
return 0;
|
||||
} elseif (1 === \count($events)) {
|
||||
$options = ['event' => $events[array_key_first($events)]];
|
||||
} else {
|
||||
$options = ['events' => $events];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$helper = new DescriptorHelper();
|
||||
|
||||
if (self::DEFAULT_DISPATCHER !== $dispatcherServiceName) {
|
||||
$options['dispatcher_service_name'] = $dispatcherServiceName;
|
||||
}
|
||||
|
||||
$options['format'] = $input->getOption('format');
|
||||
$options['raw_text'] = $input->getOption('raw');
|
||||
$options['output'] = $io;
|
||||
$helper->describe($io, $dispatcher, $options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('event')) {
|
||||
$dispatcherServiceName = $input->getOption('dispatcher');
|
||||
if ($this->dispatchers->has($dispatcherServiceName)) {
|
||||
$dispatcher = $this->dispatchers->get($dispatcherServiceName);
|
||||
$suggestions->suggestValues(array_keys($dispatcher->getListeners()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('dispatcher')) {
|
||||
if ($this->dispatchers instanceof ServiceProviderInterface) {
|
||||
$suggestions->suggestValues(array_keys($this->dispatchers->getProvidedServices()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues((new DescriptorHelper())->getFormats());
|
||||
}
|
||||
}
|
||||
|
||||
private function searchForEvent(EventDispatcherInterface $dispatcher, string $needle): array
|
||||
{
|
||||
$output = [];
|
||||
$lcNeedle = strtolower($needle);
|
||||
$allEvents = array_keys($dispatcher->getListeners());
|
||||
foreach ($allEvents as $event) {
|
||||
if (str_contains(strtolower($event), $lcNeedle)) {
|
||||
$output[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
150
vendor/symfony/framework-bundle/Command/RouterDebugCommand.php
vendored
Normal file
150
vendor/symfony/framework-bundle/Command/RouterDebugCommand.php
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\HttpKernel\Debug\FileLinkFormatter;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about routes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RouterDebugCommand extends Command
|
||||
{
|
||||
use BuildDebugContainerTrait;
|
||||
|
||||
protected static $defaultName = 'debug:router';
|
||||
protected static $defaultDescription = 'Display current routes for an application';
|
||||
private $router;
|
||||
private $fileLinkFormatter;
|
||||
|
||||
public function __construct(RouterInterface $router, FileLinkFormatter $fileLinkFormatter = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->router = $router;
|
||||
$this->fileLinkFormatter = $fileLinkFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'A route name'),
|
||||
new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> displays the configured routes:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws InvalidArgumentException When route does not exist
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$name = $input->getArgument('name');
|
||||
$helper = new DescriptorHelper($this->fileLinkFormatter);
|
||||
$routes = $this->router->getRouteCollection();
|
||||
$container = null;
|
||||
if ($this->fileLinkFormatter) {
|
||||
$container = function () {
|
||||
return $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
};
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
if (!($route = $routes->get($name)) && $matchingRoutes = $this->findRouteNameContaining($name, $routes)) {
|
||||
$default = 1 === \count($matchingRoutes) ? $matchingRoutes[0] : null;
|
||||
$name = $io->choice('Select one of the matching routes', $matchingRoutes, $default);
|
||||
$route = $routes->get($name);
|
||||
}
|
||||
|
||||
if (!$route) {
|
||||
throw new InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
$helper->describe($io, $route, [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'name' => $name,
|
||||
'output' => $io,
|
||||
'container' => $container,
|
||||
]);
|
||||
} else {
|
||||
$helper->describe($io, $routes, [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'show_controllers' => $input->getOption('show-controllers'),
|
||||
'output' => $io,
|
||||
'container' => $container,
|
||||
]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function findRouteNameContaining(string $name, RouteCollection $routes): array
|
||||
{
|
||||
$foundRoutesNames = [];
|
||||
foreach ($routes as $routeName => $route) {
|
||||
if (false !== stripos($routeName, $name)) {
|
||||
$foundRoutesNames[] = $routeName;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundRoutesNames;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->router->getRouteCollection()->all()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$helper = new DescriptorHelper();
|
||||
$suggestions->suggestValues($helper->getFormats());
|
||||
}
|
||||
}
|
||||
}
|
129
vendor/symfony/framework-bundle/Command/RouterMatchCommand.php
vendored
Normal file
129
vendor/symfony/framework-bundle/Command/RouterMatchCommand.php
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\ExpressionLanguage\ExpressionFunctionProviderInterface;
|
||||
use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* A console command to test route matching.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RouterMatchCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'router:match';
|
||||
protected static $defaultDescription = 'Help debug routes by simulating a path info match';
|
||||
|
||||
private $router;
|
||||
private $expressionLanguageProviders;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, ExpressionFunctionProviderInterface> $expressionLanguageProviders
|
||||
*/
|
||||
public function __construct(RouterInterface $router, iterable $expressionLanguageProviders = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->router = $router;
|
||||
$this->expressionLanguageProviders = $expressionLanguageProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('path_info', InputArgument::REQUIRED, 'A path info'),
|
||||
new InputOption('method', null, InputOption::VALUE_REQUIRED, 'Set the HTTP method'),
|
||||
new InputOption('scheme', null, InputOption::VALUE_REQUIRED, 'Set the URI scheme (usually http or https)'),
|
||||
new InputOption('host', null, InputOption::VALUE_REQUIRED, 'Set the URI host'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> shows which routes match a given request and which don't and for what reason:
|
||||
|
||||
<info>php %command.full_name% /foo</info>
|
||||
|
||||
or
|
||||
|
||||
<info>php %command.full_name% /foo --method POST --scheme https --host symfony.com --verbose</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$context = $this->router->getContext();
|
||||
if (null !== $method = $input->getOption('method')) {
|
||||
$context->setMethod($method);
|
||||
}
|
||||
if (null !== $scheme = $input->getOption('scheme')) {
|
||||
$context->setScheme($scheme);
|
||||
}
|
||||
if (null !== $host = $input->getOption('host')) {
|
||||
$context->setHost($host);
|
||||
}
|
||||
|
||||
$matcher = new TraceableUrlMatcher($this->router->getRouteCollection(), $context);
|
||||
foreach ($this->expressionLanguageProviders as $provider) {
|
||||
$matcher->addExpressionLanguageProvider($provider);
|
||||
}
|
||||
|
||||
$traces = $matcher->getTraces($input->getArgument('path_info'));
|
||||
|
||||
$io->newLine();
|
||||
|
||||
$matches = false;
|
||||
foreach ($traces as $trace) {
|
||||
if (TraceableUrlMatcher::ROUTE_ALMOST_MATCHES == $trace['level']) {
|
||||
$io->text(sprintf('Route <info>"%s"</> almost matches but %s', $trace['name'], lcfirst($trace['log'])));
|
||||
} elseif (TraceableUrlMatcher::ROUTE_MATCHES == $trace['level']) {
|
||||
$io->success(sprintf('Route "%s" matches', $trace['name']));
|
||||
|
||||
$routerDebugCommand = $this->getApplication()->find('debug:router');
|
||||
$routerDebugCommand->run(new ArrayInput(['name' => $trace['name']]), $output);
|
||||
|
||||
$matches = true;
|
||||
} elseif ($input->getOption('verbose')) {
|
||||
$io->text(sprintf('Route "%s" does not match: %s', $trace['name'], $trace['log']));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matches) {
|
||||
$io->error(sprintf('None of the routes match the path "%s"', $input->getArgument('path_info')));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
104
vendor/symfony/framework-bundle/Command/SecretsDecryptToLocalCommand.php
vendored
Normal file
104
vendor/symfony/framework-bundle/Command/SecretsDecryptToLocalCommand.php
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsDecryptToLocalCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:decrypt-to-local';
|
||||
protected static $defaultDescription = 'Decrypt all secrets and stores them in the local vault';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Force overriding of secrets that already exist in the local vault')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command decrypts all secrets and copies them in the local vault.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
When the option <info>--force</info> is provided, secrets that already exist in the local vault are overriden.
|
||||
|
||||
<info>%command.full_name% --force</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
if (null === $this->localVault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets = $this->vault->list(true);
|
||||
|
||||
$io->comment(sprintf('%d secret%s found in the vault.', \count($secrets), 1 !== \count($secrets) ? 's' : ''));
|
||||
|
||||
$skipped = 0;
|
||||
if (!$input->getOption('force')) {
|
||||
foreach ($this->localVault->list() as $k => $v) {
|
||||
if (isset($secrets[$k])) {
|
||||
++$skipped;
|
||||
unset($secrets[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($skipped > 0) {
|
||||
$io->warning([
|
||||
sprintf('%d secret%s already overridden in the local vault and will be skipped.', $skipped, 1 !== $skipped ? 's are' : ' is'),
|
||||
'Use the --force flag to override these.',
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($secrets as $k => $v) {
|
||||
if (null === $v) {
|
||||
$io->error($this->vault->getLastMessage() ?? sprintf('Secret "%s" has been skipped as there was an error reading it.', $k));
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->localVault->seal($k, $v);
|
||||
$io->note($this->localVault->getLastMessage());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
79
vendor/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php
vendored
Normal file
79
vendor/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsEncryptFromLocalCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:encrypt-from-local';
|
||||
protected static $defaultDescription = 'Encrypt all local secrets to the vault';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command encrypts all locally overridden secrets to the vault.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
if (null === $this->localVault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
foreach ($this->vault->list(true) as $name => $value) {
|
||||
$localValue = $this->localVault->reveal($name);
|
||||
|
||||
if (null !== $localValue && $value !== $localValue) {
|
||||
$this->vault->seal($name, $localValue);
|
||||
} elseif (null !== $message = $this->localVault->getLastMessage()) {
|
||||
$io->error($message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
126
vendor/symfony/framework-bundle/Command/SecretsGenerateKeysCommand.php
vendored
Normal file
126
vendor/symfony/framework-bundle/Command/SecretsGenerateKeysCommand.php
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsGenerateKeysCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:generate-keys';
|
||||
protected static $defaultDescription = 'Generate new encryption keys';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->addOption('rotate', 'r', InputOption::VALUE_NONE, 'Re-encrypt existing secrets with the newly generated keys.')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command generates a new encryption key.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
If encryption keys already exist, the command must be called with
|
||||
the <info>--rotate</info> option in order to override those keys and re-encrypt
|
||||
existing secrets.
|
||||
|
||||
<info>%command.full_name% --rotate</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->success('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!$input->getOption('rotate')) {
|
||||
if ($vault->generateKeys()) {
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$io->warning($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets = [];
|
||||
foreach ($vault->list(true) as $name => $value) {
|
||||
if (null === $value) {
|
||||
$io->error($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets[$name] = $value;
|
||||
}
|
||||
|
||||
if (!$vault->generateKeys(true)) {
|
||||
$io->warning($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($secrets) {
|
||||
foreach ($secrets as $name => $value) {
|
||||
$vault->seal($name, $value);
|
||||
}
|
||||
|
||||
$io->comment('Existing secrets have been rotated to the new keys.');
|
||||
}
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
109
vendor/symfony/framework-bundle/Command/SecretsListCommand.php
vendored
Normal file
109
vendor/symfony/framework-bundle/Command/SecretsListCommand.php
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Dumper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:list';
|
||||
protected static $defaultDescription = 'List all secrets';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addOption('reveal', 'r', InputOption::VALUE_NONE, 'Display decrypted values alongside names')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command list all stored secrets.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
When the option <info>--reveal</info> is provided, the decrypted secrets are also displayed.
|
||||
|
||||
<info>%command.full_name% --reveal</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
$io->comment('Use <info>"%env(<name>)%"</info> to reference a secret in a config file.');
|
||||
|
||||
if (!$reveal = $input->getOption('reveal')) {
|
||||
$io->comment(sprintf('To reveal the secrets run <info>php %s %s --reveal</info>', $_SERVER['PHP_SELF'], $this->getName()));
|
||||
}
|
||||
|
||||
$secrets = $this->vault->list($reveal);
|
||||
$localSecrets = null !== $this->localVault ? $this->localVault->list($reveal) : null;
|
||||
|
||||
$rows = [];
|
||||
|
||||
$dump = new Dumper($output);
|
||||
$dump = static function (?string $v) use ($dump) {
|
||||
return null === $v ? '******' : $dump($v);
|
||||
};
|
||||
|
||||
foreach ($secrets as $name => $value) {
|
||||
$rows[$name] = [$name, $dump($value)];
|
||||
}
|
||||
|
||||
if (null !== $message = $this->vault->getLastMessage()) {
|
||||
$io->comment($message);
|
||||
}
|
||||
|
||||
foreach ($localSecrets ?? [] as $name => $value) {
|
||||
if (isset($rows[$name])) {
|
||||
$rows[$name][] = $dump($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->localVault && null !== $message = $this->localVault->getLastMessage()) {
|
||||
$io->comment($message);
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))
|
||||
->table(['Secret', 'Value'] + (null !== $localSecrets ? [2 => 'Local Value'] : []), $rows);
|
||||
|
||||
$io->comment("Local values override secret values.\nUse <info>secrets:set --local</info> to define them.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
102
vendor/symfony/framework-bundle/Command/SecretsRemoveCommand.php
vendored
Normal file
102
vendor/symfony/framework-bundle/Command/SecretsRemoveCommand.php
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsRemoveCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:remove';
|
||||
protected static $defaultDescription = 'Remove a secret from the vault';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret')
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command removes a secret from the vault.
|
||||
|
||||
<info>%command.full_name% <name></info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->success('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($vault->remove($name = $input->getArgument('name'))) {
|
||||
$io->success($vault->getLastMessage() ?? 'Secret was removed from the vault.');
|
||||
} else {
|
||||
$io->comment($vault->getLastMessage() ?? 'Secret was not found in the vault.');
|
||||
}
|
||||
|
||||
if ($this->vault === $vault && null !== $this->localVault->reveal($name)) {
|
||||
$io->comment('Note that this secret is overridden in the local vault.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (!$input->mustSuggestArgumentValuesFor('name')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$vaultKeys = array_keys($this->vault->list(false));
|
||||
if ($input->getOption('local')) {
|
||||
if (null === $this->localVault) {
|
||||
return;
|
||||
}
|
||||
$vaultKeys = array_intersect($vaultKeys, array_keys($this->localVault->list(false)));
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($vaultKeys);
|
||||
}
|
||||
}
|
149
vendor/symfony/framework-bundle/Command/SecretsSetCommand.php
vendored
Normal file
149
vendor/symfony/framework-bundle/Command/SecretsSetCommand.php
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SecretsSetCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'secrets:set';
|
||||
protected static $defaultDescription = 'Set a secret in the vault';
|
||||
|
||||
private $vault;
|
||||
private $localVault;
|
||||
|
||||
public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
|
||||
{
|
||||
$this->vault = $vault;
|
||||
$this->localVault = $localVault;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret')
|
||||
->addArgument('file', InputArgument::OPTIONAL, 'A file where to read the secret from or "-" for reading from STDIN')
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->addOption('random', 'r', InputOption::VALUE_OPTIONAL, 'Generate a random value.', false)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command stores a secret in the vault.
|
||||
|
||||
<info>%command.full_name% <name></info>
|
||||
|
||||
To reference secrets in services.yaml or any other config
|
||||
files, use <info>"%env(<name>)%"</info>.
|
||||
|
||||
By default, the secret value should be entered interactively.
|
||||
Alternatively, provide a file where to read the secret from:
|
||||
|
||||
<info>php %command.full_name% <name> filename</info>
|
||||
|
||||
Use "-" as a file name to read from STDIN:
|
||||
|
||||
<info>cat filename | php %command.full_name% <name> -</info>
|
||||
|
||||
Use <info>--local</info> to override secrets for local needs.
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
|
||||
$io = new SymfonyStyle($input, $errOutput);
|
||||
$name = $input->getArgument('name');
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->localVault === $vault && !\array_key_exists($name, $this->vault->list())) {
|
||||
$io->error(sprintf('Secret "%s" does not exist in the vault, you cannot override it locally.', $name));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 < $random = $input->getOption('random') ?? 16) {
|
||||
$value = strtr(substr(base64_encode(random_bytes($random)), 0, $random), '+/', '-_');
|
||||
} elseif (!$file = $input->getArgument('file')) {
|
||||
$value = $io->askHidden('Please type the secret value');
|
||||
|
||||
if (null === $value) {
|
||||
$io->warning('No value provided: using empty string');
|
||||
$value = '';
|
||||
}
|
||||
} elseif ('-' === $file) {
|
||||
$value = file_get_contents('php://stdin');
|
||||
} elseif (is_file($file) && is_readable($file)) {
|
||||
$value = file_get_contents($file);
|
||||
} elseif (!is_file($file)) {
|
||||
throw new \InvalidArgumentException(sprintf('File not found: "%s".', $file));
|
||||
} elseif (!is_readable($file)) {
|
||||
throw new \InvalidArgumentException(sprintf('File is not readable: "%s".', $file));
|
||||
}
|
||||
|
||||
if ($vault->generateKeys()) {
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
}
|
||||
|
||||
$vault->seal($name, $value);
|
||||
|
||||
$io->success($vault->getLastMessage() ?? 'Secret was successfully stored in the vault.');
|
||||
|
||||
if (0 < $random) {
|
||||
$errOutput->write(' // The generated random value is: <comment>');
|
||||
$output->write($value);
|
||||
$errOutput->writeln('</comment>');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
if ($this->vault === $vault && null !== $this->localVault->reveal($name)) {
|
||||
$io->comment('Note that this secret is overridden in the local vault.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->vault->list(false)));
|
||||
}
|
||||
}
|
||||
}
|
418
vendor/symfony/framework-bundle/Command/TranslationDebugCommand.php
vendored
Normal file
418
vendor/symfony/framework-bundle/Command/TranslationDebugCommand.php
vendored
Normal file
@ -0,0 +1,418 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\LoggingTranslator;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Helps finding unused or missing translation messages in a given locale
|
||||
* and comparing them with the fallback ones.
|
||||
*
|
||||
* @author Florian Voutzinos <florian@voutzinos.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class TranslationDebugCommand extends Command
|
||||
{
|
||||
public const EXIT_CODE_GENERAL_ERROR = 64;
|
||||
public const EXIT_CODE_MISSING = 65;
|
||||
public const EXIT_CODE_UNUSED = 66;
|
||||
public const EXIT_CODE_FALLBACK = 68;
|
||||
public const MESSAGE_MISSING = 0;
|
||||
public const MESSAGE_UNUSED = 1;
|
||||
public const MESSAGE_EQUALS_FALLBACK = 2;
|
||||
|
||||
protected static $defaultName = 'debug:translation';
|
||||
protected static $defaultDescription = 'Display translation messages information';
|
||||
|
||||
private $translator;
|
||||
private $reader;
|
||||
private $extractor;
|
||||
private $defaultTransPath;
|
||||
private $defaultViewsPath;
|
||||
private $transPaths;
|
||||
private $codePaths;
|
||||
private $enabledLocales;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->translator = $translator;
|
||||
$this->reader = $reader;
|
||||
$this->extractor = $extractor;
|
||||
$this->defaultTransPath = $defaultTransPath;
|
||||
$this->defaultViewsPath = $defaultViewsPath;
|
||||
$this->transPaths = $transPaths;
|
||||
$this->codePaths = $codePaths;
|
||||
$this->enabledLocales = $enabledLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
|
||||
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
|
||||
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'The messages domain'),
|
||||
new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Display only missing messages'),
|
||||
new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Display only unused messages'),
|
||||
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->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 default translations directory.
|
||||
|
||||
You can display information about bundle translations in a specific locale:
|
||||
|
||||
<info>php %command.full_name% en AcmeDemoBundle</info>
|
||||
|
||||
You can also specify a translation domain for the search:
|
||||
|
||||
<info>php %command.full_name% --domain=messages en AcmeDemoBundle</info>
|
||||
|
||||
You can only display missing messages:
|
||||
|
||||
<info>php %command.full_name% --only-missing en AcmeDemoBundle</info>
|
||||
|
||||
You can only display unused messages:
|
||||
|
||||
<info>php %command.full_name% --only-unused en AcmeDemoBundle</info>
|
||||
|
||||
You can display information about application translations in a specific locale:
|
||||
|
||||
<info>php %command.full_name% en</info>
|
||||
|
||||
You can display information about translations in all registered bundles in a specific locale:
|
||||
|
||||
<info>php %command.full_name% --all en</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$locale = $input->getArgument('locale');
|
||||
$domain = $input->getOption('domain');
|
||||
|
||||
$exitCode = self::SUCCESS;
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Paths
|
||||
$transPaths = $this->getRootTransPaths();
|
||||
$codePaths = $this->getRootCodePaths($kernel);
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$bundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$bundleDir = $bundle->getPath();
|
||||
$transPaths = [is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundleDir.'/translations'];
|
||||
$codePaths = [is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundleDir.'/templates'];
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$path = $input->getArgument('bundle');
|
||||
|
||||
$transPaths = [$path.'/translations'];
|
||||
$codePaths = [$path.'/templates'];
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
} elseif ($input->getOption('all')) {
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$bundleDir = $bundle->getPath();
|
||||
$transPaths[] = is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundle->getPath().'/translations';
|
||||
$codePaths[] = is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundle->getPath().'/templates';
|
||||
}
|
||||
}
|
||||
|
||||
// Extract used messages
|
||||
$extractedCatalogue = $this->extractMessages($locale, $codePaths);
|
||||
|
||||
// Load defined messages
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths);
|
||||
|
||||
// Merge defined and extracted messages to get all message ids
|
||||
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
|
||||
$allMessages = $mergeOperation->getResult()->all($domain);
|
||||
if (null !== $domain) {
|
||||
$allMessages = [$domain => $allMessages];
|
||||
}
|
||||
|
||||
// No defined or extracted messages
|
||||
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
|
||||
$outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale);
|
||||
|
||||
if (null !== $domain) {
|
||||
$outputMessage .= sprintf(' and domain "%s"', $domain);
|
||||
}
|
||||
|
||||
$io->getErrorStyle()->warning($outputMessage);
|
||||
|
||||
return self::EXIT_CODE_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
// Load the fallback catalogues
|
||||
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $transPaths);
|
||||
|
||||
// Display header line
|
||||
$headers = ['State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale)];
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
|
||||
}
|
||||
$rows = [];
|
||||
// Iterate all message ids and determine their state
|
||||
foreach ($allMessages as $domain => $messages) {
|
||||
foreach (array_keys($messages) as $messageId) {
|
||||
$value = $currentCatalogue->get($messageId, $domain);
|
||||
$states = [];
|
||||
|
||||
if ($extractedCatalogue->defines($messageId, $domain)) {
|
||||
if (!$currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_MISSING;
|
||||
|
||||
if (!$input->getOption('only-unused')) {
|
||||
$exitCode = $exitCode | self::EXIT_CODE_MISSING;
|
||||
}
|
||||
}
|
||||
} elseif ($currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_UNUSED;
|
||||
|
||||
if (!$input->getOption('only-missing')) {
|
||||
$exitCode = $exitCode | self::EXIT_CODE_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array(self::MESSAGE_UNUSED, $states) && $input->getOption('only-unused')
|
||||
|| !\in_array(self::MESSAGE_MISSING, $states) && $input->getOption('only-missing')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_EQUALS_FALLBACK;
|
||||
|
||||
$exitCode = $exitCode | self::EXIT_CODE_FALLBACK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$row = [$this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value)];
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$io->table($headers, $rows);
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('locale')) {
|
||||
$suggestions->suggestValues($this->enabledLocales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('bundle')) {
|
||||
$availableBundles = [];
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$availableBundles[] = $bundle->getName();
|
||||
|
||||
if ($extension = $bundle->getContainerExtension()) {
|
||||
$availableBundles[] = $extension->getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($availableBundles);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('domain')) {
|
||||
$locale = $input->getArgument('locale');
|
||||
|
||||
$mergeOperation = new MergeOperation(
|
||||
$this->extractMessages($locale, $this->getRootCodePaths($kernel)),
|
||||
$this->loadCurrentMessages($locale, $this->getRootTransPaths())
|
||||
);
|
||||
|
||||
$suggestions->suggestValues($mergeOperation->getDomains());
|
||||
}
|
||||
}
|
||||
|
||||
private function formatState(int $state): string
|
||||
{
|
||||
if (self::MESSAGE_MISSING === $state) {
|
||||
return '<error> missing </error>';
|
||||
}
|
||||
|
||||
if (self::MESSAGE_UNUSED === $state) {
|
||||
return '<comment> unused </comment>';
|
||||
}
|
||||
|
||||
if (self::MESSAGE_EQUALS_FALLBACK === $state) {
|
||||
return '<info> fallback </info>';
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
private function formatStates(array $states): string
|
||||
{
|
||||
$result = [];
|
||||
foreach ($states as $state) {
|
||||
$result[] = $this->formatState($state);
|
||||
}
|
||||
|
||||
return implode(' ', $result);
|
||||
}
|
||||
|
||||
private function formatId(string $id): string
|
||||
{
|
||||
return sprintf('<fg=cyan;options=bold>%s</>', $id);
|
||||
}
|
||||
|
||||
private function sanitizeString(string $string, int $length = 40): string
|
||||
{
|
||||
$string = trim(preg_replace('/\s+/', ' ', $string));
|
||||
|
||||
if (false !== $encoding = mb_detect_encoding($string, null, true)) {
|
||||
if (mb_strlen($string, $encoding) > $length) {
|
||||
return mb_substr($string, 0, $length - 3, $encoding).'...';
|
||||
}
|
||||
} elseif (\strlen($string) > $length) {
|
||||
return substr($string, 0, $length - 3).'...';
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function extractMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path) || is_file($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $extractedCatalogue;
|
||||
}
|
||||
|
||||
private function loadCurrentMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCatalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageCatalogue[]
|
||||
*/
|
||||
private function loadFallbackCatalogues(string $locale, array $transPaths): array
|
||||
{
|
||||
$fallbackCatalogues = [];
|
||||
if ($this->translator instanceof Translator || $this->translator instanceof DataCollectorTranslator || $this->translator instanceof LoggingTranslator) {
|
||||
foreach ($this->translator->getFallbackLocales() as $fallbackLocale) {
|
||||
if ($fallbackLocale === $locale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $fallbackCatalogue);
|
||||
}
|
||||
}
|
||||
$fallbackCatalogues[] = $fallbackCatalogue;
|
||||
}
|
||||
}
|
||||
|
||||
return $fallbackCatalogues;
|
||||
}
|
||||
|
||||
private function getRootTransPaths(): array
|
||||
{
|
||||
$transPaths = $this->transPaths;
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
|
||||
return $transPaths;
|
||||
}
|
||||
|
||||
private function getRootCodePaths(KernelInterface $kernel): array
|
||||
{
|
||||
$codePaths = $this->codePaths;
|
||||
$codePaths[] = $kernel->getProjectDir().'/src';
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
|
||||
return $codePaths;
|
||||
}
|
||||
}
|
451
vendor/symfony/framework-bundle/Command/TranslationUpdateCommand.php
vendored
Normal file
451
vendor/symfony/framework-bundle/Command/TranslationUpdateCommand.php
vendored
Normal file
@ -0,0 +1,451 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Translation\Catalogue\TargetOperation;
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
|
||||
use Symfony\Component\Translation\Writer\TranslationWriterInterface;
|
||||
|
||||
/**
|
||||
* A command that parses templates to extract translation messages and adds them
|
||||
* into the translation files.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class TranslationUpdateCommand extends Command
|
||||
{
|
||||
private const ASC = 'asc';
|
||||
private const DESC = 'desc';
|
||||
private const SORT_ORDERS = [self::ASC, self::DESC];
|
||||
private const FORMATS = [
|
||||
'xlf12' => ['xlf', '1.2'],
|
||||
'xlf20' => ['xlf', '2.0'],
|
||||
];
|
||||
|
||||
protected static $defaultName = 'translation:extract|translation:update';
|
||||
protected static $defaultDescription = 'Extract missing translations keys from code to translation files.';
|
||||
|
||||
private $writer;
|
||||
private $reader;
|
||||
private $extractor;
|
||||
private $defaultLocale;
|
||||
private $defaultTransPath;
|
||||
private $defaultViewsPath;
|
||||
private $transPaths;
|
||||
private $codePaths;
|
||||
private $enabledLocales;
|
||||
|
||||
public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $codePaths = [], array $enabledLocales = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->writer = $writer;
|
||||
$this->reader = $reader;
|
||||
$this->extractor = $extractor;
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
$this->defaultTransPath = $defaultTransPath;
|
||||
$this->defaultViewsPath = $defaultViewsPath;
|
||||
$this->transPaths = $transPaths;
|
||||
$this->codePaths = $codePaths;
|
||||
$this->enabledLocales = $enabledLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
|
||||
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
|
||||
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
|
||||
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format (deprecated)'),
|
||||
new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'xlf12'),
|
||||
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 extract be done'),
|
||||
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
|
||||
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'Specify the domain to extract'),
|
||||
new InputOption('xliff-version', null, InputOption::VALUE_OPTIONAL, 'Override the default xliff version (deprecated)'),
|
||||
new InputOption('sort', null, InputOption::VALUE_OPTIONAL, 'Return list of messages sorted alphabetically', 'asc'),
|
||||
new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command extracts translation strings from templates
|
||||
of a given bundle or the default translations directory. It can display them or merge
|
||||
the new ones into the translation files.
|
||||
|
||||
When new translation strings are found it can automatically add a prefix to the translation
|
||||
message.
|
||||
|
||||
Example running against a Bundle (AcmeBundle)
|
||||
|
||||
<info>php %command.full_name% --dump-messages en AcmeBundle</info>
|
||||
<info>php %command.full_name% --force --prefix="new_" fr AcmeBundle</info>
|
||||
|
||||
Example running against default messages directory
|
||||
|
||||
<info>php %command.full_name% --dump-messages en</info>
|
||||
<info>php %command.full_name% --force --prefix="new_" fr</info>
|
||||
|
||||
You can sort the output with the <comment>--sort</> flag:
|
||||
|
||||
<info>php %command.full_name% --dump-messages --sort=asc en AcmeBundle</info>
|
||||
<info>php %command.full_name% --dump-messages --sort=desc fr</info>
|
||||
|
||||
You can dump a tree-like structure using the yaml format with <comment>--as-tree</> flag:
|
||||
|
||||
<info>php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle</info>
|
||||
<info>php %command.full_name% --force --format=yaml --sort=asc --as-tree=3 fr</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $output instanceof ConsoleOutputInterface ? new SymfonyStyle($input, $output->getErrorOutput()) : $io;
|
||||
|
||||
if ('translation:update' === $input->getFirstArgument()) {
|
||||
$errorIo->caution('Command "translation:update" is deprecated since version 5.4 and will be removed in Symfony 6.0. Use "translation:extract" instead.');
|
||||
}
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
// check presence of force or dump-message
|
||||
if (true !== $input->getOption('force') && true !== $input->getOption('dump-messages')) {
|
||||
$errorIo->error('You must choose one of --force or --dump-messages');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$format = $input->getOption('output-format') ?: $input->getOption('format');
|
||||
$xliffVersion = $input->getOption('xliff-version') ?? '1.2';
|
||||
|
||||
if ($input->getOption('xliff-version')) {
|
||||
$errorIo->warning(sprintf('The "--xliff-version" option is deprecated since version 5.3, use "--format=xlf%d" instead.', 10 * $xliffVersion));
|
||||
}
|
||||
|
||||
if ($input->getOption('output-format')) {
|
||||
$errorIo->warning(sprintf('The "--output-format" option is deprecated since version 5.3, use "--format=xlf%d" instead.', 10 * $xliffVersion));
|
||||
}
|
||||
|
||||
if (\in_array($format, array_keys(self::FORMATS), true)) {
|
||||
[$format, $xliffVersion] = self::FORMATS[$format];
|
||||
}
|
||||
|
||||
// check format
|
||||
$supportedFormats = $this->writer->getFormats();
|
||||
if (!\in_array($format, $supportedFormats, true)) {
|
||||
$errorIo->error(['Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).', xlf12 and xlf20.']);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Paths
|
||||
$transPaths = $this->getRootTransPaths();
|
||||
$codePaths = $this->getRootCodePaths($kernel);
|
||||
|
||||
$currentName = 'default directory';
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$foundBundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$bundleDir = $foundBundle->getPath();
|
||||
$transPaths = [is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundleDir.'/translations'];
|
||||
$codePaths = [is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundleDir.'/templates'];
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
$currentName = $foundBundle->getName();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$path = $input->getArgument('bundle');
|
||||
|
||||
$transPaths = [$path.'/translations'];
|
||||
$codePaths = [$path.'/templates'];
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$io->title('Translation Messages Extractor and Dumper');
|
||||
$io->comment(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
|
||||
|
||||
$io->comment('Parsing templates...');
|
||||
$extractedCatalogue = $this->extractMessages($input->getArgument('locale'), $codePaths, $input->getOption('prefix'));
|
||||
|
||||
$io->comment('Loading translation files...');
|
||||
$currentCatalogue = $this->loadCurrentMessages($input->getArgument('locale'), $transPaths);
|
||||
|
||||
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)
|
||||
: new MergeOperation($currentCatalogue, $extractedCatalogue);
|
||||
|
||||
// Exit if no messages found.
|
||||
if (!\count($operation->getDomains())) {
|
||||
$errorIo->warning('No translation messages were found.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$resultMessage = 'Translation files were successfully updated';
|
||||
|
||||
$operation->moveMessagesToIntlDomainsIfPossible('new');
|
||||
|
||||
// show compiled list of messages
|
||||
if (true === $input->getOption('dump-messages')) {
|
||||
$extractedMessagesCount = 0;
|
||||
$io->newLine();
|
||||
foreach ($operation->getDomains() as $domain) {
|
||||
$newKeys = array_keys($operation->getNewMessages($domain));
|
||||
$allKeys = array_keys($operation->getMessages($domain));
|
||||
|
||||
$list = array_merge(
|
||||
array_diff($allKeys, $newKeys),
|
||||
array_map(function ($id) {
|
||||
return sprintf('<fg=green>%s</>', $id);
|
||||
}, $newKeys),
|
||||
array_map(function ($id) {
|
||||
return sprintf('<fg=red>%s</>', $id);
|
||||
}, array_keys($operation->getObsoleteMessages($domain)))
|
||||
);
|
||||
|
||||
$domainMessagesCount = \count($list);
|
||||
|
||||
if ($sort = $input->getOption('sort')) {
|
||||
$sort = strtolower($sort);
|
||||
if (!\in_array($sort, self::SORT_ORDERS, true)) {
|
||||
$errorIo->error(['Wrong sort order', 'Supported formats are: '.implode(', ', self::SORT_ORDERS).'.']);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (self::DESC === $sort) {
|
||||
rsort($list);
|
||||
} else {
|
||||
sort($list);
|
||||
}
|
||||
}
|
||||
|
||||
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : ''));
|
||||
$io->listing($list);
|
||||
|
||||
$extractedMessagesCount += $domainMessagesCount;
|
||||
}
|
||||
|
||||
if ('xlf' === $format) {
|
||||
$io->comment(sprintf('Xliff output version is <info>%s</info>', $xliffVersion));
|
||||
}
|
||||
|
||||
$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
|
||||
}
|
||||
|
||||
// save the files
|
||||
if (true === $input->getOption('force')) {
|
||||
$io->comment('Writing files...');
|
||||
|
||||
$bundleTransPath = false;
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$bundleTransPath = $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bundleTransPath) {
|
||||
$bundleTransPath = end($transPaths);
|
||||
}
|
||||
|
||||
$this->writer->write($operation->getResult(), $format, ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $xliffVersion, 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]);
|
||||
|
||||
if (true === $input->getOption('dump-messages')) {
|
||||
$resultMessage .= ' and translation files were updated';
|
||||
}
|
||||
}
|
||||
|
||||
$io->success($resultMessage.'.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('locale')) {
|
||||
$suggestions->suggestValues($this->enabledLocales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($input->mustSuggestArgumentValuesFor('bundle')) {
|
||||
$bundles = [];
|
||||
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$bundles[] = $bundle->getName();
|
||||
if ($bundle->getContainerExtension()) {
|
||||
$bundles[] = $bundle->getContainerExtension()->getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($bundles);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues(array_merge(
|
||||
$this->writer->getFormats(),
|
||||
array_keys(self::FORMATS)
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('domain') && $locale = $input->getArgument('locale')) {
|
||||
$extractedCatalogue = $this->extractMessages($locale, $this->getRootCodePaths($kernel), $input->getOption('prefix'));
|
||||
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $this->getRootTransPaths());
|
||||
|
||||
// process catalogues
|
||||
$operation = $input->getOption('clean')
|
||||
? new TargetOperation($currentCatalogue, $extractedCatalogue)
|
||||
: new MergeOperation($currentCatalogue, $extractedCatalogue);
|
||||
|
||||
$suggestions->suggestValues($operation->getDomains());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('sort')) {
|
||||
$suggestions->suggestValues(self::SORT_ORDERS);
|
||||
}
|
||||
}
|
||||
|
||||
private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue
|
||||
{
|
||||
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
|
||||
|
||||
// extract intl-icu messages only
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
if ($intlMessages = $catalogue->all($intlDomain)) {
|
||||
$filteredCatalogue->add($intlMessages, $intlDomain);
|
||||
}
|
||||
|
||||
// extract all messages and subtract intl-icu messages
|
||||
if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {
|
||||
$filteredCatalogue->add($messages, $domain);
|
||||
}
|
||||
foreach ($catalogue->getResources() as $resource) {
|
||||
$filteredCatalogue->addResource($resource);
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $intlDomain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$filteredCatalogue->setMetadata($k, $v, $intlDomain);
|
||||
}
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $domain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$filteredCatalogue->setMetadata($k, $v, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
return $filteredCatalogue;
|
||||
}
|
||||
|
||||
private function extractMessages(string $locale, array $transPaths, string $prefix): MessageCatalogue
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
$this->extractor->setPrefix($prefix);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path) || is_file($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $extractedCatalogue;
|
||||
}
|
||||
|
||||
private function loadCurrentMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCatalogue;
|
||||
}
|
||||
|
||||
private function getRootTransPaths(): array
|
||||
{
|
||||
$transPaths = $this->transPaths;
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
|
||||
return $transPaths;
|
||||
}
|
||||
|
||||
private function getRootCodePaths(KernelInterface $kernel): array
|
||||
{
|
||||
$codePaths = $this->codePaths;
|
||||
$codePaths[] = $kernel->getProjectDir().'/src';
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
|
||||
return $codePaths;
|
||||
}
|
||||
}
|
148
vendor/symfony/framework-bundle/Command/WorkflowDumpCommand.php
vendored
Normal file
148
vendor/symfony/framework-bundle/Command/WorkflowDumpCommand.php
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Workflow\Definition;
|
||||
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
|
||||
use Symfony\Component\Workflow\Dumper\MermaidDumper;
|
||||
use Symfony\Component\Workflow\Dumper\PlantUmlDumper;
|
||||
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
|
||||
use Symfony\Component\Workflow\Marking;
|
||||
|
||||
/**
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class WorkflowDumpCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'workflow:dump';
|
||||
protected static $defaultDescription = 'Dump a workflow';
|
||||
/**
|
||||
* string is the service id.
|
||||
*
|
||||
* @var array<string, Definition>
|
||||
*/
|
||||
private $workflows = [];
|
||||
|
||||
private const DUMP_FORMAT_OPTIONS = [
|
||||
'puml',
|
||||
'mermaid',
|
||||
'dot',
|
||||
];
|
||||
|
||||
public function __construct(array $workflows)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->workflows = $workflows;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::REQUIRED, 'A workflow name'),
|
||||
new InputArgument('marking', InputArgument::IS_ARRAY, 'A marking (a list of places)'),
|
||||
new InputOption('label', 'l', InputOption::VALUE_REQUIRED, 'Label a graph'),
|
||||
new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'),
|
||||
])
|
||||
->setDescription(self::$defaultDescription)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command dumps the graphical representation of a
|
||||
workflow in different formats
|
||||
|
||||
<info>DOT</info>: %command.full_name% <workflow name> | dot -Tpng > workflow.png
|
||||
<info>PUML</info>: %command.full_name% <workflow name> --dump-format=puml | java -jar plantuml.jar -p > workflow.png
|
||||
<info>MERMAID</info>: %command.full_name% <workflow name> --dump-format=mermaid | mmdc -o workflow.svg
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$workflowName = $input->getArgument('name');
|
||||
|
||||
$workflow = null;
|
||||
|
||||
if (isset($this->workflows['workflow.'.$workflowName])) {
|
||||
$workflow = $this->workflows['workflow.'.$workflowName];
|
||||
$type = 'workflow';
|
||||
} elseif (isset($this->workflows['state_machine.'.$workflowName])) {
|
||||
$workflow = $this->workflows['state_machine.'.$workflowName];
|
||||
$type = 'state_machine';
|
||||
}
|
||||
|
||||
if (null === $workflow) {
|
||||
throw new InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $workflowName));
|
||||
}
|
||||
|
||||
switch ($input->getOption('dump-format')) {
|
||||
case 'puml':
|
||||
$transitionType = 'workflow' === $type ? PlantUmlDumper::WORKFLOW_TRANSITION : PlantUmlDumper::STATEMACHINE_TRANSITION;
|
||||
$dumper = new PlantUmlDumper($transitionType);
|
||||
break;
|
||||
|
||||
case 'mermaid':
|
||||
$transitionType = 'workflow' === $type ? MermaidDumper::TRANSITION_TYPE_WORKFLOW : MermaidDumper::TRANSITION_TYPE_STATEMACHINE;
|
||||
$dumper = new MermaidDumper($transitionType);
|
||||
break;
|
||||
|
||||
case 'dot':
|
||||
default:
|
||||
$dumper = ('workflow' === $type) ? new GraphvizDumper() : new StateMachineGraphvizDumper();
|
||||
}
|
||||
|
||||
$marking = new Marking();
|
||||
|
||||
foreach ($input->getArgument('marking') as $place) {
|
||||
$marking->mark($place);
|
||||
}
|
||||
|
||||
$options = [
|
||||
'name' => $workflowName,
|
||||
'nofooter' => true,
|
||||
'graph' => [
|
||||
'label' => $input->getOption('label'),
|
||||
],
|
||||
];
|
||||
$output->writeln($dumper->dump($workflow, $marking, $options));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->workflows));
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('dump-format')) {
|
||||
$suggestions->suggestValues(self::DUMP_FORMAT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
63
vendor/symfony/framework-bundle/Command/XliffLintCommand.php
vendored
Normal file
63
vendor/symfony/framework-bundle/Command/XliffLintCommand.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Translation\Command\XliffLintCommand as BaseLintCommand;
|
||||
|
||||
/**
|
||||
* Validates XLIFF files syntax and outputs encountered errors.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class XliffLintCommand extends BaseLintCommand
|
||||
{
|
||||
protected static $defaultName = 'lint:xliff';
|
||||
protected static $defaultDescription = 'Lints an XLIFF file and outputs encountered errors';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$directoryIteratorProvider = function ($directory, $default) {
|
||||
if (!is_dir($directory)) {
|
||||
$directory = $this->getApplication()->getKernel()->locateResource($directory);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
};
|
||||
|
||||
$isReadableProvider = function ($fileOrDirectory, $default) {
|
||||
return str_starts_with($fileOrDirectory, '@') || $default($fileOrDirectory);
|
||||
};
|
||||
|
||||
parent::__construct(null, $directoryIteratorProvider, $isReadableProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setHelp($this->getHelp().<<<'EOF'
|
||||
|
||||
Or find all files in a bundle:
|
||||
|
||||
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
62
vendor/symfony/framework-bundle/Command/YamlLintCommand.php
vendored
Normal file
62
vendor/symfony/framework-bundle/Command/YamlLintCommand.php
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
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>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class YamlLintCommand extends BaseLintCommand
|
||||
{
|
||||
protected static $defaultName = 'lint:yaml';
|
||||
protected static $defaultDescription = 'Lint a YAML file and outputs encountered errors';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$directoryIteratorProvider = function ($directory, $default) {
|
||||
if (!is_dir($directory)) {
|
||||
$directory = $this->getApplication()->getKernel()->locateResource($directory);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
};
|
||||
|
||||
$isReadableProvider = function ($fileOrDirectory, $default) {
|
||||
return str_starts_with($fileOrDirectory, '@') || $default($fileOrDirectory);
|
||||
};
|
||||
|
||||
parent::__construct(null, $directoryIteratorProvider, $isReadableProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setHelp($this->getHelp().<<<'EOF'
|
||||
|
||||
Or find all files in a bundle:
|
||||
|
||||
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user