Completed
Push — master ( ba3223...b47a39 )
by Luís
17s
created

MappingDescribeCommand::formatValue()   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 9.1582

Importance

Changes 0
Metric Value
cc 9
eloc 15
nc 8
nop 1
dl 0
loc 31
rs 4.909
c 0
b 0
f 0
ccs 14
cts 16
cp 0.875
crap 9.1582
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Tools\Console\Command;
21
22
use Doctrine\Common\Persistence\Mapping\MappingException;
23
use Doctrine\ORM\EntityManagerInterface;
24
use Symfony\Component\Console\Command\Command;
25
use Symfony\Component\Console\Input\InputArgument;
26
use Symfony\Component\Console\Input\InputInterface;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\Console\Style\SymfonyStyle;
29
30
/**
31
 * Show information about mapped entities.
32
 *
33
 * @link    www.doctrine-project.org
34
 * @since   2.4
35
 * @author  Daniel Leech <[email protected]>
36
 */
37
final class MappingDescribeCommand extends Command
38
{
39
    /**
40
     * {@inheritdoc}
41
     */
42 3
    protected function configure()
43
    {
44 3
        $this->setName('orm:mapping:describe')
45 3
             ->addArgument('entityName', InputArgument::REQUIRED, 'Full or partial name of entity')
46 3
             ->setDescription('Display information about mapped objects')
47 3
             ->setHelp(<<<EOT
48 3
The %command.full_name% command describes the metadata for the given full or partial entity class name.
49
50
    <info>%command.full_name%</info> My\Namespace\Entity\MyEntity
51
52
Or:
53
54
    <info>%command.full_name%</info> MyEntity
55
EOT
56
             );
57 3
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 3
    protected function execute(InputInterface $input, OutputInterface $output)
63
    {
64 3
        $ui = new SymfonyStyle($input, $output);
65
66
        /* @var $entityManager \Doctrine\ORM\EntityManagerInterface */
67 3
        $entityManager = $this->getHelper('em')->getEntityManager();
68
69 3
        $this->displayEntity($input->getArgument('entityName'), $entityManager, $ui);
70
71 1
        return 0;
72
    }
73
74
    /**
75
     * Display all the mapping information for a single Entity.
76
     *
77
     * @param string                 $entityName    Full or partial entity class name
78
     * @param EntityManagerInterface $entityManager
79
     * @param SymfonyStyle           $ui
80
     */
81 3
    private function displayEntity($entityName, EntityManagerInterface $entityManager, SymfonyStyle $ui)
82
    {
83 3
        $metadata = $this->getClassMetadata($entityName, $entityManager);
84
85 1
        $ui->table(
86 1
            ['Field', 'Value'],
87 1
            array_merge(
88
                [
89 1
                    $this->formatField('Name', $metadata->name),
90 1
                    $this->formatField('Root entity name', $metadata->rootEntityName),
91 1
                    $this->formatField('Custom generator definition', $metadata->customGeneratorDefinition),
92 1
                    $this->formatField('Custom repository class', $metadata->customRepositoryClassName),
93 1
                    $this->formatField('Mapped super class?', $metadata->isMappedSuperclass),
94 1
                    $this->formatField('Embedded class?', $metadata->isEmbeddedClass),
95 1
                    $this->formatField('Parent classes', $metadata->parentClasses),
96 1
                    $this->formatField('Sub classes', $metadata->subClasses),
97 1
                    $this->formatField('Embedded classes', $metadata->subClasses),
98 1
                    $this->formatField('Named queries', $metadata->namedQueries),
99 1
                    $this->formatField('Named native queries', $metadata->namedNativeQueries),
100 1
                    $this->formatField('SQL result set mappings', $metadata->sqlResultSetMappings),
101 1
                    $this->formatField('Identifier', $metadata->identifier),
102 1
                    $this->formatField('Inheritance type', $metadata->inheritanceType),
103 1
                    $this->formatField('Discriminator column', $metadata->discriminatorColumn),
104 1
                    $this->formatField('Discriminator value', $metadata->discriminatorValue),
105 1
                    $this->formatField('Discriminator map', $metadata->discriminatorMap),
106 1
                    $this->formatField('Generator type', $metadata->generatorType),
107 1
                    $this->formatField('Table', $metadata->table),
108 1
                    $this->formatField('Composite identifier?', $metadata->isIdentifierComposite),
109 1
                    $this->formatField('Foreign identifier?', $metadata->containsForeignIdentifier),
110 1
                    $this->formatField('Sequence generator definition', $metadata->sequenceGeneratorDefinition),
111 1
                    $this->formatField('Table generator definition', $metadata->tableGeneratorDefinition),
112 1
                    $this->formatField('Change tracking policy', $metadata->changeTrackingPolicy),
113 1
                    $this->formatField('Versioned?', $metadata->isVersioned),
114 1
                    $this->formatField('Version field', $metadata->versionField),
115 1
                    $this->formatField('Read only?', $metadata->isReadOnly),
116
117 1
                    $this->formatEntityListeners($metadata->entityListeners),
118
                ],
119 1
                [$this->formatField('Association mappings:', '')],
120 1
                $this->formatMappings($metadata->associationMappings),
121 1
                [$this->formatField('Field mappings:', '')],
122 1
                $this->formatMappings($metadata->fieldMappings)
123
            )
124
        );
125 1
    }
126
127
    /**
128
     * Return all mapped entity class names
129
     *
130
     * @param EntityManagerInterface $entityManager
131
     *
132
     * @return string[]
133
     */
134 3
    private function getMappedEntities(EntityManagerInterface $entityManager)
135
    {
136 3
        $entityClassNames = $entityManager->getConfiguration()
137 3
                                          ->getMetadataDriverImpl()
138 3
                                          ->getAllClassNames();
139
140 3
        if ( ! $entityClassNames) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $entityClassNames of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
141
            throw new \InvalidArgumentException(
142
                'You do not have any mapped Doctrine ORM entities according to the current configuration. '.
143
                'If you have entities or mapping files you should check your mapping configuration for errors.'
144
            );
145
        }
146
147 3
        return $entityClassNames;
148
    }
149
150
    /**
151
     * Return the class metadata for the given entity
152
     * name
153
     *
154
     * @param string                 $entityName    Full or partial entity name
155
     * @param EntityManagerInterface $entityManager
156
     *
157
     * @return \Doctrine\ORM\Mapping\ClassMetadata
158
     */
159 3
    private function getClassMetadata($entityName, EntityManagerInterface $entityManager)
160
    {
161
        try {
162 3
            return $entityManager->getClassMetadata($entityName);
163 3
        } catch (MappingException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
164
        }
165
166 3
        $matches = array_filter(
167 3
            $this->getMappedEntities($entityManager),
168 3
            function ($mappedEntity) use ($entityName) {
169 3
                return preg_match('{' . preg_quote($entityName) . '}', $mappedEntity);
170 3
            }
171
        );
172
173 3
        if ( ! $matches) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $matches of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
174 1
            throw new \InvalidArgumentException(sprintf(
175 1
                'Could not find any mapped Entity classes matching "%s"',
176 1
                $entityName
177
            ));
178
        }
179
180 2
        if (count($matches) > 1) {
181 1
            throw new \InvalidArgumentException(sprintf(
182 1
                'Entity name "%s" is ambiguous, possible matches: "%s"',
183 1
                $entityName, implode(', ', $matches)
184
            ));
185
        }
186
187 1
        return $entityManager->getClassMetadata(current($matches));
188
    }
