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; |
||
21 | |||
22 | use Doctrine\Common\Collections\Collection; |
||
23 | use Doctrine\Common\Util\Inflector; |
||
24 | use Doctrine\DBAL\Types\Type; |
||
25 | use Doctrine\ORM\Mapping\ClassMetadataInfo; |
||
26 | |||
27 | /** |
||
28 | * Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances. |
||
29 | * |
||
30 | * [php] |
||
31 | * $classes = $em->getClassMetadataFactory()->getAllMetadata(); |
||
32 | * |
||
33 | * $generator = new \Doctrine\ORM\Tools\EntityGenerator(); |
||
34 | * $generator->setGenerateAnnotations(true); |
||
35 | * $generator->setGenerateStubMethods(true); |
||
36 | * $generator->setRegenerateEntityIfExists(false); |
||
37 | * $generator->setUpdateEntityIfExists(true); |
||
38 | * $generator->generate($classes, '/path/to/generate/entities'); |
||
39 | * |
||
40 | * |
||
41 | * @link www.doctrine-project.org |
||
42 | * @since 2.0 |
||
43 | * @author Benjamin Eberlei <[email protected]> |
||
44 | * @author Guilherme Blanco <[email protected]> |
||
45 | * @author Jonathan Wage <[email protected]> |
||
46 | * @author Roman Borschel <[email protected]> |
||
47 | */ |
||
48 | class EntityGenerator |
||
49 | { |
||
50 | /** |
||
51 | * Specifies class fields should be protected. |
||
52 | */ |
||
53 | const FIELD_VISIBLE_PROTECTED = 'protected'; |
||
54 | |||
55 | /** |
||
56 | * Specifies class fields should be private. |
||
57 | */ |
||
58 | const FIELD_VISIBLE_PRIVATE = 'private'; |
||
59 | |||
60 | /** |
||
61 | * @var bool |
||
62 | */ |
||
63 | protected $backupExisting = true; |
||
64 | |||
65 | /** |
||
66 | * The extension to use for written php files. |
||
67 | * |
||
68 | * @var string |
||
69 | */ |
||
70 | protected $extension = '.php'; |
||
71 | |||
72 | /** |
||
73 | * Whether or not the current ClassMetadataInfo instance is new or old. |
||
74 | * |
||
75 | * @var boolean |
||
76 | */ |
||
77 | protected $isNew = true; |
||
78 | |||
79 | /** |
||
80 | * @var array |
||
81 | */ |
||
82 | protected $staticReflection = []; |
||
83 | |||
84 | /** |
||
85 | * Number of spaces to use for indention in generated code. |
||
86 | */ |
||
87 | protected $numSpaces = 4; |
||
88 | |||
89 | /** |
||
90 | * The actual spaces to use for indention. |
||
91 | * |
||
92 | * @var string |
||
93 | */ |
||
94 | protected $spaces = ' '; |
||
95 | |||
96 | /** |
||
97 | * The class all generated entities should extend. |
||
98 | * |
||
99 | * @var string |
||
100 | */ |
||
101 | protected $classToExtend; |
||
102 | |||
103 | /** |
||
104 | * Whether or not to generation annotations. |
||
105 | * |
||
106 | * @var boolean |
||
107 | */ |
||
108 | protected $generateAnnotations = false; |
||
109 | |||
110 | /** |
||
111 | * @var string |
||
112 | */ |
||
113 | protected $annotationsPrefix = ''; |
||
114 | |||
115 | /** |
||
116 | * Whether or not to generate sub methods. |
||
117 | * |
||
118 | * @var boolean |
||
119 | */ |
||
120 | protected $generateEntityStubMethods = false; |
||
121 | |||
122 | /** |
||
123 | * Whether or not to update the entity class if it exists already. |
||
124 | * |
||
125 | * @var boolean |
||
126 | */ |
||
127 | protected $updateEntityIfExists = false; |
||
128 | |||
129 | /** |
||
130 | * Whether or not to re-generate entity class if it exists already. |
||
131 | * |
||
132 | * @var boolean |
||
133 | */ |
||
134 | protected $regenerateEntityIfExists = false; |
||
135 | |||
136 | /** |
||
137 | * Visibility of the field |
||
138 | * |
||
139 | * @var string |
||
140 | */ |
||
141 | protected $fieldVisibility = 'private'; |
||
142 | |||
143 | /** |
||
144 | * Whether or not to make generated embeddables immutable. |
||
145 | * |
||
146 | * @var boolean. |
||
147 | */ |
||
148 | protected $embeddablesImmutable = false; |
||
149 | |||
150 | /** |
||
151 | * Hash-map for handle types. |
||
152 | * |
||
153 | * @var array |
||
154 | */ |
||
155 | protected $typeAlias = [ |
||
156 | Type::DATETIMETZ => '\DateTime', |
||
157 | Type::DATETIME => '\DateTime', |
||
158 | Type::DATE => '\DateTime', |
||
159 | Type::TIME => '\DateTime', |
||
160 | Type::OBJECT => '\stdClass', |
||
161 | Type::INTEGER => 'int', |
||
162 | Type::BIGINT => 'int', |
||
163 | Type::SMALLINT => 'int', |
||
164 | Type::TEXT => 'string', |
||
165 | Type::BLOB => 'string', |
||
166 | Type::DECIMAL => 'string', |
||
167 | Type::JSON_ARRAY => 'array', |
||
168 | Type::SIMPLE_ARRAY => 'array', |
||
169 | Type::BOOLEAN => 'bool', |
||
170 | ]; |
||
171 | |||
172 | /** |
||
173 | * Hash-map to handle generator types string. |
||
174 | * |
||
175 | * @var array |
||
176 | */ |
||
177 | protected static $generatorStrategyMap = [ |
||
178 | ClassMetadataInfo::GENERATOR_TYPE_AUTO => 'AUTO', |
||
179 | ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE => 'SEQUENCE', |
||
180 | ClassMetadataInfo::GENERATOR_TYPE_TABLE => 'TABLE', |
||
181 | ClassMetadataInfo::GENERATOR_TYPE_IDENTITY => 'IDENTITY', |
||
182 | ClassMetadataInfo::GENERATOR_TYPE_NONE => 'NONE', |
||
183 | ClassMetadataInfo::GENERATOR_TYPE_UUID => 'UUID', |
||
184 | ClassMetadataInfo::GENERATOR_TYPE_CUSTOM => 'CUSTOM' |
||
185 | ]; |
||
186 | |||
187 | /** |
||
188 | * Hash-map to handle the change tracking policy string. |
||
189 | * |
||
190 | * @var array |
||
191 | */ |
||
192 | protected static $changeTrackingPolicyMap = [ |
||
193 | ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT => 'DEFERRED_IMPLICIT', |
||
194 | ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT => 'DEFERRED_EXPLICIT', |
||
195 | ClassMetadataInfo::CHANGETRACKING_NOTIFY => 'NOTIFY', |
||
196 | ]; |
||
197 | |||
198 | /** |
||
199 | * Hash-map to handle the inheritance type string. |
||
200 | * |
||
201 | * @var array |
||
202 | */ |
||
203 | protected static $inheritanceTypeMap = [ |
||
204 | ClassMetadataInfo::INHERITANCE_TYPE_NONE => 'NONE', |
||
205 | ClassMetadataInfo::INHERITANCE_TYPE_JOINED => 'JOINED', |
||
206 | ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE => 'SINGLE_TABLE', |
||
207 | ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS => 'TABLE_PER_CLASS', |
||
208 | ]; |
||
209 | |||
210 | /** |
||
211 | * @var string |
||
212 | */ |
||
213 | protected static $classTemplate = |
||
214 | '<?php |
||
215 | |||
216 | <namespace> |
||
217 | <useStatement> |
||
218 | <entityAnnotation> |
||
219 | <entityClassName> |
||
220 | { |
||
221 | <entityBody> |
||
222 | } |
||
223 | '; |
||
224 | |||
225 | /** |
||
226 | * @var string |
||
227 | */ |
||
228 | protected static $getMethodTemplate = |
||
229 | '/** |
||
230 | * <description> |
||
231 | * |
||
232 | * @return <variableType> |
||
233 | */ |
||
234 | public function <methodName>() |
||
235 | { |
||
236 | <spaces>return $this-><fieldName>; |
||
237 | }'; |
||
238 | |||
239 | /** |
||
240 | * @var string |
||
241 | */ |
||
242 | protected static $setMethodTemplate = |
||
243 | '/** |
||
244 | * <description> |
||
245 | * |
||
246 | * @param <variableType> $<variableName> |
||
247 | * |
||
248 | * @return <entity> |
||
249 | */ |
||
250 | public function <methodName>(<methodTypeHint>$<variableName><variableDefault>) |
||
251 | { |
||
252 | <spaces>$this-><fieldName> = $<variableName>; |
||
253 | |||
254 | <spaces>return $this; |
||
255 | }'; |
||
256 | |||
257 | /** |
||
258 | * @var string |
||
259 | */ |
||
260 | protected static $addMethodTemplate = |
||
261 | '/** |
||
262 | * <description> |
||
263 | * |
||
264 | * @param <variableType> $<variableName> |
||
265 | * |
||
266 | * @return <entity> |
||
267 | */ |
||
268 | public function <methodName>(<methodTypeHint>$<variableName>) |
||
269 | { |
||
270 | <spaces>$this-><fieldName>[] = $<variableName>; |
||
271 | |||
272 | <spaces>return $this; |
||
273 | }'; |
||
274 | |||
275 | /** |
||
276 | * @var string |
||
277 | */ |
||
278 | protected static $removeMethodTemplate = |
||
279 | '/** |
||
280 | * <description> |
||
281 | * |
||
282 | * @param <variableType> $<variableName> |
||
283 | * |
||
284 | * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. |
||
285 | */ |
||
286 | public function <methodName>(<methodTypeHint>$<variableName>) |
||
287 | { |
||
288 | <spaces>return $this-><fieldName>->removeElement($<variableName>); |
||
289 | }'; |
||
290 | |||
291 | /** |
||
292 | * @var string |
||
293 | */ |
||
294 | protected static $lifecycleCallbackMethodTemplate = |
||
295 | '/** |
||
296 | * @<name> |
||
297 | */ |
||
298 | public function <methodName>() |
||
299 | { |
||
300 | <spaces>// Add your code here |
||
301 | }'; |
||
302 | |||
303 | /** |
||
304 | * @var string |
||
305 | */ |
||
306 | protected static $constructorMethodTemplate = |
||
307 | '/** |
||
308 | * Constructor |
||
309 | */ |
||
310 | public function __construct() |
||
311 | { |
||
312 | <spaces><collections> |
||
313 | } |
||
314 | '; |
||
315 | |||
316 | /** |
||
317 | * @var string |
||
318 | */ |
||
319 | protected static $embeddableConstructorMethodTemplate = |
||
320 | '/** |
||
321 | * Constructor |
||
322 | * |
||
323 | * <paramTags> |
||
324 | */ |
||
325 | public function __construct(<params>) |
||
326 | { |
||
327 | <spaces><fields> |
||
328 | } |
||
329 | '; |
||
330 | |||
331 | /** |
||
332 | * Constructor. |
||
333 | */ |
||
334 | 40 | public function __construct() |
|
335 | { |
||
336 | 40 | if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) { |
|
337 | 40 | $this->annotationsPrefix = 'ORM\\'; |
|
338 | } |
||
339 | 40 | } |
|
340 | |||
341 | /** |
||
342 | * Generates and writes entity classes for the given array of ClassMetadataInfo instances. |
||
343 | * |
||
344 | * @param array $metadatas |
||
345 | * @param string $outputDirectory |
||
346 | * |
||
347 | * @return void |
||
348 | */ |
||
349 | public function generate(array $metadatas, $outputDirectory) |
||
350 | { |
||
351 | foreach ($metadatas as $metadata) { |
||
352 | $this->writeEntityClass($metadata, $outputDirectory); |
||
353 | } |
||
354 | } |
||
355 | |||
356 | /** |
||
357 | * Generates and writes entity class to disk for the given ClassMetadataInfo instance. |
||
358 | * |
||
359 | * @param ClassMetadataInfo $metadata |
||
360 | * @param string $outputDirectory |
||
361 | * |
||
362 | * @return void |
||
363 | * |
||
364 | * @throws \RuntimeException |
||
365 | */ |
||
366 | 31 | public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory) |
|
367 | { |
||
368 | 31 | $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension; |
|
369 | 31 | $dir = dirname($path); |
|
370 | |||
371 | 31 | if ( ! is_dir($dir)) { |
|
372 | 2 | mkdir($dir, 0775, true); |
|
373 | } |
||
374 | |||
375 | 31 | $this->isNew = ! file_exists($path) || $this->regenerateEntityIfExists; |
|
376 | |||
377 | 31 | if ( ! $this->isNew) { |
|
378 | 3 | $this->parseTokensInEntityFile(file_get_contents($path)); |
|
379 | } else { |
||
380 | 30 | $this->staticReflection[$metadata->name] = ['properties' => [], 'methods' => []]; |
|
381 | } |
||
382 | |||
383 | 31 | if ($this->backupExisting && file_exists($path)) { |
|
384 | 3 | $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~"; |
|
385 | 3 | if (!copy($path, $backupPath)) { |
|
386 | throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed."); |
||
387 | } |
||
388 | } |
||
389 | |||
390 | // If entity doesn't exist or we're re-generating the entities entirely |
||
391 | 31 | if ($this->isNew) { |
|
392 | 30 | file_put_contents($path, $this->generateEntityClass($metadata)); |
|
393 | // If entity exists and we're allowed to update the entity class |
||
394 | 3 | } elseif ($this->updateEntityIfExists) { |
|
395 | 3 | file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path)); |
|
396 | } |
||
397 | 31 | chmod($path, 0664); |
|
398 | 31 | } |
|
399 | |||
400 | /** |
||
401 | * Generates a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance. |
||
402 | * |
||
403 | * @param ClassMetadataInfo $metadata |
||
404 | * |
||
405 | * @return string |
||
406 | */ |
||
407 | 31 | public function generateEntityClass(ClassMetadataInfo $metadata) |
|
408 | { |
||
409 | $placeHolders = [ |
||
410 | 31 | '<namespace>', |
|
411 | '<useStatement>', |
||
412 | '<entityAnnotation>', |
||
413 | '<entityClassName>', |
||
414 | '<entityBody>' |
||
415 | ]; |
||
416 | |||
417 | $replacements = [ |
||
418 | 31 | $this->generateEntityNamespace($metadata), |
|
419 | 31 | $this->generateEntityUse(), |
|
420 | 31 | $this->generateEntityDocBlock($metadata), |
|
421 | 31 | $this->generateEntityClassName($metadata), |
|
422 | 31 | $this->generateEntityBody($metadata) |
|
423 | ]; |
||
424 | |||
425 | 31 | $code = str_replace($placeHolders, $replacements, static::$classTemplate); |
|
426 | |||
427 | 31 | return str_replace('<spaces>', $this->spaces, $code); |
|
428 | } |
||
429 | |||
430 | /** |
||
431 | * Generates the updated code for the given ClassMetadataInfo and entity at path. |
||
432 | * |
||
433 | * @param ClassMetadataInfo $metadata |
||
434 | * @param string $path |
||
435 | * |
||
436 | * @return string |
||
437 | */ |
||
438 | 3 | public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path) |
|
439 | { |
||
440 | 3 | $currentCode = file_get_contents($path); |
|
441 | |||
442 | 3 | $body = $this->generateEntityBody($metadata); |
|
443 | 3 | $body = str_replace('<spaces>', $this->spaces, $body); |
|
444 | 3 | $last = strrpos($currentCode, '}'); |
|
445 | |||
446 | 3 | return substr($currentCode, 0, $last) . $body . ($body ? "\n" : '') . "}\n"; |
|
447 | } |
||
448 | |||
449 | /** |
||
450 | * Sets the number of spaces the exported class should have. |
||
451 | * |
||
452 | * @param integer $numSpaces |
||
453 | * |
||
454 | * @return void |
||
455 | */ |
||
456 | public function setNumSpaces($numSpaces) |
||
457 | { |
||
458 | $this->spaces = str_repeat(' ', $numSpaces); |
||
459 | $this->numSpaces = $numSpaces; |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Sets the extension to use when writing php files to disk. |
||
464 | * |
||
465 | * @param string $extension |
||
466 | * |
||
467 | * @return void |
||
468 | */ |
||
469 | public function setExtension($extension) |
||
470 | { |
||
471 | $this->extension = $extension; |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Sets the name of the class the generated classes should extend from. |
||
476 | * |
||
477 | * @param string $classToExtend |
||
478 | * |
||
479 | * @return void |
||
480 | */ |
||
481 | 1 | public function setClassToExtend($classToExtend) |
|
482 | { |
||
483 | 1 | $this->classToExtend = $classToExtend; |
|
484 | 1 | } |
|
485 | |||
486 | /** |
||
487 | * Sets whether or not to generate annotations for the entity. |
||
488 | * |
||
489 | * @param bool $bool |
||
490 | * |
||
491 | * @return void |
||
492 | */ |
||
493 | 40 | public function setGenerateAnnotations($bool) |
|
494 | { |
||
495 | 40 | $this->generateAnnotations = $bool; |
|
496 | 40 | } |
|
497 | |||
498 | /** |
||
499 | * Sets the class fields visibility for the entity (can either be private or protected). |
||
500 | * |
||
501 | * @param bool $visibility |
||
502 | * |
||
503 | * @return void |
||
504 | * |
||
505 | * @throws \InvalidArgumentException |
||
506 | */ |
||
507 | 39 | public function setFieldVisibility($visibility) |
|
508 | { |
||
509 | 39 | if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) { |
|
510 | throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility); |
||
511 | } |
||
512 | |||
513 | 39 | $this->fieldVisibility = $visibility; |
|
514 | 39 | } |
|
515 | |||
516 | /** |
||
517 | * Sets whether or not to generate immutable embeddables. |
||
518 | * |
||
519 | * @param boolean $embeddablesImmutable |
||
520 | */ |
||
521 | 1 | public function setEmbeddablesImmutable($embeddablesImmutable) |
|
522 | { |
||
523 | 1 | $this->embeddablesImmutable = (boolean) $embeddablesImmutable; |
|
524 | 1 | } |
|
525 | |||
526 | /** |
||
527 | * Sets an annotation prefix. |
||
528 | * |
||
529 | * @param string $prefix |
||
530 | * |
||
531 | * @return void |
||
532 | */ |
||
533 | 40 | public function setAnnotationPrefix($prefix) |
|
534 | { |
||
535 | 40 | $this->annotationsPrefix = $prefix; |
|
536 | 40 | } |
|
537 | |||
538 | /** |
||
539 | * Sets whether or not to try and update the entity if it already exists. |
||
540 | * |
||
541 | * @param bool $bool |
||
542 | * |
||
543 | * @return void |
||
544 | */ |
||
545 | 40 | public function setUpdateEntityIfExists($bool) |
|
546 | { |
||
547 | 40 | $this->updateEntityIfExists = $bool; |
|
548 | 40 | } |
|
549 | |||
550 | /** |
||
551 | * Sets whether or not to regenerate the entity if it exists. |
||
552 | * |
||
553 | * @param bool $bool |
||
554 | * |
||
555 | * @return void |
||
556 | */ |
||
557 | 40 | public function setRegenerateEntityIfExists($bool) |
|
558 | { |
||
559 | 40 | $this->regenerateEntityIfExists = $bool; |
|
560 | 40 | } |
|
561 | |||
562 | /** |
||
563 | * Sets whether or not to generate stub methods for the entity. |
||
564 | * |
||
565 | * @param bool $bool |
||
566 | * |
||
567 | * @return void |
||
568 | */ |
||
569 | 40 | public function setGenerateStubMethods($bool) |
|
570 | { |
||
571 | 40 | $this->generateEntityStubMethods = $bool; |
|
572 | 40 | } |
|
573 | |||
574 | /** |
||
575 | * Should an existing entity be backed up if it already exists? |
||
576 | * |
||
577 | * @param bool $bool |
||
578 | * |
||
579 | * @return void |
||
580 | */ |
||
581 | 1 | public function setBackupExisting($bool) |
|
582 | { |
||
583 | 1 | $this->backupExisting = $bool; |
|
584 | 1 | } |
|
585 | |||
586 | /** |
||
587 | * @param string $type |
||
588 | * |
||
589 | * @return string |
||
590 | */ |
||
591 | 31 | protected function getType($type) |
|
592 | { |
||
593 | 31 | if (isset($this->typeAlias[$type])) { |
|
594 | 30 | return $this->typeAlias[$type]; |
|
595 | } |
||
596 | |||
597 | 20 | return $type; |
|
598 | } |
||
599 | |||
600 | /** |
||
601 | * @param ClassMetadataInfo $metadata |
||
602 | * |
||
603 | * @return string |
||
604 | */ |
||
605 | 31 | protected function generateEntityNamespace(ClassMetadataInfo $metadata) |
|
606 | { |
||
607 | 31 | if (! $this->hasNamespace($metadata)) { |
|
608 | 2 | return ''; |
|
609 | } |
||
610 | |||
611 | 31 | return 'namespace ' . $this->getNamespace($metadata) .';'; |
|
612 | } |
||
613 | |||
614 | /** |
||
615 | * @return string |
||
616 | */ |
||
617 | 31 | protected function generateEntityUse() |
|
618 | { |
||
619 | 31 | if (! $this->generateAnnotations) { |
|
620 | return ''; |
||
621 | } |
||
622 | |||
623 | 31 | return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n"; |
|
624 | } |
||
625 | |||
626 | /** |
||
627 | * @param ClassMetadataInfo $metadata |
||
628 | * |
||
629 | * @return string |
||
630 | */ |
||
631 | 31 | protected function generateEntityClassName(ClassMetadataInfo $metadata) |
|
632 | { |
||
633 | 31 | return 'class ' . $this->getClassName($metadata) . |
|
634 | 31 | ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null); |
|
635 | } |
||
636 | |||
637 | /** |
||
638 | * @param ClassMetadataInfo $metadata |
||
639 | * |
||
640 | * @return string |
||
641 | */ |
||
642 | 32 | protected function generateEntityBody(ClassMetadataInfo $metadata) |
|
643 | { |
||
644 | 32 | $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata); |
|
645 | 32 | $embeddedProperties = $this->generateEntityEmbeddedProperties($metadata); |
|
646 | 32 | $associationMappingProperties = $this->generateEntityAssociationMappingProperties($metadata); |
|
647 | 32 | $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods($metadata) : null; |
|
648 | 32 | $lifecycleCallbackMethods = $this->generateEntityLifecycleCallbackMethods($metadata); |
|
649 | |||
650 | 32 | $code = []; |
|
651 | |||
652 | 32 | if ($fieldMappingProperties) { |
|
653 | 29 | $code[] = $fieldMappingProperties; |
|
654 | } |
||
655 | |||
656 | 32 | if ($embeddedProperties) { |
|
657 | 10 | $code[] = $embeddedProperties; |
|
658 | } |
||
659 | |||
660 | 32 | if ($associationMappingProperties) { |
|
661 | 11 | $code[] = $associationMappingProperties; |
|
662 | } |
||
663 | |||
664 | 32 | $code[] = $this->generateEntityConstructor($metadata); |
|
665 | |||
666 | 32 | if ($stubMethods) { |
|
667 | 30 | $code[] = $stubMethods; |
|
668 | } |
||
669 | |||
670 | 32 | if ($lifecycleCallbackMethods) { |
|
671 | 10 | $code[] = $lifecycleCallbackMethods; |
|
672 | } |
||
673 | |||
674 | 32 | return implode("\n", $code); |
|
675 | } |
||
676 | |||
677 | /** |
||
678 | * @param ClassMetadataInfo $metadata |
||
679 | * |
||
680 | * @return string |
||
681 | */ |
||
682 | 32 | protected function generateEntityConstructor(ClassMetadataInfo $metadata) |
|
683 | { |
||
684 | 32 | if ($this->hasMethod('__construct', $metadata)) { |
|
685 | 2 | return ''; |
|
686 | } |
||
687 | |||
688 | 32 | if ($metadata->isEmbeddedClass && $this->embeddablesImmutable) { |
|
689 | 1 | return $this->generateEmbeddableConstructor($metadata); |
|
690 | } |
||
691 | |||
692 | 31 | $collections = []; |
|
693 | |||
694 | 31 | foreach ($metadata->associationMappings as $mapping) { |
|
695 | 13 | if ($mapping['type'] & ClassMetadataInfo::TO_MANY) { |
|
696 | 13 | $collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();'; |
|
697 | } |
||
698 | } |
||
699 | |||
700 | 31 | if ($collections) { |
|
701 | 11 | return $this->prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->spaces, $collections), static::$constructorMethodTemplate)); |
|
702 | } |
||
703 | |||
704 | 27 | return ''; |
|
705 | } |
||
706 | |||
707 | /** |
||
708 | * @param ClassMetadataInfo $metadata |
||
709 | * |
||
710 | * @return string |
||
711 | */ |
||
712 | 1 | private function generateEmbeddableConstructor(ClassMetadataInfo $metadata) |
|
713 | { |
||
714 | 1 | $paramTypes = []; |
|
715 | 1 | $paramVariables = []; |
|
716 | 1 | $params = []; |
|
717 | 1 | $fields = []; |
|
718 | |||
719 | // Resort fields to put optional fields at the end of the method signature. |
||
720 | 1 | $requiredFields = []; |
|
721 | 1 | $optionalFields = []; |
|
722 | |||
723 | 1 | foreach ($metadata->fieldMappings as $fieldMapping) { |
|
724 | 1 | if (empty($fieldMapping['nullable'])) { |
|
725 | 1 | $requiredFields[] = $fieldMapping; |
|
726 | |||
727 | 1 | continue; |
|
728 | } |
||
729 | |||
730 | 1 | $optionalFields[] = $fieldMapping; |
|
731 | } |
||
732 | |||
733 | 1 | $fieldMappings = array_merge($requiredFields, $optionalFields); |
|
734 | |||
735 | 1 | foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) { |
|
736 | 1 | $paramType = '\\' . ltrim($embeddedClass['class'], '\\'); |
|
737 | 1 | $paramVariable = '$' . $fieldName; |
|
738 | |||
739 | 1 | $paramTypes[] = $paramType; |
|
740 | 1 | $paramVariables[] = $paramVariable; |
|
741 | 1 | $params[] = $paramType . ' ' . $paramVariable; |
|
742 | 1 | $fields[] = '$this->' . $fieldName . ' = ' . $paramVariable . ';'; |
|
743 | } |
||
744 | |||
745 | 1 | foreach ($fieldMappings as $fieldMapping) { |
|
746 | 1 | if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']])) { |
|
747 | continue; |
||
748 | } |
||
749 | |||
750 | 1 | $paramTypes[] = $this->getType($fieldMapping['type']) . (!empty($fieldMapping['nullable']) ? '|null' : ''); |
|
751 | 1 | $param = '$' . $fieldMapping['fieldName']; |
|
752 | 1 | $paramVariables[] = $param; |
|
753 | |||
754 | 1 | if ($fieldMapping['type'] === 'datetime') { |
|
755 | 1 | $param = $this->getType($fieldMapping['type']) . ' ' . $param; |
|
756 | } |
||
757 | |||
758 | 1 | if (!empty($fieldMapping['nullable'])) { |
|
759 | 1 | $param .= ' = null'; |
|
760 | } |
||
761 | |||
762 | 1 | $params[] = $param; |
|
763 | |||
764 | 1 | $fields[] = '$this->' . $fieldMapping['fieldName'] . ' = $' . $fieldMapping['fieldName'] . ';'; |
|
765 | } |
||
766 | |||
767 | 1 | $maxParamTypeLength = max(array_map('strlen', $paramTypes)); |
|
768 | 1 | $paramTags = array_map( |
|
769 | 1 | function ($type, $variable) use ($maxParamTypeLength) { |
|
770 | 1 | return '@param ' . $type . str_repeat(' ', $maxParamTypeLength - strlen($type) + 1) . $variable; |
|
771 | 1 | }, |
|
772 | 1 | $paramTypes, |
|
773 | 1 | $paramVariables |
|
774 | ); |
||
775 | |||
776 | // Generate multi line constructor if the signature exceeds 120 characters. |
||
777 | 1 | if (array_sum(array_map('strlen', $params)) + count($params) * 2 + 29 > 120) { |
|
778 | 1 | $delimiter = "\n" . $this->spaces; |
|
779 | 1 | $params = $delimiter . implode(',' . $delimiter, $params) . "\n"; |
|
780 | } else { |
||
781 | 1 | $params = implode(', ', $params); |
|
782 | } |
||
783 | |||
784 | $replacements = [ |
||
785 | 1 | '<paramTags>' => implode("\n * ", $paramTags), |
|
786 | 1 | '<params>' => $params, |
|
787 | 1 | '<fields>' => implode("\n" . $this->spaces, $fields), |
|
788 | ]; |
||
789 | |||
790 | 1 | $constructor = str_replace( |
|
791 | 1 | array_keys($replacements), |
|
792 | 1 | array_values($replacements), |
|
793 | 1 | static::$embeddableConstructorMethodTemplate |
|
794 | ); |
||
795 | |||
796 | 1 | return $this->prefixCodeWithSpaces($constructor); |
|
797 | } |
||
798 | |||
799 | /** |
||
800 | * @todo this won't work if there is a namespace in brackets and a class outside of it. |
||
801 | * |
||
802 | * @param string $src |
||
803 | * |
||
804 | * @return void |
||
805 | */ |
||
806 | 8 | protected function parseTokensInEntityFile($src) |
|
807 | { |
||
808 | 8 | $tokens = token_get_all($src); |
|
809 | 8 | $tokensCount = count($tokens); |
|
810 | 8 | $lastSeenNamespace = ''; |
|
811 | 8 | $lastSeenClass = false; |
|
812 | |||
813 | 8 | $inNamespace = false; |
|
814 | 8 | $inClass = false; |
|
815 | |||
816 | 8 | for ($i = 0; $i < $tokensCount; $i++) { |
|
817 | 8 | $token = $tokens[$i]; |
|
818 | 8 | if (in_array($token[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) { |
|
819 | 8 | continue; |
|
820 | } |
||
821 | |||
822 | 8 | if ($inNamespace) { |
|
823 | 8 | if (in_array($token[0], [T_NS_SEPARATOR, T_STRING], true)) { |
|
824 | 8 | $lastSeenNamespace .= $token[1]; |
|
825 | 8 | } elseif (is_string($token) && in_array($token, [';', '{'], true)) { |
|
826 | 8 | $inNamespace = false; |
|
827 | } |
||
828 | } |
||
829 | |||
830 | 8 | if ($inClass) { |
|
831 | 8 | $inClass = false; |
|
832 | 8 | $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1]; |
|
833 | 8 | $this->staticReflection[$lastSeenClass]['properties'] = []; |
|
834 | 8 | $this->staticReflection[$lastSeenClass]['methods'] = []; |
|
835 | } |
||
836 | |||
837 | 8 | if (T_NAMESPACE === $token[0]) { |
|
838 | 8 | $lastSeenNamespace = ''; |
|
839 | 8 | $inNamespace = true; |
|
840 | 8 | } elseif (T_CLASS === $token[0] && T_DOUBLE_COLON !== $tokens[$i-1][0]) { |
|
841 | 8 | $inClass = true; |
|
842 | 8 | } elseif (T_FUNCTION === $token[0]) { |
|
843 | 3 | if (T_STRING === $tokens[$i+2][0]) { |
|
844 | 3 | $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]); |
|
845 | } elseif ($tokens[$i+2] == '&' && T_STRING === $tokens[$i+3][0]) { |
||
846 | 3 | $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]); |
|
847 | } |
||
848 | 8 | } elseif (in_array($token[0], [T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED], true) && T_FUNCTION !== $tokens[$i+2][0]) { |
|
849 | 4 | $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1); |
|
850 | } |
||
851 | } |
||
852 | 8 | } |
|
853 | |||
854 | /** |
||
855 | * @param string $property |
||
856 | * @param ClassMetadataInfo $metadata |
||
857 | * |
||
858 | * @return bool |
||
859 | */ |
||
860 | 31 | View Code Duplication | protected function hasProperty($property, ClassMetadataInfo $metadata) |
861 | { |
||
862 | 31 | if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) { |
|
863 | // don't generate property if its already on the base class. |
||
864 | 2 | $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); |
|
865 | 2 | if ($reflClass->hasProperty($property)) { |
|
866 | 1 | return true; |
|
867 | } |
||
868 | } |
||
869 | |||
870 | // check traits for existing property |
||
871 | 30 | foreach ($this->getTraits($metadata) as $trait) { |
|
872 | 2 | if ($trait->hasProperty($property)) { |
|
873 | 2 | return true; |
|
874 | } |
||
875 | } |
||
876 | |||
877 | return ( |
||
878 | 30 | isset($this->staticReflection[$metadata->name]) && |
|
879 | 30 | in_array($property, $this->staticReflection[$metadata->name]['properties'], true) |
|
880 | ); |
||
881 | } |
||
882 | |||
883 | /** |
||
884 | * @param string $method |
||
885 | * @param ClassMetadataInfo $metadata |
||
886 | * |
||
887 | * @return bool |
||
888 | */ |
||
889 | 32 | View Code Duplication | protected function hasMethod($method, ClassMetadataInfo $metadata) |
890 | { |
||
891 | 32 | if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) { |
|
892 | // don't generate method if its already on the base class. |
||
893 | 2 | $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); |
|
894 | |||
895 | 2 | if ($reflClass->hasMethod($method)) { |
|
896 | 1 | return true; |
|
897 | } |
||
898 | } |
||
899 | |||
900 | // check traits for existing method |
||
901 | 32 | foreach ($this->getTraits($metadata) as $trait) { |
|
902 | 2 | if ($trait->hasMethod($method)) { |
|
903 | 2 | return true; |
|
904 | } |
||
905 | } |
||
906 | |||
907 | return ( |
||
908 | 32 | isset($this->staticReflection[$metadata->name]) && |
|
909 | 32 | in_array(strtolower($method), $this->staticReflection[$metadata->name]['methods'], true) |
|
910 | ); |
||
911 | } |
||
912 | |||
913 | /** |
||
914 | * @param ClassMetadataInfo $metadata |
||
915 | * |
||
916 | * @return array |
||
917 | * |
||
918 | * @throws \ReflectionException |
||
919 | */ |
||
920 | 32 | protected function getTraits(ClassMetadataInfo $metadata) |
|
921 | { |
||
922 | 32 | if (! ($metadata->reflClass !== null || class_exists($metadata->name))) { |
|
923 | 26 | return []; |
|
924 | } |
||
925 | |||
926 | 7 | $reflClass = $metadata->reflClass ?? new \ReflectionClass($metadata->name); |
|
927 | |||
928 | 7 | $traits = []; |
|
929 | |||
930 | 7 | while ($reflClass !== false) { |
|
931 | 7 | $traits = array_merge($traits, $reflClass->getTraits()); |
|
932 | |||
933 | 7 | $reflClass = $reflClass->getParentClass(); |
|
934 | } |
||
935 | |||
936 | 7 | return $traits; |
|
937 | } |
||
938 | |||
939 | /** |
||
940 | * @param ClassMetadataInfo $metadata |
||
941 | * |
||
942 | * @return bool |
||
943 | */ |
||
944 | 31 | protected function hasNamespace(ClassMetadataInfo $metadata) |
|
945 | { |
||
946 | 31 | return (bool) strpos($metadata->name, '\\'); |
|
947 | } |
||
948 | |||
949 | /** |
||
950 | * @return bool |
||
951 | */ |
||
952 | 32 | protected function extendsClass() |
|
953 | { |
||
954 | 32 | return (bool) $this->classToExtend; |
|
955 | } |
||
956 | |||
957 | /** |
||
958 | * @return string |
||
959 | */ |
||
960 | 2 | protected function getClassToExtend() |
|
961 | { |
||
962 | 2 | return $this->classToExtend; |
|
963 | } |
||
964 | |||
965 | /** |
||
966 | * @return string |
||
967 | */ |
||
968 | 1 | protected function getClassToExtendName() |
|
969 | { |
||
970 | 1 | $refl = new \ReflectionClass($this->getClassToExtend()); |
|
971 | |||
972 | 1 | return '\\' . $refl->getName(); |
|
973 | } |
||
974 | |||
975 | /** |
||
976 | * @param ClassMetadataInfo $metadata |
||
977 | * |
||
978 | * @return string |
||
979 | */ |
||
980 | 32 | protected function getClassName(ClassMetadataInfo $metadata) |
|
981 | { |
||
982 | 32 | return ($pos = strrpos($metadata->name, '\\')) |
|
983 | 32 | ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name; |
|
984 | } |
||
985 | |||
986 | /** |
||
987 | * @param ClassMetadataInfo $metadata |
||
988 | * |
||
989 | * @return string |
||
990 | */ |
||
991 | 31 | protected function getNamespace(ClassMetadataInfo $metadata) |
|
992 | { |
||
993 | 31 | return substr($metadata->name, 0, strrpos($metadata->name, '\\')); |
|
994 | } |
||
995 | |||
996 | /** |
||
997 | * @param ClassMetadataInfo $metadata |
||
998 | * |
||
999 | * @return string |
||
1000 | */ |
||
1001 | 31 | protected function generateEntityDocBlock(ClassMetadataInfo $metadata) |
|
1002 | { |
||
1003 | 31 | $lines = []; |
|
1004 | 31 | $lines[] = '/**'; |
|
1005 | 31 | $lines[] = ' * ' . $this->getClassName($metadata); |
|
1006 | |||
1007 | 31 | if ($this->generateAnnotations) { |
|
1008 | 31 | $lines[] = ' *'; |
|
1009 | |||
1010 | $methods = [ |
||
1011 | 31 | 'generateTableAnnotation', |
|
1012 | 'generateInheritanceAnnotation', |
||
1013 | 'generateDiscriminatorColumnAnnotation', |
||
1014 | 'generateDiscriminatorMapAnnotation', |
||
1015 | 'generateEntityAnnotation', |
||
1016 | 'generateEntityListenerAnnotation', |
||
1017 | ]; |
||
1018 | |||
1019 | 31 | foreach ($methods as $method) { |
|
1020 | 31 | if ($code = $this->$method($metadata)) { |
|
1021 | 31 | $lines[] = ' * ' . $code; |
|
1022 | } |
||
1023 | } |
||
1024 | |||
1025 | 31 | if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) { |
|
1026 | 10 | $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks'; |
|
1027 | } |
||
1028 | } |
||
1029 | |||
1030 | 31 | $lines[] = ' */'; |
|
1031 | |||
1032 | 31 | return implode("\n", $lines); |
|
1033 | } |
||
1034 | |||
1035 | /** |
||
1036 | * @param ClassMetadataInfo $metadata |
||
1037 | * |
||
1038 | * @return string |
||
1039 | */ |
||
1040 | 31 | protected function generateEntityAnnotation(ClassMetadataInfo $metadata) |
|
1041 | { |
||
1042 | 31 | $prefix = '@' . $this->annotationsPrefix; |
|
1043 | |||
1044 | 31 | if ($metadata->isEmbeddedClass) { |
|
1045 | 11 | return $prefix . 'Embeddable'; |
|
1046 | } |
||
1047 | |||
1048 | 27 | $customRepository = $metadata->customRepositoryClassName |
|
1049 | 11 | ? '(repositoryClass="' . $metadata->customRepositoryClassName . '")' |
|
1050 | 27 | : ''; |
|
1051 | |||
1052 | 27 | return $prefix . ($metadata->isMappedSuperclass ? 'MappedSuperclass' : 'Entity') . $customRepository; |
|
1053 | } |
||
1054 | |||
1055 | /** |
||
1056 | * @param ClassMetadataInfo $metadata |
||
1057 | * |
||
1058 | * @return string |
||
1059 | */ |
||
1060 | 31 | protected function generateTableAnnotation(ClassMetadataInfo $metadata) |
|
1061 | { |
||
1062 | 31 | if ($metadata->isEmbeddedClass) { |
|
1063 | 11 | return ''; |
|
1064 | } |
||
1065 | |||
1066 | 27 | $table = []; |
|
1067 | |||
1068 | 27 | View Code Duplication | if (isset($metadata->table['schema'])) { |
1069 | $table[] = 'schema="' . $metadata->table['schema'] . '"'; |
||
1070 | } |
||
1071 | |||
1072 | 27 | View Code Duplication | if (isset($metadata->table['name'])) { |
1073 | 24 | $table[] = 'name="' . $metadata->table['name'] . '"'; |
|
1074 | } |
||
1075 | |||
1076 | 27 | if (isset($metadata->table['options']) && $metadata->table['options']) { |
|
1077 | 1 | $table[] = 'options={' . $this->exportTableOptions((array) $metadata->table['options']) . '}'; |
|
1078 | } |
||
1079 | |||
1080 | 27 | View Code Duplication | if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) { |
1081 | 9 | $constraints = $this->generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']); |
|
1082 | 9 | $table[] = 'uniqueConstraints={' . $constraints . '}'; |
|
1083 | } |
||
1084 | |||
1085 | 27 | View Code Duplication | if (isset($metadata->table['indexes']) && $metadata->table['indexes']) { |
1086 | 9 | $constraints = $this->generateTableConstraints('Index', $metadata->table['indexes']); |
|
1087 | 9 | $table[] = 'indexes={' . $constraints . '}'; |
|
1088 | } |
||
1089 | |||
1090 | 27 | return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')'; |
|
1091 | } |
||
1092 | |||
1093 | /** |
||
1094 | * @param string $constraintName |
||
1095 | * @param array $constraints |
||
1096 | * |
||
1097 | * @return string |
||
1098 | */ |
||
1099 | 9 | protected function generateTableConstraints($constraintName, array $constraints) |
|
1100 | { |
||
1101 | 9 | $annotations = []; |
|
1102 | 9 | foreach ($constraints as $name => $constraint) { |
|
1103 | 9 | $columns = []; |
|
1104 | 9 | foreach ($constraint['columns'] as $column) { |
|
1105 | 9 | $columns[] = '"' . $column . '"'; |
|
1106 | } |
||
1107 | 9 | $annotations[] = '@' . $this->annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})'; |
|
1108 | } |
||
1109 | |||
1110 | 9 | return implode(', ', $annotations); |
|
1111 | } |
||
1112 | |||
1113 | /** |
||
1114 | * @param ClassMetadataInfo $metadata |
||
1115 | * |
||
1116 | * @return string |
||
1117 | */ |
||
1118 | 31 | protected function generateInheritanceAnnotation(ClassMetadataInfo $metadata) |
|
1119 | { |
||
1120 | 31 | if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { |
|
1121 | 31 | return ''; |
|
1122 | } |
||
1123 | |||
1124 | return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")'; |
||
1125 | } |
||
1126 | |||
1127 | /** |
||
1128 | * @param ClassMetadataInfo $metadata |
||
1129 | * |
||
1130 | * @return string |
||
1131 | */ |
||
1132 | 31 | protected function generateDiscriminatorColumnAnnotation(ClassMetadataInfo $metadata) |
|
1133 | { |
||
1134 | 31 | if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { |
|
1135 | 31 | return ''; |
|
1136 | } |
||
1137 | |||
1138 | $discrColumn = $metadata->discriminatorColumn; |
||
1139 | $columnDefinition = 'name="' . $discrColumn['name'] |
||
1140 | . '", type="' . $discrColumn['type'] |
||
1141 | . '", length=' . $discrColumn['length']; |
||
1142 | |||
1143 | return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')'; |
||
1144 | } |
||
1145 | |||
1146 | /** |
||
1147 | * @param ClassMetadataInfo $metadata |
||
1148 | * |
||
1149 | * @return string |
||
1150 | */ |
||
1151 | 31 | protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata) |
|
1152 | { |
||
1153 | 31 | if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { |
|
1154 | 31 | return null; |
|
1155 | } |
||
1156 | |||
1157 | $inheritanceClassMap = []; |
||
1158 | |||
1159 | foreach ($metadata->discriminatorMap as $type => $class) { |
||
1160 | $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"'; |
||
1161 | } |
||
1162 | |||
1163 | return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})'; |
||
1164 | } |
||
1165 | |||
1166 | /** |
||
1167 | * @param ClassMetadataInfo $metadata |
||
1168 | * |
||
1169 | * @return string |
||
1170 | */ |
||
1171 | 31 | protected function generateEntityStubMethods(ClassMetadataInfo $metadata) |
|
1172 | { |
||
1173 | 31 | $methods = []; |
|
1174 | |||
1175 | 31 | foreach ($metadata->fieldMappings as $fieldMapping) { |
|
1176 | 30 | if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']])) { |
|
1177 | continue; |
||
1178 | } |
||
1179 | |||
1180 | 30 | $nullableField = $this->nullableFieldExpression($fieldMapping); |
|
1181 | |||
1182 | 30 | if ((!$metadata->isEmbeddedClass || !$this->embeddablesImmutable) |
|
1183 | 30 | && (!isset($fieldMapping['id']) || ! $fieldMapping['id'] || $metadata->generatorType === ClassMetadataInfo::GENERATOR_TYPE_NONE) |
|
1184 | 30 | && $code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'], $nullableField) |
|
1185 | ) { |
||
1186 | 27 | $methods[] = $code; |
|
1187 | } |
||
1188 | |||
1189 | 30 | if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'], $nullableField)) { |
|
1190 | 30 | $methods[] = $code; |
|
1191 | } |
||
1192 | } |
||
1193 | |||
1194 | 31 | foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) { |
|
1195 | 10 | if (isset($embeddedClass['declaredField'])) { |
|
1196 | 1 | continue; |
|
1197 | } |
||
1198 | |||
1199 | 10 | if ( ! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable) { |
|
1200 | 9 | if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldName, $embeddedClass['class'])) { |
|
1201 | 9 | $methods[] = $code; |
|
1202 | } |
||
1203 | } |
||
1204 | |||
1205 | 10 | if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldName, $embeddedClass['class'])) { |
|
1206 | 10 | $methods[] = $code; |
|
1207 | } |
||
1208 | } |
||
1209 | |||
1210 | 31 | foreach ($metadata->associationMappings as $associationMapping) { |
|
1211 | 12 | if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { |
|
1212 | 11 | $nullable = $this->isAssociationIsNullable($associationMapping) ? 'null' : null; |
|
1213 | 11 | if ($code = $this->generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) { |
|
1214 | 9 | $methods[] = $code; |
|
1215 | } |
||
1216 | 11 | if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) { |
|
1217 | 11 | $methods[] = $code; |
|
1218 | } |
||
1219 | 10 | } elseif ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) { |
|
1220 | 10 | View Code Duplication | if ($code = $this->generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { |
1221 | 10 | $methods[] = $code; |
|
1222 | } |
||
1223 | 10 | View Code Duplication | if ($code = $this->generateEntityStubMethod($metadata, 'remove', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { |
1224 | 10 | $methods[] = $code; |
|
1225 | } |
||
1226 | 10 | View Code Duplication | if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], Collection::class)) { |
1227 | 12 | $methods[] = $code; |
|
1228 | } |
||
1229 | } |
||
1230 | } |
||
1231 | |||
1232 | 31 | return implode("\n\n", $methods); |
|
1233 | } |
||
1234 | |||
1235 | /** |
||
1236 | * @param array $associationMapping |
||
1237 | * |
||
1238 | * @return bool |
||
1239 | */ |
||
1240 | 11 | protected function isAssociationIsNullable(array $associationMapping) |
|
1241 | { |
||
1242 | 11 | if (isset($associationMapping['id']) && $associationMapping['id']) { |
|
1243 | return false; |
||
1244 | } |
||
1245 | |||
1246 | 11 | if (isset($associationMapping['joinColumns'])) { |
|
1247 | 2 | $joinColumns = $associationMapping['joinColumns']; |
|
1248 | } else { |
||
1249 | //@todo there is no way to retrieve targetEntity metadata |
||
1250 | 9 | $joinColumns = []; |
|
1251 | } |
||
1252 | |||
1253 | 11 | foreach ($joinColumns as $joinColumn) { |
|
1254 | 2 | if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) { |
|
1255 | 2 | return false; |
|
1256 | } |
||
1257 | } |
||
1258 | |||
1259 | 11 | return true; |
|
1260 | } |
||
1261 | |||
1262 | /** |
||
1263 | * @param ClassMetadataInfo $metadata |
||
1264 | * |
||
1265 | * @return string |
||
1266 | */ |
||
1267 | 32 | protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata) |
|
1268 | { |
||
1269 | 32 | if (empty($metadata->lifecycleCallbacks)) { |
|
1270 | 29 | return ''; |
|
1271 | } |
||
1272 | |||
1273 | 10 | $methods = []; |
|
1274 | |||
1275 | 10 | foreach ($metadata->lifecycleCallbacks as $name => $callbacks) { |
|
1276 | 10 | foreach ($callbacks as $callback) { |
|
1277 | 10 | $methods[] = $this->generateLifecycleCallbackMethod($name, $callback, $metadata); |
|
1278 | } |
||
1279 | } |
||
1280 | |||
1281 | 10 | return implode("\n\n", array_filter($methods)); |
|
1282 | } |
||
1283 | |||
1284 | /** |
||
1285 | * @param ClassMetadataInfo $metadata |
||
1286 | * |
||
1287 | * @return string |
||
1288 | */ |
||
1289 | 32 | protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata) |
|
1290 | { |
||
1291 | 32 | $lines = []; |
|
1292 | |||
1293 | 32 | foreach ($metadata->associationMappings as $associationMapping) { |
|
1294 | 13 | if ($this->hasProperty($associationMapping['fieldName'], $metadata)) { |
|
1295 | 4 | continue; |
|
1296 | } |
||
1297 | |||
1298 | 11 | $lines[] = $this->generateAssociationMappingPropertyDocBlock($associationMapping, $metadata); |
|
1299 | 11 | $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $associationMapping['fieldName'] |
|
1300 | 11 | . ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n"; |
|
1301 | } |
||
1302 | |||
1303 | 32 | return implode("\n", $lines); |
|
1304 | } |
||
1305 | |||
1306 | /** |
||
1307 | * @param ClassMetadataInfo $metadata |
||
1308 | * |
||
1309 | * @return string |
||
1310 | */ |
||
1311 | 32 | protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata) |
|
1312 | { |
||
1313 | 32 | $lines = []; |
|
1314 | |||
1315 | 32 | foreach ($metadata->fieldMappings as $fieldMapping) { |
|
1316 | 31 | if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']]) || |
|
1317 | 31 | $this->hasProperty($fieldMapping['fieldName'], $metadata) || |
|
1318 | 31 | $metadata->isInheritedField($fieldMapping['fieldName']) |
|
1319 | ) { |
||
1320 | 4 | continue; |
|
1321 | } |
||
1322 | |||
1323 | 29 | $lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata); |
|
1324 | 29 | $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName'] |
|
1325 | 29 | . (isset($fieldMapping['options']['default']) ? ' = ' . var_export($fieldMapping['options']['default'], true) : null) . ";\n"; |
|
1326 | } |
||
1327 | |||
1328 | 32 | return implode("\n", $lines); |
|
1329 | } |
||
1330 | |||
1331 | /** |
||
1332 | * @param ClassMetadataInfo $metadata |
||
1333 | * |
||
1334 | * @return string |
||
1335 | */ |
||
1336 | 32 | protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata) |
|
1337 | { |
||
1338 | 32 | $lines = []; |
|
1339 | |||
1340 | 32 | foreach ($metadata->embeddedClasses as $fieldName => $embeddedClass) { |
|
1341 | 10 | if (isset($embeddedClass['declaredField']) || $this->hasProperty($fieldName, $metadata)) { |
|
1342 | 2 | continue; |
|
1343 | } |
||
1344 | |||
1345 | 10 | $lines[] = $this->generateEmbeddedPropertyDocBlock($embeddedClass); |
|
1346 | 10 | $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldName . ";\n"; |
|
1347 | } |
||
1348 | |||
1349 | 32 | return implode("\n", $lines); |
|
1350 | } |
||
1351 | |||
1352 | /** |
||
1353 | * @param ClassMetadataInfo $metadata |
||
1354 | * @param string $type |
||
1355 | * @param string $fieldName |
||
1356 | * @param string|null $typeHint |
||
1357 | * @param string|null $defaultValue |
||
1358 | * |
||
1359 | * @return string |
||
1360 | */ |
||
1361 | 30 | protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null) |
|
1362 | { |
||
1363 | 30 | $methodName = $type . Inflector::classify($fieldName); |
|
1364 | 30 | $variableName = Inflector::camelize($fieldName); |
|
1365 | 30 | if (in_array($type, ["add", "remove"])) { |
|
1366 | 10 | $methodName = Inflector::singularize($methodName); |
|
1367 | 10 | $variableName = Inflector::singularize($variableName); |
|
1368 | } |
||
1369 | |||
1370 | 30 | if ($this->hasMethod($methodName, $metadata)) { |
|
1371 | 5 | return ''; |
|
1372 | } |
||
1373 | 30 | $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName); |
|
1374 | |||
1375 | 30 | $var = sprintf('%sMethodTemplate', $type); |
|
1376 | 30 | $template = static::$$var; |
|
1377 | |||
1378 | 30 | $methodTypeHint = null; |
|
1379 | 30 | $types = Type::getTypesMap(); |
|
1380 | 30 | $variableType = $typeHint ? $this->getType($typeHint) : null; |
|
1381 | |||
1382 | 30 | if ($typeHint && ! isset($types[$typeHint])) { |
|
1383 | 14 | $variableType = '\\' . ltrim($variableType, '\\'); |
|
1384 | 14 | $methodTypeHint = '\\' . $typeHint . ' '; |
|
1385 | } |
||
1386 | |||
1387 | $replacements = [ |
||
1388 | 30 | '<description>' => ucfirst($type) . ' ' . $variableName . '.', |
|
1389 | 30 | '<methodTypeHint>' => $methodTypeHint, |
|
1390 | 30 | '<variableType>' => $variableType . (null !== $defaultValue ? ('|' . $defaultValue) : ''), |
|
1391 | 30 | '<variableName>' => $variableName, |
|
1392 | 30 | '<methodName>' => $methodName, |
|
1393 | 30 | '<fieldName>' => $fieldName, |
|
1394 | 30 | '<variableDefault>' => ($defaultValue !== null ) ? (' = ' . $defaultValue) : '', |
|
1395 | 30 | '<entity>' => $this->getClassName($metadata) |
|
1396 | ]; |
||
1397 | |||
1398 | 30 | $method = str_replace( |
|
1399 | 30 | array_keys($replacements), |
|
1400 | 30 | array_values($replacements), |
|
1401 | 30 | $template |
|
1402 | ); |
||
1403 | |||
1404 | 30 | return $this->prefixCodeWithSpaces($method); |
|
1405 | } |
||
1406 | |||
1407 | /** |
||
1408 | * @param string $name |
||
1409 | * @param string $methodName |
||
1410 | * @param ClassMetadataInfo $metadata |
||
1411 | * |
||
1412 | * @return string |
||
1413 | */ |
||
1414 | 10 | protected function generateLifecycleCallbackMethod($name, $methodName, ClassMetadataInfo $metadata) |
|
1415 | { |
||
1416 | 10 | if ($this->hasMethod($methodName, $metadata)) { |
|
1417 | 2 | return ''; |
|
1418 | } |
||
1419 | |||
1420 | 10 | $this->staticReflection[$metadata->name]['methods'][] = $methodName; |
|
1421 | |||
1422 | $replacements = [ |
||
1423 | 10 | '<name>' => $this->annotationsPrefix . ucfirst($name), |
|
1424 | 10 | '<methodName>' => $methodName, |
|
1425 | ]; |
||
1426 | |||
1427 | 10 | $method = str_replace( |
|
1428 | 10 | array_keys($replacements), |
|
1429 | 10 | array_values($replacements), |
|
1430 | 10 | static::$lifecycleCallbackMethodTemplate |
|
1431 | ); |
||
1432 | |||
1433 | 10 | return $this->prefixCodeWithSpaces($method); |
|
1434 | } |
||
1435 | |||
1436 | /** |
||
1437 | * @param array $joinColumn |
||
1438 | * |
||
1439 | * @return string |
||
1440 | */ |
||
1441 | 11 | protected function generateJoinColumnAnnotation(array $joinColumn) |
|
1442 | { |
||
1443 | 11 | $joinColumnAnnot = []; |
|
1444 | |||
1445 | 11 | if (isset($joinColumn['name'])) { |
|
1446 | 11 | $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"'; |
|
1447 | } |
||
1448 | |||
1449 | 11 | if (isset($joinColumn['referencedColumnName'])) { |
|
1450 | 11 | $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"'; |
|
1451 | } |
||
1452 | |||
1453 | 11 | if (isset($joinColumn['unique']) && $joinColumn['unique']) { |
|
1454 | 1 | $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false'); |
|
1455 | } |
||
1456 | |||
1457 | 11 | if (isset($joinColumn['nullable'])) { |
|
1458 | 1 | $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false'); |
|
1459 | } |
||
1460 | |||
1461 | 11 | if (isset($joinColumn['onDelete'])) { |
|
1462 | 1 | $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"'); |
|
1463 | } |
||
1464 | |||
1465 | 11 | if (isset($joinColumn['columnDefinition'])) { |
|
1466 | 1 | $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"'; |
|
1467 | } |
||
1468 | |||
1469 | 11 | return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')'; |
|
1470 | } |
||
1471 | |||
1472 | /** |
||
1473 | * @param array $associationMapping |
||
1474 | * @param ClassMetadataInfo $metadata |
||
1475 | * |
||
1476 | * @return string |
||
1477 | */ |
||
1478 | 11 | protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata) |
|
1479 | { |
||
1480 | 11 | $lines = []; |
|
1481 | 11 | $lines[] = $this->spaces . '/**'; |
|
1482 | |||
1483 | 11 | if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) { |
|
1484 | 11 | $lines[] = $this->spaces . ' * @var \Doctrine\Common\Collections\Collection'; |
|
1485 | } else { |
||
1486 | 10 | $lines[] = $this->spaces . ' * @var \\' . ltrim($associationMapping['targetEntity'], '\\'); |
|
1487 | } |
||
1488 | |||
1489 | 11 | if ($this->generateAnnotations) { |
|
1490 | 11 | $lines[] = $this->spaces . ' *'; |
|
1491 | |||
1492 | 11 | if (isset($associationMapping['id']) && $associationMapping['id']) { |
|
1493 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id'; |
||
1494 | |||
1495 | View Code Duplication | if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) { |
|
1496 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")'; |
||
1497 | } |
||
1498 | } |
||
1499 | |||
1500 | 11 | $type = null; |
|
1501 | 11 | switch ($associationMapping['type']) { |
|
1502 | 11 | case ClassMetadataInfo::ONE_TO_ONE: |
|
0 ignored issues
–
show
|
|||
1503 | 10 | $type = 'OneToOne'; |
|
1504 | 10 | break; |
|
1505 | 11 | case ClassMetadataInfo::MANY_TO_ONE: |
|
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.
Loading history...
|
|||
1506 | 1 | $type = 'ManyToOne'; |
|
1507 | 1 | break; |
|
1508 | 11 | case ClassMetadataInfo::ONE_TO_MANY: |
|
1509 | 1 | $type = 'OneToMany'; |
|
1510 | 1 | break; |
|
1511 | 11 | case ClassMetadataInfo::MANY_TO_MANY: |
|
1512 | 11 | $type = 'ManyToMany'; |
|
1513 | 11 | break; |
|
1514 | } |
||
1515 | 11 | $typeOptions = []; |
|
1516 | |||
1517 | 11 | if (isset($associationMapping['targetEntity'])) { |
|
1518 | 11 | $typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"'; |
|
1519 | } |
||
1520 | |||
1521 | 11 | if (isset($associationMapping['inversedBy'])) { |
|
1522 | 1 | $typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"'; |
|
1523 | } |
||
1524 | |||
1525 | 11 | if (isset($associationMapping['mappedBy'])) { |
|
1526 | 10 | $typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"'; |
|
1527 | } |
||
1528 | |||
1529 | 11 | if ($associationMapping['cascade']) { |
|
1530 | 1 | $cascades = []; |
|
1531 | |||
1532 | 1 | if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"'; |
|
1533 | 1 | if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"'; |
|
1534 | 1 | if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"'; |
|
1535 | 1 | if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"'; |
|
1536 | 1 | if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"'; |
|
1537 | |||
1538 | 1 | if (count($cascades) === 5) { |
|
1539 | 1 | $cascades = ['"all"']; |
|
1540 | } |
||
1541 | |||
1542 | 1 | $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}'; |
|
1543 | } |
||
1544 | |||
1545 | 11 | if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) { |
|
1546 | 1 | $typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false'); |
|
1547 | } |
||
1548 | |||
1549 | 11 | if (isset($associationMapping['fetch']) && $associationMapping['fetch'] !== ClassMetadataInfo::FETCH_LAZY) { |
|
1550 | $fetchMap = [ |
||
1551 | 10 | ClassMetadataInfo::FETCH_EXTRA_LAZY => 'EXTRA_LAZY', |
|
1552 | ClassMetadataInfo::FETCH_EAGER => 'EAGER', |
||
1553 | ]; |
||
1554 | |||
1555 | 10 | $typeOptions[] = 'fetch="' . $fetchMap[$associationMapping['fetch']] . '"'; |
|
1556 | } |
||
1557 | |||
1558 | 11 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')'; |
|
1559 | |||
1560 | 11 | if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) { |
|
1561 | 1 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinColumns({'; |
|
1562 | |||
1563 | 1 | $joinColumnsLines = []; |
|
1564 | |||
1565 | 1 | View Code Duplication | foreach ($associationMapping['joinColumns'] as $joinColumn) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
1566 | 1 | if ($joinColumnAnnot = $this->generateJoinColumnAnnotation($joinColumn)) { |
|
1567 | 1 | $joinColumnsLines[] = $this->spaces . ' * ' . $joinColumnAnnot; |
|
1568 | } |
||
1569 | } |
||
1570 | |||
1571 | 1 | $lines[] = implode(",\n", $joinColumnsLines); |
|
1572 | 1 | $lines[] = $this->spaces . ' * })'; |
|
1573 | } |
||
1574 | |||
1575 | 11 | if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) { |
|
1576 | 11 | $joinTable = []; |
|
1577 | 11 | $joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"'; |
|
1578 | |||
1579 | 11 | if (isset($associationMapping['joinTable']['schema'])) { |
|
1580 | $joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"'; |
||
1581 | } |
||
1582 | |||
1583 | 11 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ','; |
|
1584 | 11 | $lines[] = $this->spaces . ' * joinColumns={'; |
|
1585 | |||
1586 | 11 | $joinColumnsLines = []; |
|
1587 | |||
1588 | 11 | View Code Duplication | foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
1589 | 11 | $joinColumnsLines[] = $this->spaces . ' * ' . $this->generateJoinColumnAnnotation($joinColumn); |
|
1590 | } |
||
1591 | |||
1592 | 11 | $lines[] = implode(",". PHP_EOL, $joinColumnsLines); |
|
1593 | 11 | $lines[] = $this->spaces . ' * },'; |
|
1594 | 11 | $lines[] = $this->spaces . ' * inverseJoinColumns={'; |
|
1595 | |||
1596 | 11 | $inverseJoinColumnsLines = []; |
|
1597 | |||
1598 | 11 | foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) { |
|
1599 | 11 | $inverseJoinColumnsLines[] = $this->spaces . ' * ' . $this->generateJoinColumnAnnotation($joinColumn); |
|
1600 | } |
||
1601 | |||
1602 | 11 | $lines[] = implode(",". PHP_EOL, $inverseJoinColumnsLines); |
|
1603 | 11 | $lines[] = $this->spaces . ' * }'; |
|
1604 | 11 | $lines[] = $this->spaces . ' * )'; |
|
1605 | } |
||
1606 | |||
1607 | 11 | if (isset($associationMapping['orderBy'])) { |
|
1608 | 1 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'OrderBy({'; |
|
1609 | |||
1610 | 1 | foreach ($associationMapping['orderBy'] as $name => $direction) { |
|
1611 | 1 | $lines[] = $this->spaces . ' * "' . $name . '"="' . $direction . '",'; |
|
1612 | } |
||
1613 | |||
1614 | 1 | $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1); |
|
1615 | 1 | $lines[] = $this->spaces . ' * })'; |
|
1616 | } |
||
1617 | } |
||
1618 | |||
1619 | 11 | $lines[] = $this->spaces . ' */'; |
|
1620 | |||
1621 | 11 | return implode("\n", $lines); |
|
1622 | } |
||
1623 | |||
1624 | /** |
||
1625 | * @param array $fieldMapping |
||
1626 | * @param ClassMetadataInfo $metadata |
||
1627 | * |
||
1628 | * @return string |
||
1629 | */ |
||
1630 | 29 | protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata) |
|
1631 | { |
||
1632 | 29 | $lines = []; |
|
1633 | 29 | $lines[] = $this->spaces . '/**'; |
|
1634 | 29 | $lines[] = $this->spaces . ' * @var ' |
|
1635 | 29 | . $this->getType($fieldMapping['type']) |
|
1636 | 29 | . ($this->nullableFieldExpression($fieldMapping) ? '|null' : ''); |
|
1637 | |||
1638 | 29 | if ($this->generateAnnotations) { |
|
1639 | 29 | $lines[] = $this->spaces . ' *'; |
|
1640 | |||
1641 | 29 | $column = []; |
|
1642 | 29 | if (isset($fieldMapping['columnName'])) { |
|
1643 | 29 | $column[] = 'name="' . $fieldMapping['columnName'] . '"'; |
|
1644 | } |
||
1645 | |||
1646 | 29 | if (isset($fieldMapping['type'])) { |
|
1647 | 29 | $column[] = 'type="' . $fieldMapping['type'] . '"'; |
|
1648 | } |
||
1649 | |||
1650 | 29 | if (isset($fieldMapping['length'])) { |
|
1651 | 4 | $column[] = 'length=' . $fieldMapping['length']; |
|
1652 | } |
||
1653 | |||
1654 | 29 | if (isset($fieldMapping['precision'])) { |
|
1655 | 4 | $column[] = 'precision=' . $fieldMapping['precision']; |
|
1656 | } |
||
1657 | |||
1658 | 29 | if (isset($fieldMapping['scale'])) { |
|
1659 | 4 | $column[] = 'scale=' . $fieldMapping['scale']; |
|
1660 | } |
||
1661 | |||
1662 | 29 | View Code Duplication | if (isset($fieldMapping['nullable'])) { |
1663 | 10 | $column[] = 'nullable=' . var_export($fieldMapping['nullable'], true); |
|
1664 | } |
||
1665 | |||
1666 | 29 | $options = []; |
|
1667 | |||
1668 | 29 | if (isset($fieldMapping['options']['unsigned']) && $fieldMapping['options']['unsigned']) { |
|
1669 | 1 | $options[] = '"unsigned"=true'; |
|
1670 | } |
||
1671 | |||
1672 | 29 | if ($options) { |
|
1673 | 1 | $column[] = 'options={'.implode(',', $options).'}'; |
|
1674 | } |
||
1675 | |||
1676 | 29 | if (isset($fieldMapping['columnDefinition'])) { |
|
1677 | 1 | $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"'; |
|
1678 | } |
||
1679 | |||
1680 | 29 | View Code Duplication | if (isset($fieldMapping['unique'])) { |
1681 | 4 | $column[] = 'unique=' . var_export($fieldMapping['unique'], true); |
|
1682 | } |
||
1683 | |||
1684 | 29 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Column(' . implode(', ', $column) . ')'; |
|
1685 | |||
1686 | 29 | if (isset($fieldMapping['id']) && $fieldMapping['id']) { |
|
1687 | 25 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id'; |
|
1688 | |||
1689 | 25 | View Code Duplication | if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) { |
1690 | 25 | $lines[] = $this->spaces.' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")'; |
|
1691 | } |
||
1692 | |||
1693 | 25 | if ($metadata->sequenceGeneratorDefinition) { |
|
1694 | 1 | $sequenceGenerator = []; |
|
1695 | |||
1696 | 1 | if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) { |
|
1697 | 1 | $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"'; |
|
1698 | } |
||
1699 | |||
1700 | 1 | if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) { |
|
1701 | 1 | $sequenceGenerator[] = 'allocationSize=' . $metadata->sequenceGeneratorDefinition['allocationSize']; |
|
1702 | } |
||
1703 | |||
1704 | 1 | if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) { |
|
1705 | 1 | $sequenceGenerator[] = 'initialValue=' . $metadata->sequenceGeneratorDefinition['initialValue']; |
|
1706 | } |
||
1707 | |||
1708 | 1 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')'; |
|
1709 | } |
||
1710 | } |
||
1711 | |||
1712 | 29 | if (isset($fieldMapping['version']) && $fieldMapping['version']) { |
|
1713 | $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Version'; |
||
1714 | } |
||
1715 | } |
||
1716 | |||
1717 | 29 | $lines[] = $this->spaces . ' */'; |
|
1718 | |||
1719 | 29 | return implode("\n", $lines); |
|
1720 | } |
||
1721 | |||
1722 | /** |
||
1723 | * @param array $embeddedClass |
||
1724 | * |
||
1725 | * @return string |
||
1726 | */ |
||
1727 | 10 | protected function generateEmbeddedPropertyDocBlock(array $embeddedClass) |
|
1728 | { |
||
1729 | 10 | $lines = []; |
|
1730 | 10 | $lines[] = $this->spaces . '/**'; |
|
1731 | 10 | $lines[] = $this->spaces . ' * @var \\' . ltrim($embeddedClass['class'], '\\'); |
|
1732 | |||
1733 | 10 | if ($this->generateAnnotations) { |
|
1734 | 10 | $lines[] = $this->spaces . ' *'; |
|
1735 | |||
1736 | 10 | $embedded = ['class="' . $embeddedClass['class'] . '"']; |
|
1737 | |||
1738 | 10 | if (isset($embeddedClass['columnPrefix'])) { |
|
1739 | 8 | if (is_string($embeddedClass['columnPrefix'])) { |
|
1740 | 1 | $embedded[] = 'columnPrefix="' . $embeddedClass['columnPrefix'] . '"'; |
|
1741 | } else { |
||
1742 | 7 | $embedded[] = 'columnPrefix=' . var_export($embeddedClass['columnPrefix'], true); |
|
1743 | } |
||
1744 | } |
||
1745 | |||
1746 | 10 | $lines[] = $this->spaces . ' * @' . |
|
1747 | 10 | $this->annotationsPrefix . 'Embedded(' . implode(', ', $embedded) . ')'; |
|
1748 | } |
||
1749 | |||
1750 | 10 | $lines[] = $this->spaces . ' */'; |
|
1751 | |||
1752 | 10 | return implode("\n", $lines); |
|
1753 | } |
||
1754 | |||
1755 | 31 | private function generateEntityListenerAnnotation(ClassMetadataInfo $metadata): string |
|
1756 | { |
||
1757 | 31 | if (0 === \count($metadata->entityListeners)) { |
|
1758 | 30 | return ''; |
|
1759 | } |
||
1760 | |||
1761 | 1 | $processedClasses = []; |
|
1762 | 1 | foreach ($metadata->entityListeners as $event => $eventListeners) { |
|
1763 | 1 | foreach ($eventListeners as $eventListener) { |
|
1764 | 1 | $processedClasses[] = '"' . $eventListener['class'] . '"'; |
|
1765 | } |
||
1766 | } |
||
1767 | |||
1768 | 1 | return \sprintf( |
|
1769 | 1 | '%s%s({%s})', |
|
1770 | 1 | '@' . $this->annotationsPrefix, |
|
1771 | 1 | 'EntityListeners', |
|
1772 | 1 | \implode(',', \array_unique($processedClasses)) |
|
1773 | ); |
||
1774 | } |
||
1775 | |||
1776 | /** |
||
1777 | * @param string $code |
||
1778 | * @param int $num |
||
1779 | * |
||
1780 | * @return string |
||
1781 | */ |
||
1782 | 31 | protected function prefixCodeWithSpaces($code, $num = 1) |
|
1783 | { |
||
1784 | 31 | $lines = explode("\n", $code); |
|
1785 | |||
1786 | 31 | foreach ($lines as $key => $value) { |
|
1787 | 31 | if ( ! empty($value)) { |
|
1788 | 31 | $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key]; |
|
1789 | } |
||
1790 | } |
||
1791 | |||
1792 | 31 | return implode("\n", $lines); |
|
1793 | } |
||
1794 | |||
1795 | /** |
||
1796 | * @param integer $type The inheritance type used by the class and its subclasses. |
||
1797 | * |
||
1798 | * @return string The literal string for the inheritance type. |
||
1799 | * |
||
1800 | * @throws \InvalidArgumentException When the inheritance type does not exist. |
||
1801 | */ |
||
1802 | 1 | protected function getInheritanceTypeString($type) |
|
1803 | { |
||
1804 | 1 | if ( ! isset(static::$inheritanceTypeMap[$type])) { |
|
1805 | 1 | throw new \InvalidArgumentException(sprintf('Invalid provided InheritanceType: %s', $type)); |
|
1806 | } |
||
1807 | |||
1808 | 1 | return static::$inheritanceTypeMap[$type]; |
|
1809 | } |
||
1810 | |||
1811 | /** |
||
1812 | * @param integer $type The policy used for change-tracking for the mapped class. |
||
1813 | * |
||
1814 | * @return string The literal string for the change-tracking type. |
||
1815 | * |
||
1816 | * @throws \InvalidArgumentException When the change-tracking type does not exist. |
||
1817 | */ |
||
1818 | 1 | protected function getChangeTrackingPolicyString($type) |
|
1819 | { |
||
1820 | 1 | if ( ! isset(static::$changeTrackingPolicyMap[$type])) { |
|
1821 | 1 | throw new \InvalidArgumentException(sprintf('Invalid provided ChangeTrackingPolicy: %s', $type)); |
|
1822 | } |
||
1823 | |||
1824 | 1 | return static::$changeTrackingPolicyMap[$type]; |
|
1825 | } |
||
1826 | |||
1827 | /** |
||
1828 | * @param integer $type The generator to use for the mapped class. |
||
1829 | * |
||
1830 | * @return string The literal string for the generator type. |
||
1831 | * |
||
1832 | * @throws \InvalidArgumentException When the generator type does not exist. |
||
1833 | */ |
||
1834 | 26 | protected function getIdGeneratorTypeString($type) |
|
1835 | { |
||
1836 | 26 | if ( ! isset(static::$generatorStrategyMap[$type])) { |
|
1837 | 1 | throw new \InvalidArgumentException(sprintf('Invalid provided IdGeneratorType: %s', $type)); |
|
1838 | } |
||
1839 | |||
1840 | 26 | return static::$generatorStrategyMap[$type]; |
|
1841 | } |
||
1842 | |||
1843 | /** |
||
1844 | * @param array $fieldMapping |
||
1845 | * |
||
1846 | * @return string|null |
||
1847 | */ |
||
1848 | 31 | private function nullableFieldExpression(array $fieldMapping) |
|
1849 | { |
||
1850 | 31 | if (isset($fieldMapping['nullable']) && true === $fieldMapping['nullable']) { |
|
1851 | 7 | return 'null'; |
|
1852 | } |
||
1853 | |||
1854 | 31 | return null; |
|
1855 | } |
||
1856 | |||
1857 | /** |
||
1858 | * Exports (nested) option elements. |
||
1859 | * |
||
1860 | * @param array $options |
||
1861 | * |
||
1862 | * @return string |
||
1863 | */ |
||
1864 | 1 | private function exportTableOptions(array $options) |
|
1865 | { |
||
1866 | 1 | $optionsStr = []; |
|
1867 | |||
1868 | 1 | foreach ($options as $name => $option) { |
|
1869 | 1 | if (is_array($option)) { |
|
1870 | 1 | $optionsStr[] = '"' . $name . '"={' . $this->exportTableOptions($option) . '}'; |
|
1871 | } else { |
||
1872 | 1 | $optionsStr[] = '"' . $name . '"="' . (string) $option . '"'; |
|
1873 | } |
||
1874 | } |
||
1875 | |||
1876 | 1 | return implode(',', $optionsStr); |
|
1877 | } |
||
1878 | } |
||
1879 |
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.