From 8dc40e4d2928ac343b08ae786cef0da1a38130c2 Mon Sep 17 00:00:00 2001 From: kbond Date: Fri, 3 Jun 2011 14:38:47 -0400 Subject: [PATCH] [FrameworkBundle] added config:dump console command --- .../Command/ConfigDumpCommand.php | 267 ++++++++++++++++++ .../Command/ContainerDebugCommand.php | 2 +- .../FrameworkBundle/Command/DebugCommand.php | 47 +++ 3 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpCommand.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Command/DebugCommand.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpCommand.php new file mode 100644 index 0000000000..c10cdd5a66 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDumpCommand.php @@ -0,0 +1,267 @@ + + * + * 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\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\Config\Definition\NodeInterface; +use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\PrototypedArrayNode; +use Symfony\Component\Config\Definition\BooleanNode; + +/** + * A console command for dumping available configuration reference + * + * @author Kevin Bond + */ +class ConfigDumpCommand extends DebugCommand +{ + protected $output; + + /** + * @see Command + */ + protected function configure() + { + $this + ->setDefinition(array( + new InputArgument('name', InputArgument::REQUIRED, 'The Bundle or extension alias') + )) + ->setName('config:dump') + ->setDescription('Dumps default configuration for an extension.') + ->setHelp(<<config:dump command dumps the default configuration for an extension/bundle. + +The extension alias or bundle name can be used: + +Example: + + container:debug framework + +or + + container:debug FrameworkBundle + +EOF + ) + ; + } + + /** + * @see Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->output = $output; + $kernel = $this->getContainer()->get('kernel'); + $containerBuilder = $this->getContainerBuilder(); + + $name = $input->getArgument('name'); + + $extension = null; + + if (preg_match('/Bundle$/', $name)) { + // input is bundle name + $extension = $kernel->getBundle($name)->getContainerExtension(); + + if (!$extension) { + throw new \LogicException('No extensions with configuration available for "'.$name.'"'); + } + + $message = 'Default configuration for "'.$name.'"'; + } else { + foreach ($kernel->getBundles() as $bundle) { + $extension = $bundle->getContainerExtension(); + + if ($extension && ($extension->getAlias() == $name)) { + break; + } + + $extension = null; + } + + if (!$extension) { + throw new \LogicException('No extension with alias "'.$name.'" is enabled'); + } + + $message = 'Default configuration for extension with alias: "'.$name.'"'; + } + + $configuration = $extension->getConfiguration(array(), $containerBuilder); + + if (!$configuration) { + throw new \LogicException('The extension with alias "'.$extension->getAlias(). + '" does not have it\'s getConfiguration() method setup'); + } + + $rootNode = $configuration->getConfigTreeBuilder()->buildTree(); + + $output->writeln($message); + + // root node + $this->outputNode($rootNode); + } + + /** + * Outputs a single config reference line + * + * @param string $text + * @param int $indent + */ + private function outputLine($text, $indent = 0) + { + $indent = strlen($text) + $indent; + + $format = '%'.$indent.'s'; + + $this->output->writeln(sprintf($format, $text)); + } + + private function outputArray(array $array, $depth) + { + $is_indexed = array_values($array) === $array; + + foreach ($array as $key => $value) { + if (is_array($value)) { + $val = ''; + } else { + $val = $value; + } + + if ($is_indexed) { + $this->outputLine('- '.$val, $depth * 4); + + } else { + $text = sprintf('%-20s %s', $key.':', $val); + $this->outputLine($text, $depth * 4); + + } + + if (is_array($value)) { + $this->outputArray($value, $depth + 1); + } + } + } + + /** + * @param NodeInterface $node + * @param int $depth + */ + private function outputNode(NodeInterface $node, $depth = 0) + { + $comments = array(); + $default = ''; + $defaultArray = null; + $children = null; + $example = $node->getExample(); + + // defaults + if ($node instanceof ArrayNode) { + $children = $node->getChildren(); + + if ($node instanceof PrototypedArrayNode) { + $prototype = $node->getPrototype(); + + if ($prototype instanceof ArrayNode) { + $children = $prototype->getChildren(); + } + + // check for attribute as key + if ($key = $node->getKeyAttribute()) { + $keyNode = new ArrayNode($key, $node); + $keyNode->setInfo('Prototype'); + + // add children + foreach ($children as $childNode) { + $keyNode->addChild($childNode); + } + $children = array($key => $keyNode); + } + } + + if (!$children) { + if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) { + $default = ''; + } elseif (!is_array($example)) { + $default = '[]'; + } + } + } else { + $default = '~'; + + if ($node->hasDefaultValue()) { + $default = $node->getDefaultValue(); + + if (true === $default) { + $default = 'true'; + } elseif (false === $default) { + $default = 'false'; + } elseif (null === $default) { + $default = '~'; + } + } + } + + // required? + if ($node->isRequired()) { + $comments[] = 'Required'; + } + + // example + if ($example && !is_array($example)) { + $comments[] = 'Example: '.$example; + } + + $default = (string) $default != '' ? ' '.$default : ''; + $comments = count($comments) ? '# '.implode(', ', $comments) : ''; + + $text = sprintf('%-20s %s %s', $node->getName().':', $default, $comments); + + if ($info = $node->getInfo()) { + $this->outputLine(''); + $this->outputLine('# '.$info, $depth * 4); + } + + $this->outputLine($text, $depth * 4); + + // output defaults + if ($defaultArray) { + $this->outputLine(''); + + $message = count($defaultArray) > 1 ? 'Defaults' : 'Default'; + + $this->outputLine('# '.$message.':', $depth * 4 + 4); + + $this->outputArray($defaultArray, $depth + 1); + } + + if (is_array($example)) { + $this->outputLine(''); + + $message = count($example) > 1 ? 'Examples' : 'Example'; + + $this->outputLine('# '.$message.':', $depth * 4 + 4); + + $this->outputArray($example, $depth + 1); + } + + if ($children) { + foreach ($children as $childNode) { + $this->outputNode($childNode, $depth + 1); + } + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 305832545f..e252287d70 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -27,7 +27,7 @@ use Symfony\Component\Config\FileLocator; * * @author Ryan Weaver */ -class ContainerDebugCommand extends ContainerAwareCommand +class ContainerDebugCommand extends DebugCommand { /** * @var ContainerBuilder diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/DebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/DebugCommand.php new file mode 100644 index 0000000000..5bfc8b41ad --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/DebugCommand.php @@ -0,0 +1,47 @@ + + * + * 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\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Base command for debug tasks + * + * @author Kevin Bond + */ +abstract class DebugCommand extends ContainerAwareCommand +{ + /** + * Loads the ContainerBuilder from the cache. + * + * @return ContainerBuilder + */ + protected function getContainerBuilder() + { + if (!$this->getApplication()->getKernel()->isDebug()) { + throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.')); + } + + if (!file_exists($cachedFile = $this->getContainer()->getParameter('debug.container.dump'))) { + throw new \LogicException(sprintf('Debug information about the container could not be found. Please clear the cache and try again.')); + } + + $container = new ContainerBuilder(); + + $loader = new XmlFileLoader($container, new FileLocator()); + $loader->load($cachedFile); + + return $container; + } +}