189
190
    /**
191
     * Format the given value for console output
192
     *
193
     * @param mixed $value
194
     *
195
     * @return string
196
     */
197 1
    private function formatValue($value)
198
    {
199 1
        if ('' === $value) {
200 1
            return '';
201
        }
202
203 1
        if (null === $value) {
204 1
            return '<comment>Null</comment>';
205
        }
206
207 1
        if (is_bool($value)) {
208 1
            return '<comment>' . ($value ? 'True' : 'False') . '</comment>';
209
        }
210
211 1
        if (empty($value)) {
212 1
            return '<comment>Empty</comment>';
213
        }
214
215 1
        if (is_array($value)) {
216 1
            return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
217
        }
218
219 1
        if (is_object($value)) {
220
            return sprintf('<%s>', get_class($value));
221
        }
222
223 1
        if (is_scalar($value)) {
224 1
            return $value;
225
        }
226
227
        throw new \InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true)));
228
    }
229
230
    /**
231
     * Add the given label and value to the two column table output
232
     *
233
     * @param string $label Label for the value
234
     * @param mixed  $value A Value to show
235
     *
236
     * @return array
237
     */
238 1
    private function formatField($label, $value)
239
    {
240 1
        if (null === $value) {
241 1
            $value = '<comment>None</comment>';
242
        }
243
244 1
        return [sprintf('<info>%s</info>', $label), $this->formatValue($value)];
245
    }
246
247
    /**
248
     * Format the association mappings
249
     *
250
     * @param array $propertyMappings
251
     *
252
     * @return array
253
     */
254 1
    private function formatMappings(array $propertyMappings)
255
    {
256 1
        $output = [];
257
258 1
        foreach ($propertyMappings as $propertyName => $mapping) {
259 1
            $output[] = $this->formatField(sprintf('  %s', $propertyName), '');
260
261 1
            foreach ($mapping as $field => $value) {
262 1
                $output[] = $this->formatField(sprintf('    %s', $field), $this->formatValue($value));
263
            }
264
        }
265
266 1
        return $output;
267
    }
268
269
    /**
270
     * Format the entity listeners
271
     *
272
     * @param array $entityListeners
273
     *
274
     * @return array
275
     */
276 1
    private function formatEntityListeners(array $entityListeners)
277
    {
278 1
        return $this->formatField('Entity listeners', array_map('get_class', $entityListeners));
279
    }
280
}
281