From 37de75b2ae3c529d6bd3c04dc1a5e582d9f8f269 Mon Sep 17 00:00:00 2001 From: dantleech Date: Sun, 31 Aug 2014 09:27:16 +0200 Subject: [PATCH] Split new functionality into new command --- .../ORM/Tools/Console/Command/InfoCommand.php | 296 +---------------- .../Command/MappingDescribeCommand.php | 309 ++++++++++++++++++ .../Tools/Console/Command/InfoCommandTest.php | 36 -- .../Command/MappingDescribeCommandTest.php | 83 +++++ 4 files changed, 410 insertions(+), 314 deletions(-) create mode 100644 lib/Doctrine/ORM/Tools/Console/Command/MappingDescribeCommand.php create mode 100644 tests/Doctrine/Tests/ORM/Tools/Console/Command/MappingDescribeCommandTest.php diff --git a/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php index 054942713..f23fe22c1 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php @@ -23,8 +23,6 @@ use Doctrine\ORM\Mapping\MappingException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Helper\TableHelper; /** * Show information about mapped entities. @@ -32,20 +30,9 @@ use Symfony\Component\Console\Helper\TableHelper; * @link www.doctrine-project.org * @since 2.1 * @author Benjamin Eberlei - * @author Daniel Leech */ class InfoCommand extends Command { - /** - * @var OutputInterface - */ - private $output; - - /** - * @var array - */ - private $out; - /** * {@inheritdoc} */ @@ -53,20 +40,11 @@ class InfoCommand extends Command { $this ->setName('orm:info') - ->addArgument('entityName', InputArgument::OPTIONAL, 'Show detailed information about the given class') - ->setDescription('Display information about mapped objects') + ->setDescription('Show basic information about all mapped entities') ->setHelp(<<%command.name% without arguments shows basic information about -which entities exist and possibly if their mapping information contains errors -or not. - -You can display the complete metadata for a given entity by specifying it, e.g. - - %command.full_name% My\Namespace\Entity\MyEntity - -You can also specify a partial class name (as a regex): - - %command.full_name% MyEntity +The %command.name% shows basic information about which +entities exist and possibly if their mapping information contains errors or +not. EOT ); } @@ -76,47 +54,32 @@ EOT */ protected function execute(InputInterface $input, OutputInterface $output) { - $entityName = $input->getArgument('entityName'); - /* @var $entityManager \Doctrine\ORM\EntityManager */ $entityManager = $this->getHelper('em')->getEntityManager(); - $this->output = $output; - $this->entityManager = $entityManager; + $entityClassNames = $entityManager->getConfiguration() + ->getMetadataDriverImpl() + ->getAllClassNames(); - if (null === $entityName) { - return $this->displayAll($output); + if (!$entityClassNames) { + throw new \Exception( + 'You do not have any mapped Doctrine ORM entities according to the current configuration. '. + 'If you have entities or mapping files you should check your mapping configuration for errors.' + ); } - $this->displayEntity($entityName); - - return 0; - } - - /** - * List all the mapped classes - * - * Returns the exit code, which will be 1 if there are any mapping exceptions - * encountered when listing the mapped classes. - * - * @return integer - */ - private function displayAll() - { - $entityClassNames = $this->getMappedEntities(); - - $this->output->writeln(sprintf("Found %d mapped entities:", count($entityClassNames))); + $output->writeln(sprintf("Found %d mapped entities:", count($entityClassNames))); $failure = false; foreach ($entityClassNames as $entityClassName) { try { - $meta = $this->entityManager->getClassMetadata($entityClassName); - $this->output->writeln(sprintf("[OK] %s", $entityClassName)); + $entityManager->getClassMetadata($entityClassName); + $output->writeln(sprintf("[OK] %s", $entityClassName)); } catch (MappingException $e) { - $this->output->writeln("[FAIL] ".$entityClassName); - $this->output->writeln(sprintf("%s", $e->getMessage())); - $this->output->writeln(''); + $output->writeln("[FAIL] ".$entityClassName); + $output->writeln(sprintf("%s", $e->getMessage())); + $output->writeln(''); $failure = true; } @@ -124,227 +87,4 @@ EOT return $failure ? 1 : 0; } - - /** - * Display all the mapping information for a single Entity. - * - * @param string $entityName Full or partial entity class name - */ - private function displayEntity($entityName) - { - $meta = $this->getClassMetadata($entityName); - - $this->formatField('Name', $meta->name); - $this->formatField('Root entity name', $meta->rootEntityName); - $this->formatField('Custom generator definition', $meta->customGeneratorDefinition); - $this->formatField('Custom repository class', $meta->customRepositoryClassName); - $this->formatField('Mapped super class?', $meta->isMappedSuperclass); - $this->formatField('Embedded class?', $meta->isEmbeddedClass); - $this->formatField('Parent classes', $meta->parentClasses); - $this->formatField('Sub classes', $meta->subClasses); - $this->formatField('Embedded classes', $meta->subClasses); - $this->formatField('Named queries', $meta->namedQueries); - $this->formatField('Named native queries', $meta->namedNativeQueries); - $this->formatField('SQL result set mappings', $meta->sqlResultSetMappings); - $this->formatField('Identifier', $meta->identifier); - $this->formatField('Inheritance type', $meta->inheritanceType); - $this->formatField('Discriminator column', $meta->discriminatorColumn); - $this->formatField('Discriminator value', $meta->discriminatorValue); - $this->formatField('Discriminator map', $meta->discriminatorMap); - $this->formatField('Generator type', $meta->generatorType); - $this->formatField('Table', $meta->table); - $this->formatField('Composite identifier?', $meta->isIdentifierComposite); - $this->formatField('Foreign identifier?', $meta->containsForeignIdentifier); - $this->formatField('Sequence generator definition', $meta->sequenceGeneratorDefinition); - $this->formatField('Table generator definition', $meta->tableGeneratorDefinition); - $this->formatField('Change tracking policy', $meta->changeTrackingPolicy); - $this->formatField('Versioned?', $meta->isVersioned); - $this->formatField('Version field', $meta->versionField); - $this->formatField('Read only?', $meta->isReadOnly); - $this->formatField('Foo', array('Foo', 'Bar', 'Boo')); - - $this->formatEntityListeners($meta->entityListeners); - $this->formatAssociationMappings($meta->associationMappings); - $this->formatFieldMappings($meta->fieldMappings); - - if (class_exists('Symfony\Component\Console\Helper\TableHelper')) { - $table = new TableHelper(); - $table->setHeaders(array('Field', 'Value')); - foreach ($this->out as $tuple) { - $table->addRow($tuple); - } - $table->render($this->output); - } else { - foreach ($this->out as $tuple) { - list($label, $value) = $tuple; - $this->output->writeln(sprintf('%s: %s', $label, $value)); - } - } - } - - /** - * Return all mapped entity class names - * - * @return array - */ - private function getMappedEntities() - { - $entityClassNames = $this->entityManager->getConfiguration() - ->getMetadataDriverImpl() - ->getAllClassNames(); - - if (!$entityClassNames) { - throw new \InvalidArgumentException( - 'You do not have any mapped Doctrine ORM entities according to the current configuration. '. - 'If you have entities or mapping files you should check your mapping configuration for errors.' - ); - } - - return $entityClassNames; - } - - /** - * Return the class metadata for the given entity - * name - * - * @param string $entityName Full or partial entity name - */ - private function getClassMetadata($entityName) - { - try { - $meta = $this->entityManager->getClassMetadata($entityName); - } catch (\Doctrine\Common\Persistence\Mapping\MappingException $e) { - $mappedEntities = $this->getMappedEntities(); - $matches = array_filter($mappedEntities, function ($mappedEntity) use ($entityName) { - if (preg_match('{' . preg_quote($entityName) . '}', $mappedEntity)) { - return true; - } - - return false; - }); - - if (0 === count($matches)) { - throw new \InvalidArgumentException(sprintf( - 'Could not find any mapped Entity classes matching "%s"', - $entityName - )); - } - - if (1 === count($matches)) { - $meta = $this->entityManager->getClassMetadata(current($matches)); - } else { - throw new \InvalidArgumentException(sprintf( - 'Entity name "%s" is ambigous, possible matches: "%s"', - $entityName, implode(', ', $matches) - )); - } - } - - return $meta; - } - - /** - * Format the given value for console output - * - * @param mixed $value - */ - private function formatValue($value) - { - if ('' === $value) { - return ''; - } - - if (null === $value) { - return 'Null'; - } - - if (is_bool($value)) { - return '' . ($value ? 'True' : 'False') . ''; - } - - if (empty($value)) { - return 'Empty'; - } - - if (is_array($value)) { - if (version_compare(phpversion(), '5.4.0', '>=')) { - return json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); - } - - return json_encode($value); - } - - if (is_object($value)) { - return sprintf('<%s>', get_class($value)); - } - - if (is_scalar($value)) { - return $value; - } - - throw new \InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true))); - } - - /** - * Add the given label and value to the two column table - * output - * - * @param string $label Label for the value - * @param mixed $valueA Value to show - */ - private function formatField($label, $value) - { - if (null === $value) { - $value = 'None'; - } - - $this->out[] = array(sprintf('%s', $label), $this->formatValue($value)); - } - - /** - * Format the association mappings - * - * @param array - */ - private function formatAssociationMappings($associationMappings) - { - $this->formatField('Association mappings:', ''); - foreach ($associationMappings as $associationName => $mapping) { - $this->formatField(sprintf(' %s',$associationName), ''); - foreach ($mapping as $field => $value) { - $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); - } - } - } - - /** - * Format the entity listeners - * - * @param array $entityListeners - */ - private function formatEntityListeners($entityListeners) - { - $entityListenerNames = array(); - foreach ($entityListeners as $entityListener) { - $entityListenerNames[] = get_class($entityListener); - } - - $this->formatField('Entity listeners', $entityListenerNames); - } - - /** - * Form the field mappings - * - * @param array $fieldMappings - */ - private function formatFieldMappings($fieldMappings) - { - $this->formatField('Field mappings:', ''); - foreach ($fieldMappings as $fieldName => $mapping) { - $this->formatField(sprintf(' %s',$fieldName), ''); - foreach ($mapping as $field => $value) { - $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); - } - } - } } diff --git a/lib/Doctrine/ORM/Tools/Console/Command/MappingDescribeCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/MappingDescribeCommand.php new file mode 100644 index 000000000..2825b143c --- /dev/null +++ b/lib/Doctrine/ORM/Tools/Console/Command/MappingDescribeCommand.php @@ -0,0 +1,309 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Doctrine\ORM\Mapping\MappingException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Helper\TableHelper; + +/** + * Show information about mapped entities. + * + * @link www.doctrine-project.org + * @since 2.4 + * @author Daniel Leech + */ +class MappingDescribeCommand extends Command +{ + /** + * @var OutputInterface + */ + private $output; + + /** + * @var array + */ + private $out; + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('orm:mapping:describe') + ->addArgument('entityName', InputArgument::REQUIRED, 'Full or partial name of entity') + ->setDescription('Display information about mapped objects') + ->setHelp(<<%command.full_name% My\Namespace\Entity\MyEntity + +Or: + + %command.full_name% MyEntity +EOT + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $entityName = $input->getArgument('entityName'); + + /* @var $entityManager \Doctrine\ORM\EntityManager */ + $entityManager = $this->getHelper('em')->getEntityManager(); + + $this->output = $output; + $this->entityManager = $entityManager; + + $this->displayEntity($entityName); + + return 0; + } + + /** + * Display all the mapping information for a single Entity. + * + * @param string $entityName Full or partial entity class name + */ + private function displayEntity($entityName) + { + $meta = $this->getClassMetadata($entityName); + + $this->formatField('Name', $meta->name); + $this->formatField('Root entity name', $meta->rootEntityName); + $this->formatField('Custom generator definition', $meta->customGeneratorDefinition); + $this->formatField('Custom repository class', $meta->customRepositoryClassName); + $this->formatField('Mapped super class?', $meta->isMappedSuperclass); + $this->formatField('Embedded class?', $meta->isEmbeddedClass); + $this->formatField('Parent classes', $meta->parentClasses); + $this->formatField('Sub classes', $meta->subClasses); + $this->formatField('Embedded classes', $meta->subClasses); + $this->formatField('Named queries', $meta->namedQueries); + $this->formatField('Named native queries', $meta->namedNativeQueries); + $this->formatField('SQL result set mappings', $meta->sqlResultSetMappings); + $this->formatField('Identifier', $meta->identifier); + $this->formatField('Inheritance type', $meta->inheritanceType); + $this->formatField('Discriminator column', $meta->discriminatorColumn); + $this->formatField('Discriminator value', $meta->discriminatorValue); + $this->formatField('Discriminator map', $meta->discriminatorMap); + $this->formatField('Generator type', $meta->generatorType); + $this->formatField('Table', $meta->table); + $this->formatField('Composite identifier?', $meta->isIdentifierComposite); + $this->formatField('Foreign identifier?', $meta->containsForeignIdentifier); + $this->formatField('Sequence generator definition', $meta->sequenceGeneratorDefinition); + $this->formatField('Table generator definition', $meta->tableGeneratorDefinition); + $this->formatField('Change tracking policy', $meta->changeTrackingPolicy); + $this->formatField('Versioned?', $meta->isVersioned); + $this->formatField('Version field', $meta->versionField); + $this->formatField('Read only?', $meta->isReadOnly); + $this->formatField('Foo', array('Foo', 'Bar', 'Boo')); + + $this->formatEntityListeners($meta->entityListeners); + $this->formatAssociationMappings($meta->associationMappings); + $this->formatFieldMappings($meta->fieldMappings); + + if (class_exists('Symfony\Component\Console\Helper\TableHelper')) { + $table = new TableHelper(); + $table->setHeaders(array('Field', 'Value')); + foreach ($this->out as $tuple) { + $table->addRow($tuple); + } + $table->render($this->output); + } else { + foreach ($this->out as $tuple) { + list($label, $value) = $tuple; + $this->output->writeln(sprintf('%s: %s', $label, $value)); + } + } + } + + /** + * Return all mapped entity class names + * + * @return array + */ + private function getMappedEntities() + { + $entityClassNames = $this->entityManager->getConfiguration() + ->getMetadataDriverImpl() + ->getAllClassNames(); + + if (!$entityClassNames) { + throw new \InvalidArgumentException( + 'You do not have any mapped Doctrine ORM entities according to the current configuration. '. + 'If you have entities or mapping files you should check your mapping configuration for errors.' + ); + } + + return $entityClassNames; + } + + /** + * Return the class metadata for the given entity + * name + * + * @param string $entityName Full or partial entity name + */ + private function getClassMetadata($entityName) + { + try { + $meta = $this->entityManager->getClassMetadata($entityName); + } catch (\Doctrine\Common\Persistence\Mapping\MappingException $e) { + $mappedEntities = $this->getMappedEntities(); + $matches = array_filter($mappedEntities, function ($mappedEntity) use ($entityName) { + if (preg_match('{' . preg_quote($entityName) . '}', $mappedEntity)) { + return true; + } + + return false; + }); + + if (0 === count($matches)) { + throw new \InvalidArgumentException(sprintf( + 'Could not find any mapped Entity classes matching "%s"', + $entityName + )); + } + + if (1 === count($matches)) { + $meta = $this->entityManager->getClassMetadata(current($matches)); + } else { + throw new \InvalidArgumentException(sprintf( + 'Entity name "%s" is ambigous, possible matches: "%s"', + $entityName, implode(', ', $matches) + )); + } + } + + return $meta; + } + + /** + * Format the given value for console output + * + * @param mixed $value + */ + private function formatValue($value) + { + if ('' === $value) { + return ''; + } + + if (null === $value) { + return 'Null'; + } + + if (is_bool($value)) { + return '' . ($value ? 'True' : 'False') . ''; + } + + if (empty($value)) { + return 'Empty'; + } + + if (is_array($value)) { + if (version_compare(phpversion(), '5.4.0', '>=')) { + return json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); + } + + return json_encode($value); + } + + if (is_object($value)) { + return sprintf('<%s>', get_class($value)); + } + + if (is_scalar($value)) { + return $value; + } + + throw new \InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true))); + } + + /** + * Add the given label and value to the two column table + * output + * + * @param string $label Label for the value + * @param mixed $valueA Value to show + */ + private function formatField($label, $value) + { + if (null === $value) { + $value = 'None'; + } + + $this->out[] = array(sprintf('%s', $label), $this->formatValue($value)); + } + + /** + * Format the association mappings + * + * @param array + */ + private function formatAssociationMappings($associationMappings) + { + $this->formatField('Association mappings:', ''); + foreach ($associationMappings as $associationName => $mapping) { + $this->formatField(sprintf(' %s',$associationName), ''); + foreach ($mapping as $field => $value) { + $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); + } + } + } + + /** + * Format the entity listeners + * + * @param array $entityListeners + */ + private function formatEntityListeners($entityListeners) + { + $entityListenerNames = array(); + foreach ($entityListeners as $entityListener) { + $entityListenerNames[] = get_class($entityListener); + } + + $this->formatField('Entity listeners', $entityListenerNames); + } + + /** + * Form the field mappings + * + * @param array $fieldMappings + */ + private function formatFieldMappings($fieldMappings) + { + $this->formatField('Field mappings:', ''); + foreach ($fieldMappings as $fieldName => $mapping) { + $this->formatField(sprintf(' %s',$fieldName), ''); + foreach ($mapping as $field => $value) { + $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); + } + } + } +} diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/Command/InfoCommandTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/Command/InfoCommandTest.php index 41b4ab833..4eafc0f27 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Console/Command/InfoCommandTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Console/Command/InfoCommandTest.php @@ -53,40 +53,4 @@ class InfoCommandTest extends OrmFunctionalTestCase $this->assertContains('Doctrine\Tests\Models\Cache\AttractionInfo', $this->tester->getDisplay()); $this->assertContains('Doctrine\Tests\Models\Cache\City', $this->tester->getDisplay()); } - - public function testShowSpecificFuzzySingle() - { - $this->tester->execute(array( - 'command' => $this->command->getName(), - 'entityName' => 'AttractionInfo', - )); - - $display = $this->tester->getDisplay(); - $this->assertContains('Doctrine\Tests\Models\Cache\AttractionInfo', $display); - $this->assertContains('Root entity name', $display); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage possible matches - */ - public function testShowSpecificFuzzyAmbiguous() - { - $this->tester->execute(array( - 'command' => $this->command->getName(), - 'entityName' => 'Attraction', - )); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Could not find any mapped Entity classes matching "AttractionFooBar" - */ - public function testShowSpecificNotFound() - { - $this->tester->execute(array( - 'command' => $this->command->getName(), - 'entityName' => 'AttractionFooBar' - )); - } } diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/Command/MappingDescribeCommandTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/Command/MappingDescribeCommandTest.php new file mode 100644 index 000000000..92cb41184 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Console/Command/MappingDescribeCommandTest.php @@ -0,0 +1,83 @@ +application = new Application(); + $command = new MappingDescribeCommand(); + + $this->application->setHelperSet(new HelperSet(array( + 'em' => new EntityManagerHelper($this->_em) + ))); + + $this->application->add($command); + + $this->command = $this->application->find('orm:mapping:describe'); + $this->tester = new CommandTester($command); + } + + public function testShowSpecificFuzzySingle() + { + $this->tester->execute(array( + 'command' => $this->command->getName(), + 'entityName' => 'AttractionInfo', + )); + + $display = $this->tester->getDisplay(); + $this->assertContains('Doctrine\Tests\Models\Cache\AttractionInfo', $display); + $this->assertContains('Root entity name', $display); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage possible matches + */ + public function testShowSpecificFuzzyAmbiguous() + { + $this->tester->execute(array( + 'command' => $this->command->getName(), + 'entityName' => 'Attraction', + )); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Could not find any mapped Entity classes matching "AttractionFooBar" + */ + public function testShowSpecificNotFound() + { + $this->tester->execute(array( + 'command' => $this->command->getName(), + 'entityName' => 'AttractionFooBar' + )); + } +} +