1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SimpleEntityGeneratorBundle\Lib\Items; |
4
|
|
|
|
5
|
|
|
use Doctrine\Common\Collections\ArrayCollection; |
6
|
|
|
use Exception; |
7
|
|
|
use SimpleEntityGeneratorBundle\Lib\Interfaces\DumpableInterface; |
8
|
|
|
use SimpleEntityGeneratorBundle\Lib\Interfaces\MultilineCommentableInterface; |
9
|
|
|
use SimpleEntityGeneratorBundle\Lib\Interfaces\RenderableInterface; |
10
|
|
|
use SimpleEntityGeneratorBundle\Lib\Interfaces\StructureWithMethodsInterface; |
11
|
|
|
use SimpleEntityGeneratorBundle\Lib\Tools; |
12
|
|
|
use SimpleEntityGeneratorBundle\Lib\Traits\MultilineCommentTrait; |
13
|
|
|
use SimpleEntityGeneratorBundle\Lib\Traits\TemplateTrait; |
14
|
|
|
use JMS\Serializer\Annotation\SerializedName; |
15
|
|
|
use JMS\Serializer\Annotation\Type; |
16
|
|
|
use Symfony\Component\Validator\Constraints as Assert; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Manager of Class structure |
20
|
|
|
* |
21
|
|
|
* @author Sławomir Kania <[email protected]> |
22
|
|
|
*/ |
23
|
|
|
class ClassManager implements RenderableInterface, DumpableInterface, StructureWithMethodsInterface, MultilineCommentableInterface |
24
|
|
|
{ |
25
|
|
|
|
26
|
|
|
use MultilineCommentTrait; |
27
|
|
|
use TemplateTrait; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Collection of MethodManager |
31
|
|
|
* |
32
|
|
|
* @var ArrayCollection |
33
|
|
|
* @Assert\NotNull(message="Properties Collection can not be empty!") |
34
|
|
|
* @Assert\Valid() |
35
|
|
|
*/ |
36
|
|
|
private $methods = null; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Collection of PropertyManager |
40
|
|
|
* |
41
|
|
|
* @Type("Doctrine\Common\Collections\ArrayCollection<SimpleEntityGeneratorBundle\Lib\Items\PropertyManager>") |
42
|
|
|
* @Assert\NotNull(message="Properties Collection can not be empty!") |
43
|
|
|
* @Assert\Valid() |
44
|
|
|
*/ |
45
|
|
|
private $properties = null; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Interface namespace |
49
|
|
|
* |
50
|
|
|
* @var InterfaceManager |
51
|
|
|
* @Assert\Valid() |
52
|
|
|
*/ |
53
|
|
|
private $interface = null; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Class constructor |
57
|
|
|
* |
58
|
|
|
* @var ClassConstructorManager |
59
|
|
|
* @Assert\NotNull(message="Constructor can not be null!") |
60
|
|
|
* @Assert\Valid() |
61
|
|
|
*/ |
62
|
|
|
private $constructor = null; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Test Class |
66
|
|
|
* |
67
|
|
|
* @var TestClassManager |
68
|
|
|
* @Assert\Valid() |
69
|
|
|
* @var TestClassManager |
70
|
|
|
*/ |
71
|
|
|
private $testClass = null; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* namespace of class - class name is retrieved from namespace |
75
|
|
|
* |
76
|
|
|
* @Type("string") |
77
|
|
|
* @Assert\NotBlank(message="Namespace can not be blank!") |
78
|
|
|
*/ |
79
|
|
|
private $namespace = ""; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Comment under class |
83
|
|
|
* |
84
|
|
|
* @Type("string") |
85
|
|
|
*/ |
86
|
|
|
private $comment = ""; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Base class namespace |
90
|
|
|
* |
91
|
|
|
* @Type("string") |
92
|
|
|
*/ |
93
|
|
|
private $extends = ""; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @SerializedName("class_manager_template_path") |
97
|
|
|
* @Type("string") |
98
|
|
|
* @Assert\Type("string") |
99
|
|
|
*/ |
100
|
|
|
private $classManagerTemplatePath = ""; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* |
104
|
|
|
* @SerializedName("class_constructor_manager_template_path") |
105
|
|
|
* @Type("string") |
106
|
|
|
* @Assert\Type("string") |
107
|
|
|
*/ |
108
|
|
|
private $classConstructorManagerTemplatePath = ""; |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @SerializedName("interface_manager_template_path") |
112
|
|
|
* @Type("string") |
113
|
|
|
* @Assert\Type("string") |
114
|
|
|
*/ |
115
|
|
|
private $interfaceManagerTemplatePath = ""; |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* @SerializedName("test_class_manager_template_path") |
119
|
|
|
* @Type("string") |
120
|
|
|
* @Assert\Type("string") |
121
|
|
|
*/ |
122
|
|
|
private $testClassManagerTemplatePath = ""; |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @Type("SimpleEntityGeneratorBundle\Lib\ClassConfig") |
126
|
|
|
* @SerializedName("configuration") |
127
|
|
|
* @Assert\Valid() |
128
|
|
|
* @var \SimpleEntityGeneratorBundle\Lib\ClassConfig |
129
|
|
|
*/ |
130
|
|
|
private $configuration; |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @SerializedName("implements") |
134
|
|
|
* @Type("Doctrine\Common\Collections\ArrayCollection<string>") |
135
|
|
|
* @Assert\Type("Doctrine\Common\Collections\ArrayCollection") |
136
|
|
|
* @var ArrayCollection |
137
|
|
|
*/ |
138
|
|
|
private $implements; |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Construct |
142
|
|
|
*/ |
143
|
|
|
public function __construct() |
144
|
|
|
{ |
145
|
|
|
$this->properties = new ArrayCollection(); |
146
|
|
|
$this->methods = new ArrayCollection(); |
147
|
|
|
$this->implements = new ArrayCollection(); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @Assert\IsTrue(message = "Duplicated properties names in entity, check yaml schema!") |
152
|
|
|
* @return boolean |
153
|
|
|
*/ |
154
|
|
|
public function hasUniquePropertiesNames() |
155
|
|
|
{ |
156
|
|
|
$tmpPropertiesNames = []; |
157
|
|
|
foreach ($this->getProperties() as $property) { |
158
|
|
|
/* @var $property PropertyManager */ |
159
|
|
|
$propertyName = $property->getName(); |
160
|
|
|
if (in_array($propertyName, $tmpPropertiesNames)) { |
161
|
|
|
return false; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
$tmpPropertiesNames[] = $propertyName; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return true; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @Assert\IsTrue(message = "Invalid class namespace, check yaml schema! eg. \AppBundle\Vendor\Entity") |
172
|
|
|
* @return boolean |
173
|
|
|
*/ |
174
|
|
|
public function isValidNamespace() |
175
|
|
|
{ |
176
|
|
|
return Tools::isNamespaceValid($this->getNamespace()); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @Assert\IsTrue(message = "Invalid base class namespace, check yaml schema! eg. \AppBundle\Vendor\Entity") |
181
|
|
|
* @return boolean |
182
|
|
|
*/ |
183
|
|
|
public function isValidExtends() |
184
|
|
|
{ |
185
|
|
|
if (false === $this->hasExtends()) { |
186
|
|
|
return true; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
if (false === Tools::isFirstCharBackslash($this->getExtends())) { |
190
|
|
|
return false; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
if (class_exists($this->getExtends())) { |
194
|
|
|
return true; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
return Tools::isNamespaceValid($this->getNamespace()); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* @return ArrayCollection |
202
|
|
|
*/ |
203
|
|
|
public function getMethods() |
204
|
|
|
{ |
205
|
|
|
return $this->methods; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @param ArrayCollection $methods |
210
|
|
|
* @return InterfaceManager |
211
|
|
|
*/ |
212
|
|
|
public function setMethods(ArrayCollection $methods) |
213
|
|
|
{ |
214
|
|
|
$this->methods = $methods; |
215
|
|
|
return $this; |
|
|
|
|
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* @return ArrayCollection |
220
|
|
|
*/ |
221
|
|
|
public function getProperties() |
222
|
|
|
{ |
223
|
|
|
return $this->properties; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* @param ArrayCollection $properties |
228
|
|
|
* @return ClassManager |
229
|
|
|
*/ |
230
|
|
|
public function setProperties(ArrayCollection $properties) |
231
|
|
|
{ |
232
|
|
|
$this->properties = $properties; |
233
|
|
|
return $this; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @return InterfaceManager |
238
|
|
|
*/ |
239
|
|
|
public function getInterface() |
240
|
|
|
{ |
241
|
|
|
return $this->interface; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* @param InterfaceManager $interface |
246
|
|
|
* @return ClassManager |
247
|
|
|
*/ |
248
|
|
|
public function setInterface(InterfaceManager $interface) |
249
|
|
|
{ |
250
|
|
|
$this->interface = $interface; |
251
|
|
|
return $this; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* @return ClassConstructorManager |
256
|
|
|
*/ |
257
|
|
|
public function getConstructor() |
258
|
|
|
{ |
259
|
|
|
return $this->constructor; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* @param ClassConstructorManager $constructor |
264
|
|
|
* @return ClassManager |
265
|
|
|
*/ |
266
|
|
|
public function setConstructor(ClassConstructorManager $constructor) |
267
|
|
|
{ |
268
|
|
|
$this->constructor = $constructor; |
269
|
|
|
return $this; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* @return string |
274
|
|
|
*/ |
275
|
|
|
public function getComment() |
276
|
|
|
{ |
277
|
|
|
return $this->comment; |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* @param string |
282
|
|
|
* @return ClassManager |
283
|
|
|
*/ |
284
|
|
|
public function setComment($comment) |
285
|
|
|
{ |
286
|
|
|
$this->comment = $comment; |
287
|
|
|
return $this; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* @return TestClassManager |
292
|
|
|
*/ |
293
|
|
|
public function getTestClass() |
294
|
|
|
{ |
295
|
|
|
return $this->testClass; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* @param TestClassManager $testClass |
300
|
|
|
* @return ClassManager |
301
|
|
|
*/ |
302
|
|
|
public function setTestClass(TestClassManager $testClass) |
303
|
|
|
{ |
304
|
|
|
$this->testClass = $testClass; |
305
|
|
|
return $this; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* @return string |
310
|
|
|
*/ |
311
|
|
|
public function getNamespace() |
312
|
|
|
{ |
313
|
|
|
return $this->namespace; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* @param string $namespace |
318
|
|
|
* @return ClassManager |
319
|
|
|
*/ |
320
|
|
|
public function setNamespace($namespace) |
321
|
|
|
{ |
322
|
|
|
$this->namespace = $namespace; |
323
|
|
|
return $this; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Return base class namespace |
328
|
|
|
* |
329
|
|
|
* @return string |
330
|
|
|
*/ |
331
|
|
|
public function getExtends() |
332
|
|
|
{ |
333
|
|
|
return $this->extends; |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Set base class namespace |
338
|
|
|
* |
339
|
|
|
* @param string $extends |
340
|
|
|
*/ |
341
|
|
|
public function setExtends($extends) |
342
|
|
|
{ |
343
|
|
|
$this->extends = $extends; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* has set base class namespace |
348
|
|
|
* |
349
|
|
|
* @return boolean |
350
|
|
|
*/ |
351
|
|
|
public function hasExtends() |
352
|
|
|
{ |
353
|
|
|
return false === empty($this->getExtends()); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Check interface exists |
358
|
|
|
* |
359
|
|
|
* @return boolean |
360
|
|
|
*/ |
361
|
|
|
public function hasInterface() |
362
|
|
|
{ |
363
|
|
|
return $this->getInterface() instanceof InterfaceManager; |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Check interface exists |
368
|
|
|
* |
369
|
|
|
* @return boolean |
370
|
|
|
*/ |
371
|
|
|
public function hasTestClass() |
372
|
|
|
{ |
373
|
|
|
return $this->getTestClass() instanceof TestClassManager; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Return namespace without name - for createing directory |
378
|
|
|
* |
379
|
|
|
* @return string |
380
|
|
|
*/ |
381
|
|
|
public function getDirectory() |
382
|
|
|
{ |
383
|
|
|
return Tools::getDirectoryFromNamespace($this->getNamespace()); |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* Return name of class/interface from namespace |
388
|
|
|
* |
389
|
|
|
* @return string |
390
|
|
|
* @throws Exception |
391
|
|
|
*/ |
392
|
|
|
public function getName() |
393
|
|
|
{ |
394
|
|
|
return Tools::getNameFromNamespace($this->getNamespace()); |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Return namespace without name - for rendering namespace in class |
399
|
|
|
* |
400
|
|
|
* @return string |
401
|
|
|
* @throws Exception |
402
|
|
|
*/ |
403
|
|
|
public function getNamespaceWithoutName() |
404
|
|
|
{ |
405
|
|
|
return Tools::getNamespaceWithoutName($this->getNamespace()); |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Return namespace without name - for rendering namespace in class |
410
|
|
|
* |
411
|
|
|
* @return string |
412
|
|
|
* @throws Exception |
413
|
|
|
*/ |
414
|
|
|
public function getNamespaceWithoutNameAndBackslashPrefix() |
415
|
|
|
{ |
416
|
|
|
return Tools::removeBackslashPrefixFromNamespace(Tools::getNamespaceWithoutName($this->getNamespace())); |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
/** |
420
|
|
|
* Return set of tags used in template |
421
|
|
|
* |
422
|
|
|
* @return array |
423
|
|
|
*/ |
424
|
|
|
public function getTemplateTags() |
425
|
|
|
{ |
426
|
|
|
return [ |
427
|
|
|
self::TAG_NAMESPACE, |
428
|
|
|
self::TAG_COMMENT, |
429
|
|
|
self::TAG_NAME, |
430
|
|
|
self::TAG_EXTENDS, |
431
|
|
|
self::TAG_INTERFACE, |
432
|
|
|
self::TAG_CONSTRUCTOR, |
433
|
|
|
self::TAG_PROPERTIES, |
434
|
|
|
self::TAG_METHODS, |
435
|
|
|
self::TAG_MULTILINE_COMMENT, |
436
|
|
|
]; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* @return string |
441
|
|
|
*/ |
442
|
|
|
public function getClassManagerTemplatePath() |
443
|
|
|
{ |
444
|
|
|
return $this->classManagerTemplatePath; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* @return string |
449
|
|
|
*/ |
450
|
|
|
public function getClassConstructorManagerTemplatePath() |
451
|
|
|
{ |
452
|
|
|
return $this->classConstructorManagerTemplatePath; |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* @return string |
457
|
|
|
*/ |
458
|
|
|
public function getInterfaceManagerTemplatePath() |
459
|
|
|
{ |
460
|
|
|
return $this->interfaceManagerTemplatePath; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
/** |
464
|
|
|
* @return string |
465
|
|
|
*/ |
466
|
|
|
public function getTestClassManagerTemplatePath() |
467
|
|
|
{ |
468
|
|
|
return $this->testClassManagerTemplatePath; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* @param string $classManagerTemplatePath |
473
|
|
|
* @return $this |
474
|
|
|
*/ |
475
|
|
|
public function setClassManagerTemplatePath($classManagerTemplatePath) |
476
|
|
|
{ |
477
|
|
|
$this->classManagerTemplatePath = $classManagerTemplatePath; |
478
|
|
|
return $this; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* @param string $classConstructorManagerTemplatePath |
483
|
|
|
* @return $this |
484
|
|
|
*/ |
485
|
|
|
public function setClassConstructorManagerTemplatePath($classConstructorManagerTemplatePath) |
486
|
|
|
{ |
487
|
|
|
$this->classConstructorManagerTemplatePath = $classConstructorManagerTemplatePath; |
488
|
|
|
return $this; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
/** |
492
|
|
|
* @param string $interfaceManagerTemplatePath |
493
|
|
|
* @return $this |
494
|
|
|
*/ |
495
|
|
|
public function setInterfaceManagerTemplatePath($interfaceManagerTemplatePath) |
496
|
|
|
{ |
497
|
|
|
$this->interfaceManagerTemplatePath = $interfaceManagerTemplatePath; |
498
|
|
|
return $this; |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
/** |
502
|
|
|
* @param string $testClassManagerTemplatePath |
503
|
|
|
* @return $this |
504
|
|
|
*/ |
505
|
|
|
public function setTestClassManagerTemplatePath($testClassManagerTemplatePath) |
506
|
|
|
{ |
507
|
|
|
$this->testClassManagerTemplatePath = $testClassManagerTemplatePath; |
508
|
|
|
return $this; |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
/** |
512
|
|
|
* @return \SimpleEntityGeneratorBundle\Lib\ClassConfig |
513
|
|
|
*/ |
514
|
|
|
public function getConfiguration() |
515
|
|
|
{ |
516
|
|
|
return $this->configuration; |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
/** |
520
|
|
|
* @param \SimpleEntityGeneratorBundle\Lib\ClassConfig $configuration |
521
|
|
|
* @return \SimpleEntityGeneratorBundle\Lib\Items\ClassManager |
522
|
|
|
*/ |
523
|
|
|
public function setConfiguration(\SimpleEntityGeneratorBundle\Lib\ClassConfig $configuration) |
524
|
|
|
{ |
525
|
|
|
$this->configuration = $configuration; |
526
|
|
|
return $this; |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
/** |
530
|
|
|
* @return ArrayCollection |
531
|
|
|
*/ |
532
|
|
|
public function getImplements() |
533
|
|
|
{ |
534
|
|
|
// TODO is it possible to deserialize to empty ArrayCollection, when property no provided in yml file? |
535
|
|
|
if (is_null($this->implements)) { |
536
|
|
|
$this->implements = new ArrayCollection(); |
537
|
|
|
} |
538
|
|
|
return $this->implements; |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
/** |
542
|
|
|
* @param ArrayCollection $implements |
543
|
|
|
* @return ClassManager |
544
|
|
|
*/ |
545
|
|
|
public function setImplements(ArrayCollection $implements) |
546
|
|
|
{ |
547
|
|
|
$this->implements = $implements; |
548
|
|
|
return $this; |
549
|
|
|
} |
550
|
|
|
} |
551
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.