These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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\Helper\Table; |
||
26 | use Symfony\Component\Console\Input\InputArgument; |
||
27 | use Symfony\Component\Console\Input\InputInterface; |
||
28 | use Symfony\Component\Console\Output\OutputInterface; |
||
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 | $this |
||
45 | 3 | ->setName('orm:mapping:describe') |
|
46 | 3 | ->addArgument('entityName', InputArgument::REQUIRED, 'Full or partial name of entity') |
|
47 | 3 | ->setDescription('Display information about mapped objects') |
|
48 | 3 | ->setHelp(<<<EOT |
|
49 | 3 | The %command.full_name% command describes the metadata for the given full or partial entity class name. |
|
50 | |||
51 | <info>%command.full_name%</info> My\Namespace\Entity\MyEntity |
||
52 | |||
53 | Or: |
||
54 | |||
55 | <info>%command.full_name%</info> MyEntity |
||
56 | EOT |
||
57 | ); |
||
58 | 3 | } |
|
59 | |||
60 | /** |
||
61 | * {@inheritdoc} |
||
62 | */ |
||
63 | 3 | protected function execute(InputInterface $input, OutputInterface $output) |
|
64 | { |
||
65 | /* @var $entityManager \Doctrine\ORM\EntityManagerInterface */ |
||
66 | 3 | $entityManager = $this->getHelper('em')->getEntityManager(); |
|
0 ignored issues
–
show
|
|||
67 | |||
68 | 3 | $this->displayEntity($input->getArgument('entityName'), $entityManager, $output); |
|
69 | |||
70 | 1 | return 0; |
|
71 | } |
||
72 | |||
73 | /** |
||
74 | * Display all the mapping information for a single Entity. |
||
75 | * |
||
76 | * @param string $entityName Full or partial entity class name |
||
77 | * @param EntityManagerInterface $entityManager |
||
78 | * @param OutputInterface $output |
||
79 | */ |
||
80 | 3 | private function displayEntity($entityName, EntityManagerInterface $entityManager, OutputInterface $output) |
|
81 | { |
||
82 | 3 | $table = new Table($output); |
|
83 | |||
84 | 3 | $table->setHeaders(['Field', 'Value']); |
|
85 | |||
86 | 3 | $metadata = $this->getClassMetadata($entityName, $entityManager); |
|
87 | |||
88 | 1 | array_map( |
|
89 | 1 | [$table, 'addRow'], |
|
90 | 1 | array_merge( |
|
91 | [ |
||
92 | 1 | $this->formatField('Name', $metadata->name), |
|
93 | 1 | $this->formatField('Root entity name', $metadata->rootEntityName), |
|
94 | 1 | $this->formatField('Custom generator definition', $metadata->customGeneratorDefinition), |
|
95 | 1 | $this->formatField('Custom repository class', $metadata->customRepositoryClassName), |
|
96 | 1 | $this->formatField('Mapped super class?', $metadata->isMappedSuperclass), |
|
97 | 1 | $this->formatField('Embedded class?', $metadata->isEmbeddedClass), |
|
98 | 1 | $this->formatField('Parent classes', $metadata->parentClasses), |
|
99 | 1 | $this->formatField('Sub classes', $metadata->subClasses), |
|
100 | 1 | $this->formatField('Embedded classes', $metadata->subClasses), |
|
101 | 1 | $this->formatField('Named queries', $metadata->namedQueries), |
|
102 | 1 | $this->formatField('Named native queries', $metadata->namedNativeQueries), |
|
103 | 1 | $this->formatField('SQL result set mappings', $metadata->sqlResultSetMappings), |
|
104 | 1 | $this->formatField('Identifier', $metadata->identifier), |
|
105 | 1 | $this->formatField('Inheritance type', $metadata->inheritanceType), |
|
106 | 1 | $this->formatField('Discriminator column', $metadata->discriminatorColumn), |
|
107 | 1 | $this->formatField('Discriminator value', $metadata->discriminatorValue), |
|
108 | 1 | $this->formatField('Discriminator map', $metadata->discriminatorMap), |
|
109 | 1 | $this->formatField('Generator type', $metadata->generatorType), |
|
110 | 1 | $this->formatField('Table', $metadata->table), |
|
111 | 1 | $this->formatField('Composite identifier?', $metadata->isIdentifierComposite), |
|
112 | 1 | $this->formatField('Foreign identifier?', $metadata->containsForeignIdentifier), |
|
113 | 1 | $this->formatField('Sequence generator definition', $metadata->sequenceGeneratorDefinition), |
|
114 | 1 | $this->formatField('Table generator definition', $metadata->tableGeneratorDefinition), |
|
115 | 1 | $this->formatField('Change tracking policy', $metadata->changeTrackingPolicy), |
|
116 | 1 | $this->formatField('Versioned?', $metadata->isVersioned), |
|
117 | 1 | $this->formatField('Version field', $metadata->versionField), |
|
118 | 1 | $this->formatField('Read only?', $metadata->isReadOnly), |
|
119 | |||
120 | 1 | $this->formatEntityListeners($metadata->entityListeners), |
|
121 | ], |
||
122 | 1 | [$this->formatField('Association mappings:', '')], |
|
123 | 1 | $this->formatMappings($metadata->associationMappings), |
|
124 | 1 | [$this->formatField('Field mappings:', '')], |
|
125 | 1 | $this->formatMappings($metadata->fieldMappings) |
|
126 | ) |
||
127 | ); |
||
128 | |||
129 | 1 | $table->render(); |
|
130 | 1 | } |
|
131 | |||
132 | /** |
||
133 | * Return all mapped entity class names |
||
134 | * |
||
135 | * @param EntityManagerInterface $entityManager |
||
136 | * |
||
137 | * @return string[] |
||
138 | */ |
||
139 | 3 | private function getMappedEntities(EntityManagerInterface $entityManager) |
|
140 | { |
||
141 | $entityClassNames = $entityManager |
||
142 | 3 | ->getConfiguration() |
|
143 | 3 | ->getMetadataDriverImpl() |
|
144 | 3 | ->getAllClassNames(); |
|
145 | |||
146 | 3 | if ( ! $entityClassNames) { |
|
147 | throw new \InvalidArgumentException( |
||
148 | 'You do not have any mapped Doctrine ORM entities according to the current configuration. '. |
||
149 | 'If you have entities or mapping files you should check your mapping configuration for errors.' |
||
150 | ); |
||
151 | } |
||
152 | |||
153 | 3 | return $entityClassNames; |
|
154 | } |
||
155 | |||
156 | /** |
||
157 | * Return the class metadata for the given entity |
||
158 | * name |
||
159 | * |
||
160 | * @param string $entityName Full or partial entity name |
||
161 | * @param EntityManagerInterface $entityManager |
||
162 | * |
||
163 | * @return \Doctrine\ORM\Mapping\ClassMetadata |
||
164 | */ |
||
165 | 3 | private function getClassMetadata($entityName, EntityManagerInterface $entityManager) |
|
166 | { |
||
167 | try { |
||
168 | 3 | return $entityManager->getClassMetadata($entityName); |
|
169 | 3 | } catch (MappingException $e) { |
|
170 | } |
||
171 | |||
172 | 3 | $matches = array_filter( |
|
173 | 3 | $this->getMappedEntities($entityManager), |
|
174 | 3 | function ($mappedEntity) use ($entityName) { |
|
175 | 3 | return preg_match('{' . preg_quote($entityName) . '}', $mappedEntity); |
|
176 | 3 | } |
|
177 | ); |
||
178 | |||
179 | 3 | if ( ! $matches) { |
|
180 | 1 | throw new \InvalidArgumentException(sprintf( |
|
181 | 1 | 'Could not find any mapped Entity classes matching "%s"', |
|
182 | 1 | $entityName |
|
183 | )); |
||
184 | } |
||
185 | |||
186 | 2 | if (count($matches) > 1) { |
|
187 | 1 | throw new \InvalidArgumentException(sprintf( |
|
188 | 1 | 'Entity name "%s" is ambiguous, possible matches: "%s"', |
|
189 | 1 | $entityName, implode(', ', $matches) |
|
190 | )); |
||
191 | } |
||
192 | |||
193 | 1 | return $entityManager->getClassMetadata(current($matches)); |
|
194 | } |
||
195 | |||
196 | /** |
||
197 | * Format the given value for console output |
||
198 | * |
||
199 | * @param mixed $value |
||
200 | * |
||
201 | * @return string |
||
202 | */ |
||
203 | 1 | private function formatValue($value) |
|
204 | { |
||
205 | 1 | if ('' === $value) { |
|
206 | 1 | return ''; |
|
207 | } |
||
208 | |||
209 | 1 | if (null === $value) { |
|
210 | 1 | return '<comment>Null</comment>'; |
|
211 | } |
||
212 | |||
213 | 1 | if (is_bool($value)) { |
|
214 | 1 | return '<comment>' . ($value ? 'True' : 'False') . '</comment>'; |
|
215 | } |
||
216 | |||
217 | 1 | if (empty($value)) { |
|
218 | 1 | return '<comment>Empty</comment>'; |
|
219 | } |
||
220 | |||
221 | 1 | if (is_array($value)) { |
|
222 | 1 | if (defined('JSON_UNESCAPED_UNICODE') && defined('JSON_UNESCAPED_SLASHES')) { |
|
223 | 1 | return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); |
|
224 | } |
||
225 | |||
226 | return json_encode($value); |
||
227 | } |
||
228 | |||
229 | 1 | if (is_object($value)) { |
|
230 | return sprintf('<%s>', get_class($value)); |
||
231 | } |
||
232 | |||
233 | 1 | if (is_scalar($value)) { |
|
234 | 1 | return $value; |
|
0 ignored issues
–
show
|
|||
235 | } |
||
236 | |||
237 | throw new \InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true))); |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Add the given label and value to the two column table output |
||
242 | * |
||
243 | * @param string $label Label for the value |
||
244 | * @param mixed $value A Value to show |
||
245 | * |
||
246 | * @return array |
||
247 | */ |
||
248 | 1 | private function formatField($label, $value) |
|
249 | { |
||
250 | 1 | if (null === $value) { |
|
251 | 1 | $value = '<comment>None</comment>'; |
|
252 | } |
||
253 | |||
254 | 1 | return [sprintf('<info>%s</info>', $label), $this->formatValue($value)]; |
|
255 | } |
||
256 | |||
257 | /** |
||
258 | * Format the association mappings |
||
259 | * |
||
260 | * @param array $propertyMappings |
||
261 | * |
||
262 | * @return array |
||
263 | */ |
||
264 | 1 | private function formatMappings(array $propertyMappings) |
|
265 | { |
||
266 | 1 | $output = []; |
|
267 | |||
268 | 1 | foreach ($propertyMappings as $propertyName => $mapping) { |
|
269 | 1 | $output[] = $this->formatField(sprintf(' %s', $propertyName), ''); |
|
270 | |||
271 | 1 | foreach ($mapping as $field => $value) { |
|
272 | 1 | $output[] = $this->formatField(sprintf(' %s', $field), $this->formatValue($value)); |
|
273 | } |
||
274 | } |
||
275 | |||
276 | 1 | return $output; |
|
277 | } |
||
278 | |||
279 | /** |
||
280 | * Format the entity listeners |
||
281 | * |
||
282 | * @param array $entityListeners |
||
283 | * |
||
284 | * @return array |
||
285 | */ |
||
286 | 1 | private function formatEntityListeners(array $entityListeners) |
|
287 | { |
||
288 | 1 | return $this->formatField( |
|
289 | 1 | 'Entity listeners', |
|
290 | 1 | array_map( |
|
291 | 1 | function ($entityListener) { |
|
292 | return get_class($entityListener); |
||
293 | 1 | }, |
|
294 | $entityListeners |
||
295 | ) |
||
296 | ); |
||
297 | } |
||
298 | } |
||
299 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: