Passed
Pull Request — master (#29)
by Sébastien
08:57
created

EntityGenerator::generateEntityNamespace()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0625
1
<?php
0 ignored issues
show
introduced by
The PHP open tag must be followed by exactly one blank line
Loading history...
2
/*
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
introduced by
Namespaced classes, interfaces and traits should not begin with a file doc comment
Loading history...
Coding Style introduced by
Empty line required before block comment
Loading history...
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 Bdf\Prime\Entity;
21
22
use Bdf\Prime\Mapper\Info\InfoInterface;
23
use Bdf\Prime\Mapper\Info\ObjectPropertyInfo;
24
use Bdf\Prime\Mapper\Info\PropertyInfo;
25
use Bdf\Prime\Mapper\Mapper;
26
use Bdf\Prime\Mapper\Info\MapperInfo;
27
use Bdf\Prime\ServiceLocator;
28
use Bdf\Prime\Types\PhpTypeInterface;
29
use Bdf\Prime\Types\TypeInterface;
30
use Doctrine\Common\Inflector\Inflector;
31
use Doctrine\Inflector\Inflector as InflectorObject;
32
use Doctrine\Inflector\InflectorFactory;
33
34
/**
35
 * Generic class used to generate PHP5 entity classes from Mapper.
36
 *
37
 *     [php]
38
 *     $mapper = $service->mappers()->build('Entity);
39
 *
40
 *     $generator = new EntityGenerator();
41
 *     $generator->setGenerateStubMethods(true);
42
 *     $generator->setRegenerateEntityIfExists(false);
43
 *     $generator->setUpdateEntityIfExists(true);
44
 *     $generator->generate($mapper, '/path/to/generate/entities');
45
 *
46
 *
47
 * @link    www.doctrine-project.org
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @author tag
Loading history...
introduced by
Tag value indented incorrectly; expected 1 space but found 4
Loading history...
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
48
 * @since   2.0
0 ignored issues
show
introduced by
Tag value indented incorrectly; expected 1 space but found 3
Loading history...
Coding Style introduced by
The tag in position 2 should be the @link tag
Loading history...
49
 * @author  Benjamin Eberlei <[email protected]>
0 ignored issues
show
introduced by
Tag value indented incorrectly; expected 1 space but found 2
Loading history...
Coding Style introduced by
The tag in position 3 should be the @since tag
Loading history...
50
 * @author  Guilherme Blanco <[email protected]>
0 ignored issues
show
introduced by
Tag value indented incorrectly; expected 1 space but found 2
Loading history...
51
 * @author  Jonathan Wage <[email protected]>
0 ignored issues
show
introduced by
Tag value indented incorrectly; expected 1 space but found 2
Loading history...
52
 * @author  Roman Borschel <[email protected]>
0 ignored issues
show
introduced by
Tag value indented incorrectly; expected 1 space but found 2
Loading history...
53
 */
54
class EntityGenerator
55
{
56
    // @todo should not be there : should be on PhpTypeInterface
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
57
    /**
58
     * Map prime types to php 7.4 property type
59
     */
60
    const PROPERTY_TYPE_MAP = [
61
        PhpTypeInterface::BOOLEAN => 'bool',
62
        PhpTypeInterface::DOUBLE => 'float',
63
        PhpTypeInterface::INTEGER => 'int',
64
    ];
65
66
    /**
67
     * Specifies class fields should be protected.
68
     */
69
    const FIELD_VISIBLE_PROTECTED = 'protected';
70
71
    /**
72
     * Specifies class fields should be private.
73
     */
74
    const FIELD_VISIBLE_PRIVATE = 'private';
75
76
    /**
77
     * The prime service locator
78
     *
79
     * @var ServiceLocator
80
     */
81
    private $prime;
82
83
    /**
84
     * The inflector instance
85
     *
86
     * @var InflectorObject
87
     */
88
    private $inflector;
89
90
    /**
91
     * The mapper info
92
     *
93
     * @var MapperInfo
94
     */
95
    private $mapperInfo;
96
97
    /**
98
     * The extension to use for written php files.
99
     *
100
     * @var string
101
     */
102
    private $extension = '.php';
103
104
    /**
105
     * Whether or not the current Mapper instance is new or old.
106
     *
107
     * @var boolean
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for @var tag in member variable comment
Loading history...
108
     */
109
    private $isNew = true;
110
111
    /**
112
     * @var array
113
     */
114
    private $staticReflection = [];
115
116
    /**
117
     * Number of spaces to use for indention in generated code.
118
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @var tag in member variable comment
Loading history...
119
    private $numSpaces = 4;
120
121
    /**
122
     * The actual spaces to use for indention.
123
     *
124
     * @var string
125
     */
126
    private $spaces = '    ';
127
128
    /**
129
     * The class all generated entities should extend.
130
     *
131
     * @var string
132
     */
133
    private $classToExtend;
134
135
    /**
136
     * The interfaces all generated entities should implement.
137
     *
138
     * @var array
139
     */
140
    private $interfaces = [];
141
142
    /**
143
     * The traits
144
     *
145
     * @var array
146
     */
147
    private $traits = [];
148
149
    /**
150
     * Whether or not to generate sub methods.
151
     *
152
     * @var boolean
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for @var tag in member variable comment
Loading history...
153
     */
154
    private $generateEntityStubMethods = true;
155
156
    /**
157
     * Whether or not to update the entity class if it exists already.
158
     *
159
     * @var boolean
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for @var tag in member variable comment
Loading history...
160
     */
161
    private $updateEntityIfExists = false;
162
163
    /**
164
     * Whether or not to re-generate entity class if it exists already.
165
     *
166
     * @var boolean
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for @var tag in member variable comment
Loading history...
167
     */
168
    private $regenerateEntityIfExists = false;
169
170
    /**
171
     * The name of get methods will not contains the 'get' prefix
172
     *
173
     * @var boolean
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for @var tag in member variable comment
Loading history...
174
     */
175
    private $useGetShortcutMethod = true;
176
177
    /**
178
     * Visibility of the field
179
     *
180
     * @var string
181
     */
182
    private $fieldVisibility = self::FIELD_VISIBLE_PROTECTED;
183
184
    /**
185
     * Use type on generated properties
186
     * Note: only compatible with PHP >= 7.4
187
     *
188
     * @var bool
0 ignored issues
show
Bug introduced by
Expected "boolean" but found "bool" for @var tag in member variable comment
Loading history...
189
     */
190
    private $useTypedProperties = false;
191
192
    /**
193
     * @var string
194
     */
195
    private static $classTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
196
'<?php
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
197
198
<namespace><useStatement><entityAnnotation>
199
<entityClassName>
200
{
201
<entityTraits><entityBody>
202
}
203
';
204
205
    /**
206
     * @var string
207
     */
208
    private static $getMethodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
209
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
210
 * <description>
211
 *
212
 * @return <variableType>
213
 */
214
public function <methodName>()
215
{
216
<spaces>return $this-><fieldName>;
217
}
218
';
219
220
    /**
221
     * @var string
222
     */
223
    private static $setMethodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
224
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
225
 * <description>
226
 *
227
 * @param <variableType> $<variableName>
228
 *
229
 * @return $this
230
 */
231
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
232
{
233
<spaces>$this-><fieldName> = $<variableName>;
234
235
<spaces>return $this;
236
}
237
';
238
239
    /**
240
     * @var string
241
     */
242
    private static $addMethodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
243
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
244
 * <description>
245
 *
246
 * @param <variableType> $<variableName>
247
 *
248
 * @return $this
249
 */
250
public function <methodName>(<methodTypeHint>$<variableName>)
251
{
252
<spaces>$this-><fieldName>[] = $<variableName>;
253
254
<spaces>return $this;
255
}
256
';
257
258
    /**
259
     * @var string
260
     */
261
    private static $methodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
262
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
263
 * <description>
264
 */
265
public function <methodName>()
266
{
267
<spaces><content>
268
}
269
';
270
271
    /**
272
     * @var string
273
     */
274
    private static $constructorMethodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
275
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
276
 * Constructor
277
 */
278
public function __construct()
279
{
280
<spaces><collections>
281
}
282
';
283
284
    /**
285
     * @var string
286
     */
287
    private static $importableConstructorMethodTemplate =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
288
'/**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 4 spaces, found 0
Loading history...
289
 * Constructor
290
 *
291
 * @param array $data
292
 */
293
public function __construct(array $data = [])
294
{
295
<spaces><initialize>$this->import($data);
296
}
297
';
298
299
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $prime should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $inflector should have a doc-comment as per coding-style.
Loading history...
300
     * Set prime service locator
301
     */
302 29
    public function __construct(ServiceLocator $prime, ?InflectorObject $inflector = null)
303
    {
304 29
        $this->prime = $prime;
305 29
        $this->inflector = $inflector ?? InflectorFactory::create()->build();
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
306 29
    }
307
308
    /**
309
     * Generates and writes entity classes
310
     *
311
     * @param Mapper $mapper
312
     * @param string $file    Entity file name
313
     *
314
     * @return string|false If no generation
315
     * 
316
     * @api
317
     */
318 28
    public function generate($mapper, $file = null)
0 ignored issues
show
introduced by
Type hint "Mapper" missing for $mapper
Loading history...
319
    {
320 28
        $this->isNew = !$file || !file_exists($file) || $this->regenerateEntityIfExists;
0 ignored issues
show
Coding Style introduced by
The value of a boolean operation must not be assigned to a variable
Loading history...
Coding Style introduced by
Boolean operators are not allowed outside of control structure conditions
Loading history...
321
322
        // If entity doesn't exist or we're re-generating the entities entirely
323 28
        if ($this->isNew || !$file) {
324 28
            return $this->generateEntityClass($mapper);
325
        // If entity exists and we're allowed to update the entity class
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 12 spaces, found 8
Loading history...
326
        } elseif ($this->updateEntityIfExists && $file) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
327
            return $this->generateUpdatedEntityClass($mapper, $file);
328
        }
329
        
330
        return false;
331
    }
332
    
333
    /**
334
     * Generates a PHP5 Doctrine 2 entity class from the given Mapper instance.
335
     *
336
     * @param Mapper $mapper
337
     *
338
     * @return string
339
     */
340 28
    public function generateEntityClass(Mapper $mapper)
341
    {
342 28
        $this->mapperInfo = $mapper->info();
343
        
344 28
        $this->staticReflection[$this->mapperInfo->className()] = ['properties' => [], 'methods' => []];
345
        
346
        $placeHolders = array(
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
347 28
            '<namespace>',
348
            '<useStatement>',
349
            '<entityAnnotation>',
350
            '<entityClassName>',
351
            '<entityTraits>',
352
            '<entityBody>'
0 ignored issues
show
introduced by
A comma should follow the last multiline array item. Found: '<entityBody>'
Loading history...
353
        );
354
355
        $replacements = array(
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
356 28
            $this->generateEntityNamespace(),
357 28
            $this->generateEntityUse(),
358 28
            $this->generateEntityDocBlock(),
359 28
            $this->generateEntityClassName(),
360 28
            $this->generateEntityTraits(),
361 28
            $this->generateEntityBody()
0 ignored issues
show
introduced by
A comma should follow the last multiline array item. Found: )
Loading history...
362
        );
363
364 28
        $code = str_replace($placeHolders, $replacements, static::$classTemplate);
0 ignored issues
show
Bug introduced by
Since $classTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $classTemplate to at least protected.
Loading history...
365
366 28
        return str_replace('<spaces>', $this->spaces, $code);
367
    }
368
369
    /**
370
     * Generates the updated code for the given Mapper and entity at path.
371
     *
372
     * @param Mapper $mapper
373
     * @param string $file
374
     *
375
     * @return string
376
     */
377
    public function generateUpdatedEntityClass(Mapper $mapper, $file)
378
    {
379
        $this->mapperInfo = $mapper->info();
380
        
381
        $currentCode = file_get_contents($file);
382
383
        $this->parseTokensInEntityFile($currentCode);
384
        
385
        $body = $this->generateEntityBody();
386
        $body = str_replace('<spaces>', $this->spaces, $body);
387
        $last = strrpos($currentCode, '}');
388
389
        return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : '') . "}\n";
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
390
    }
391
392
    /**
393
     * @return string
394
     */
395 28
    protected function generateEntityNamespace(): string
396
    {
397 28
        if ($this->hasNamespace($this->mapperInfo->className())) {
398 28
            return 'namespace ' . $this->getNamespace($this->mapperInfo->className()) .';' . "\n\n";
399
        }
400
401
        return '';
402
    }
403
404
    /**
405
     * Generate use part
406
     * 
407
     * @return string
408
     */
409 28
    protected function generateEntityUse()
410
    {
411 28
        $use = [];
412
        
413 28
        if ($this->hasNamespace($this->getClassToExtend())) {
414 2
            $use[$this->getClassToExtend()] = 'use ' . $this->getClassToExtend() . ';';
415
        }
416
        
417 28
        foreach ($this->interfaces as $interface) {
418 3
            if ($this->hasNamespace($interface)) {
419 3
                $use[$interface] = 'use ' . $interface . ';';
420
            }
421
        }
422
        
423 28
        foreach ($this->traits as $trait) {
424 2
            if ($this->hasNamespace($trait)) {
425 2
                $use[$trait] = 'use ' . $trait . ';';
426
            }
427
        }
428
        
429 28
        foreach ($this->mapperInfo->objects() as $info) {
430 25
            $className = $info->className();
431 25
            if (!$info->belongsToRoot()) {
432 4
                continue;
433
            }
434
435 25
            if ($this->hasNamespace($className)) {
436 25
                $use[$className] = 'use '.$className.';';
437
            }
438
439 25
            if ($info->wrapper() !== null) {
440 1
                $repository = $this->prime->repository($className);
441 1
                $wrapperClass = $repository->collectionFactory()->wrapperClass($info->wrapper());
0 ignored issues
show
Bug introduced by
It seems like $info->wrapper() can also be of type callable; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

441
                $wrapperClass = $repository->collectionFactory()->wrapperClass(/** @scrutinizer ignore-type */ $info->wrapper());
Loading history...
442
443 1
                if ($this->hasNamespace($wrapperClass)) {
444 25
                    $use[$wrapperClass] = 'use '.$wrapperClass.';';
445
                }
446
            }
447
        }
448
        
449 28
        if (!$use) {
450 4
            return '';
451
        }
452
        
453 25
        sort($use);
454
        
455 25
        return implode("\n", $use) . "\n\n";
456
    }
457
    
458
    /**
459
     * @return string
460
     */
461 28
    protected function generateEntityClassName()
462
    {
463 28
        return 'class ' . $this->getClassName($this->mapperInfo->className()) .
464 28
            ($this->classToExtend ? ' extends ' . $this->getClassToExtendName() : null) .
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
465 28
            ($this->interfaces ? ' implements ' . $this->getInterfacesToImplement() : null);
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
466
    }
467
468
    /**
469
     * @return string
470
     */
471 28
    protected function generateEntityTraits()
472
    {
473 28
        if (!$this->traits) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->traits of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
474 26
            return '';
475
        }
476
        
477 2
        $traits = '';
478
        
479 2
        foreach ($this->traits as $trait) {
480 2
            $traits .= $this->spaces . 'use ' . $this->getRelativeClassName($trait) . ';' . "\n";
481
        }
482
        
483 2
        return $traits . "\n";
484
    }
485
486
    /**
487
     * @param Mapper $mapper
0 ignored issues
show
Coding Style introduced by
Superfluous parameter comment
Loading history...
introduced by
Doc comment for parameter $mapper does not match actual variable name <undefined>
Loading history...
488
     *
489
     * @return string
490
     */
491 28
    protected function generateEntityBody()
492
    {
493 28
        $fieldMappingProperties = $this->generateEntityFieldMappingProperties();
494 28
        $embeddedProperties = $this->generateEntityEmbeddedProperties();
495 28
        $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods() : null;
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
496
497 28
        $code = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
498
499 28
        if ($fieldMappingProperties) {
500 28
            $code[] = $fieldMappingProperties;
501
        }
502
503 28
        if ($embeddedProperties) {
504 25
            $code[] = $embeddedProperties;
505
        }
506
507 28
        $code[] = $this->generateEntityConstructor();
508
509 28
        if ($stubMethods) {
510 27
            $code[] = $stubMethods;
511
        }
512
513 28
        return implode("\n", $code);
514
    }
515
516
    /**
517
     * @return string
518
     */
519 28
    protected function generateEntityConstructor()
520
    {
521 28
        $initializable = in_array(InitializableInterface::class, $this->interfaces);
522 28
        $isImportable  = in_array(ImportableInterface::class, $this->interfaces)
523 28
                    || is_subclass_of($this->classToExtend, ImportableInterface::class);
0 ignored issues
show
Coding Style introduced by
Boolean operators are not allowed outside of control structure conditions
Loading history...
524
525 28
        $collections = [];
526
527 28
        foreach ($this->mapperInfo->objects() as $property) {
528 25
            if (!$property->belongsToRoot()) {
529 4
                continue;
530
            }
531
532 25
            if ($property->isRelation()) {
533 24
                if (!$property->isArray()) {
534 24
                    $collections[$property->name()] = '$this->'.$property->name().' = new '.$this->getRelativeClassName($property->className()).'();';
535 21
                } elseif ($property->wrapper() === 'collection') { // @todo handle other wrapper types
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
introduced by
There should be no white space after an opening "{"
Loading history...
Coding Style introduced by
Comments may not appear after statements
Loading history...
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
536 24
                    $collections[$property->name()] = '$this->'.$property->name().' = '.$this->getRelativeClassName($property->className()).'::collection();';
537
                }
538
            } else {
539 25
                $collections[$property->name()] = '$this->'.$property->name().' = new '.$this->getRelativeClassName($property->className()).'();';
540
            }
541
        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
542 28
        foreach ($this->mapperInfo->properties() as $property) {
543 28
            if ($property->isDateTime() && $property->hasDefault()) {
544 3
                $constructorArgs = '';
545
                // Add the default timezone from the property type.
546 3
                if ($timezone = $property->getTimezone()) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
547 3
                    $constructorArgs = "'now', new \DateTimeZone('$timezone')";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $timezone instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
548
                }
549
550 28
                $collections[$property->name()] = '$this->'.$property->name().' = new '.$property->phpType().'('.$constructorArgs.');';
551
            }
552
        }
553
        
554 28
        $methods = [];
555
        
556 28
        if (!$this->hasMethod('__construct')) {
557 26
            if ($isImportable) {
558 2
                $buffer = '';
559
560 2
                if ($initializable) {
561 1
                    $buffer = '$this->initialize();'."\n".$this->spaces;
562 1
                } elseif ($collections) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
563 1
                    $buffer = implode("\n".$this->spaces, $collections)."\n".$this->spaces;
564
                }
565
566 2
                $methods[] = $this->prefixCodeWithSpaces(str_replace("<initialize>", $buffer, static::$importableConstructorMethodTemplate));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal <initialize> does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Bug introduced by
Since $importableConstructorMethodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $importableConstructorMethodTemplate to at least protected.
Loading history...
567 24
            } elseif ($collections && !$initializable) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
568 23
                $methods[] = $this->prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->spaces, $collections), static::$constructorMethodTemplate));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal <collections> does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Bug introduced by
Since $constructorMethodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $constructorMethodTemplate to at least protected.
Loading history...
569
            }
570
        }
571
        
572 28
        if (!$this->hasMethod('initialize') && $initializable) {
573 1
            $methods[] = $this->generateMethod('{@inheritdoc}', 'initialize', implode("\n".$this->spaces, $collections));
574
        }
575
576 28
        return implode("\n", $methods);
577
    }
578
579
    /**
580
     * @param Mapper $mapper
0 ignored issues
show
introduced by
Doc comment for parameter $mapper does not match actual variable name <undefined>
Loading history...
Coding Style introduced by
Superfluous parameter comment
Loading history...
581
     *
582
     * @return string
583
     */
584 28
    protected function generateEntityDocBlock()
585
    {
586 28
        $lines = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
587 28
        $lines[] = '/**';
588 28
        $lines[] = ' * ' . $this->getClassName($this->mapperInfo->className());
589 28
        $lines[] = ' */';
590
        
591 28
        return implode("\n", $lines);
592
    }
593
    
594
    /**
595
     * @return string
596
     */
597 27
    protected function generateEntityStubMethods()
598
    {
599 27
        $methods = [];
600
        
601 27
        foreach ($this->mapperInfo->properties() as $property) {
602 27
            if ($code = $this->generateEntityStubMethod('set', $property)) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
603 27
                $methods[] = $code;
604
            }
605
606 27
            if ($code = $this->generateEntityStubMethod('get', $property)) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
607 27
                $methods[] = $code;
608
            }
609
        }
610
611 27
        foreach ($this->mapperInfo->objects() as $property) {
612 24
            if (!$property->belongsToRoot()) {
613 4
                continue;
614
            }
615
616 24
            if (!$property->isArray() || $property->wrapper() !== null) {
617 24
                if ($code = $this->generateEntityStubMethod('set', $property)) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
618 24
                    $methods[] = $code;
619
                }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
620 24
                if ($code = $this->generateEntityStubMethod('get', $property)) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
621 24
                    $methods[] = $code;
622
                }
623
            } else {
624 19
                if ($code = $this->generateEntityStubMethod('add', $property)) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
625 19
                    $methods[] = $code;
626
                }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
627 19
                if ($code = $this->generateEntityStubMethod('set', $property)) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
628 19
                    $methods[] = $code;
629
                }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
630 19
                if ($code = $this->generateEntityStubMethod('get', $property)) {
0 ignored issues
show
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
631 24
                    $methods[] = $code;
632
                }
633
            }
634
        }
0 ignored issues
show
Coding Style introduced by
End comment for long condition not found; expected "//end foreach"
Loading history...
635
636 27
        return implode("\n", $methods);
637
    }
638
639
    /**
640
     * @return string
641
     */
642 28
    protected function generateEntityFieldMappingProperties()
643
    {
644 28
        $lines = [];
645
646 28
        foreach ($this->mapperInfo->properties() as  $property) {
0 ignored issues
show
Coding Style introduced by
There should be 1 space after "as" as per the coding-style, but found 2.
Loading history...
647 28
            if ($this->hasProperty($property->name())) {
648 2
                continue;
649
            }
650
            
651 28
            $default = '';
652
653 28
            if ($property->hasDefault() && !$property->isDateTime()) {
654 4
                $default = ' = '.$this->stringfyValue(
655 4
                    $property->convert($property->getDefault())
656
                );
657 28
            } elseif ($property->isArray()) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
658 17
                $default = ' = []';
659
            }
660
661
            // A nullable property should be defined as null by default
662
            // A property is considered as nullable if it's explicitly defined on mapper or if the field is auto-generated
663 28
            if ($this->useTypedProperties && !$default && $property->isNullable()) {
664 6
                $default = ' = null';
665
            }
666
667 28
            $lines[] = $this->generateFieldMappingPropertyDocBlock($property);
668 28
            $lines[] = $this->spaces.$this->fieldVisibility.$this->getPropertyTypeHintForSimpleProperty($property).' $'.$property->name().$default.";\n";
669
        }
0 ignored issues
show
Coding Style introduced by
End comment for long condition not found; expected "//end foreach"
Loading history...
670
671 28
        return implode("\n", $lines);
672
    }
673
674
    /**
675
     * @return string
676
     */
677 28
    protected function generateEntityEmbeddedProperties()
678
    {
679 28
        $lines = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
680
681 28
        foreach ($this->mapperInfo->objects() as $property) {
682 25
            if (!$property->belongsToRoot() || $this->hasProperty($property->name())) {
683 6
                continue;
684
            }
685
            
686 25
            if (!$property->isRelation()) {
687 4
                $lines[] = $this->generateEmbeddedPropertyDocBlock($property);
688 4
                $lines[] = $this->spaces . $this->fieldVisibility . $this->getPropertyTypeHintForObject($property) . ' $'.$property->name().";\n";
689
            } else {
690 24
                $name = $property->name();
691 24
                $default = '';
692
693
                // Do not initialize the property if it's a wrapper
694 24
                if ($property->isArray() && $property->wrapper() === null) {
695 18
                    $default = ' = []';
696
                }
697
698
                // If property is typed, always define a default value
699 24
                if ($this->useTypedProperties && !$default) {
700 7
                    $default = ' = null';
701
                }
702
703 24
                $lines[] = $this->generateEmbeddedPropertyDocBlock($property);
704 25
                $lines[] = $this->spaces . $this->fieldVisibility . $this->getPropertyTypeHintForObject($property) . ' $' . $name . $default .";\n";
705
            }
706
        }
0 ignored issues
show
Coding Style introduced by
End comment for long condition not found; expected "//end foreach"
Loading history...
707
708 28
        return implode("\n", $lines);
709
    }
710
711
    /**
712
     * @param string            $type
713
     * @param InfoInterface     $propertyInfo
714
     * @param string|null       $defaultValue
715
     *
716
     * @return string
717
     */
718 27
    protected function generateEntityStubMethod($type, InfoInterface $propertyInfo, $defaultValue = null)
719
    {
720 27
        $fieldName = $propertyInfo->name();
721
722
        // The hint flag help algorythm to determine the hint info for object parameter.
723
        // It should be 'array' for collection but the add method need the object hint.
724
        // setItems(array $items)
725
        // addItem(Item $item)
726 27
        $hintOne = false;
727
728 27
        if ($type === 'get' && $this->useGetShortcutMethod === true) {
729 26
            $variableName = $this->inflector->camelize($fieldName);
730 26
            $methodName = $variableName;
731
        } else {
732 27
            $methodName = $type . $this->inflector->classify($fieldName);
733 27
            $variableName = $this->inflector->camelize($fieldName);
734
        }
735
        
736 27
        if ($type === 'add') {
737 19
            $methodName = $this->inflector->singularize($methodName);
738 19
            $variableName = $this->inflector->singularize($variableName);
739 19
            $hintOne = true;
740
        }
741
742 27
        if ($this->hasMethod($methodName)) {
743
            return '';
744
        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
745 27
        $this->staticReflection[$this->mapperInfo->className()]['methods'][] = strtolower($methodName);
746
747 27
        if ($propertyInfo->isObject()) {
748
            /** @var ObjectPropertyInfo $propertyInfo */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
749 24
            $variableType = $this->getRelativeClassName($propertyInfo->className());
750 24
            $methodTypeHint =  $variableType.' ';
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "="; 2 found
Loading history...
751
        } else {
752
            /** @var PropertyInfo $propertyInfo */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
753 27
            $variableType = $propertyInfo->phpType();
754 27
            $methodTypeHint = '';
755
        }
756
757 27
        if ($propertyInfo->isArray() && $hintOne === false) {
758 20
            if ($propertyInfo->isObject() && $propertyInfo->wrapper() !== null) {
0 ignored issues
show
Bug introduced by
The method wrapper() does not exist on Bdf\Prime\Mapper\Info\PropertyInfo. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

758
            if ($propertyInfo->isObject() && $propertyInfo->/** @scrutinizer ignore-call */ wrapper() !== null) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
759
                /** @var ObjectPropertyInfo $propertyInfo */
0 ignored issues
show
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
760 1
                $repository = $this->prime->repository($propertyInfo->className());
761 1
                $wrapperClass = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass($propertyInfo->wrapper()));
0 ignored issues
show
Bug introduced by
It seems like $propertyInfo->wrapper() can also be of type callable; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

761
                $wrapperClass = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass(/** @scrutinizer ignore-type */ $propertyInfo->wrapper()));
Loading history...
762
763 1
                $methodTypeHint = $wrapperClass.' ';
764 1
                $variableType .= '[]|'.$wrapperClass;
765
            } else {
766 19
                $methodTypeHint = 'array ';
767
768 19
                if ($variableType !== 'array') {
769 19
                    $variableType .= '[]';
770
                }
771
            }
772
        }
773
774
        $replacements = array(
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
775 27
          '<description>'       => ucfirst($type).' '.$variableName,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
776 27
          '<methodTypeHint>'    => $methodTypeHint,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
777 27
          '<variableType>'      => $variableType,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
778 27
          '<variableName>'      => $variableName,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
779 27
          '<methodName>'        => $methodName,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
780 27
          '<fieldName>'         => $fieldName,
0 ignored issues
show
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
781 27
          '<variableDefault>'   => ($defaultValue !== null ) ? (' = '.$defaultValue) : ''
0 ignored issues
show
introduced by
There should be no white space before a closing ")"
Loading history...
introduced by
A comma should follow the last multiline array item. Found: ''
Loading history...
Coding Style introduced by
Array key not indented correctly; expected 12 spaces but found 10
Loading history...
782
        );
783
784 27
        $method = str_replace(
785 27
            array_keys($replacements),
786 27
            array_values($replacements),
787 27
            $this->getMethodTemplate($type)
788
        );
789
790 27
        return $this->prefixCodeWithSpaces($method);
791
    }
792
793
    /**
794
     * Get the template of the method
795
     *
796
     * @param string $prefix
797
     *
798
     * @return string
799
     *
800
     * @throws \LogicException
801
     */
802 27
    private function getMethodTemplate($prefix)
0 ignored issues
show
Coding Style introduced by
Private method name "EntityGenerator::getMethodTemplate" must be prefixed with an underscore
Loading history...
803
    {
804
        switch ($prefix) {
805 27
            case 'get':
806 27
                return static::$getMethodTemplate;
0 ignored issues
show
introduced by
Case breaking statement indented incorrectly; expected 14 spaces, found 16
Loading history...
Bug introduced by
Since $getMethodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $getMethodTemplate to at least protected.
Loading history...
807
808 27
            case 'add':
809 19
                return static::$addMethodTemplate;
0 ignored issues
show
introduced by
Case breaking statement indented incorrectly; expected 14 spaces, found 16
Loading history...
Bug introduced by
Since $addMethodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $addMethodTemplate to at least protected.
Loading history...
810
811 27
            case 'set':
812 27
                return static::$setMethodTemplate;
0 ignored issues
show
introduced by
Case breaking statement indented incorrectly; expected 14 spaces, found 16
Loading history...
Bug introduced by
Since $setMethodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $setMethodTemplate to at least protected.
Loading history...
813
        }
814
815
        throw new \LogicException('No template found for method "'.$prefix.'"');
816
    }
817
818
    /**
819
     * @param string $description
820
     * @param string $methodName
821
     * @param string $content
822
     *
823
     * @return string
824
     */
825 1
    protected function generateMethod(string $description, string $methodName, string $content)
826
    {
827 1
        if ($this->hasMethod($methodName)) {
828
            return '';
829
        }
830
        
831 1
        $this->staticReflection[$this->mapperInfo->className()]['methods'][] = $methodName;
832
833
        $replacements = array(
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
834 1
            '<description>' => $description,
835 1
            '<methodName>'  => $methodName,
836 1
            '<content>'     => $content,
837
        );
838
839 1
        $method = str_replace(
840 1
            array_keys($replacements),
841 1
            array_values($replacements),
842 1
            static::$methodTemplate
0 ignored issues
show
Bug introduced by
Since $methodTemplate is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $methodTemplate to at least protected.
Loading history...
843
        );
844
845 1
        return $this->prefixCodeWithSpaces($method);
846
    }
847
848
    /**
849
     * @param PropertyInfo $property
850
     *
851
     * @return string
852
     */
853 28
    protected function generateFieldMappingPropertyDocBlock($property)
0 ignored issues
show
introduced by
Type hint "PropertyInfo" missing for $property
Loading history...
854
    {
855 28
        $lines = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
856 28
        $lines[] = $this->spaces . '/**';
857 28
        $lines[] = $this->spaces . ' * @var '.$property->phpType();
858 28
        $lines[] = $this->spaces . ' */';
859
860 28
        return implode("\n", $lines);
861
    }
862
863
    /**
864
     * @param ObjectPropertyInfo $property
865
     *
866
     * @return string
867
     */
868 25
    protected function generateEmbeddedPropertyDocBlock($property)
0 ignored issues
show
introduced by
Type hint "ObjectPropertyInfo" missing for $property
Loading history...
869
    {
870 25
        $className = $property->className();
871 25
        if ($className) {
872 25
            $className = $this->getRelativeClassName($className);
873
874 25
            if ($property->isArray()) {
875 19
                if ($property->wrapper() !== null) {
876 1
                    $repository = $this->prime->repository($property->className());
877 1
                    $className = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass($property->wrapper())).'|'.$className.'[]';
0 ignored issues
show
Bug introduced by
It seems like $property->wrapper() can also be of type callable; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

877
                    $className = $this->getRelativeClassName($repository->collectionFactory()->wrapperClass(/** @scrutinizer ignore-type */ $property->wrapper())).'|'.$className.'[]';
Loading history...
878
                } else {
879 25
                    $className .= '[]';
880
                }
881
            }
882
        } else {
883
            $className = '{type}';
884
        }
885
        
886 25
        $lines = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
887 25
        $lines[] = $this->spaces . '/**';
888 25
        $lines[] = $this->spaces . ' * @var '.$className;
889 25
        $lines[] = $this->spaces . ' */';
890
891 25
        return implode("\n", $lines);
892
    }
893
    
894
    //
895
    //---------- tools methods
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// ---------- tools methods" but found "//---------- tools methods"
Loading history...
896
    //
897
898
    /**
899
     * @todo this won't work if there is a namespace in brackets and a class outside of it.
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
900
     *
901
     * @param string $src
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
902
     *
903
     * @return void
0 ignored issues
show
introduced by
If there is no return value for a function, there must not be a @return tag.
Loading history...
904
     */
905
    protected function parseTokensInEntityFile($src)
906
    {
907
        $tokens = token_get_all($src);
908
        $lastSeenNamespace = "";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
909
        $lastSeenClass = false;
910
911
        $inNamespace = false;
912
        $inClass = false;
913
914
        for ($i = 0; $i < count($tokens); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Performance Best Practice introduced by
Consider avoiding function calls on each iteration of the for loop.

If you have a function call in the test part of a for loop, this function is executed on each iteration. Often such a function, can be moved to the initialization part and be cached.

// count() is called on each iteration
for ($i=0; $i < count($collection); $i++) { }

// count() is only called once
for ($i=0, $c=count($collection); $i<$c; $i++) { }
Loading history...
Coding Style Performance introduced by
The use of count() inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead
Loading history...
915
            $token = $tokens[$i];
916
            if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) {
0 ignored issues
show
introduced by
If the line declaring an array spans longer than 80 characters, each element should be broken into its own line
Loading history...
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
917
                continue;
918
            }
919
920
            if ($inNamespace) {
921
                if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING) {
922
                    $lastSeenNamespace .= $token[1];
923
                } elseif (is_string($token) && in_array($token, array(';', '{'))) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
924
                    $inNamespace = false;
925
                }
926
            }
927
928
            if ($inClass) {
929
                $inClass = false;
930
                $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1];
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
931
                $this->staticReflection[$lastSeenClass]['properties'] = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
932
                $this->staticReflection[$lastSeenClass]['methods'] = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
933
            }
934
935
            if ($token[0] == T_NAMESPACE) {
936
                $lastSeenNamespace = "";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
937
                $inNamespace = true;
938
            } elseif ($token[0] == T_CLASS && $tokens[$i-1][0] != T_DOUBLE_COLON) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
Coding Style introduced by
Expected 1 space before "-"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "-"; 0 found
Loading history...
939
                $inClass = true;
940
            } elseif ($token[0] == T_FUNCTION) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
941
                if ($tokens[$i+2][0] == T_STRING) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
942
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]);
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
943
                } elseif ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
Coding Style Comprehensibility introduced by
The string literal & does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
944
                    $this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]);
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
945
                }
946
            } elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
introduced by
If the line declaring an array spans longer than 80 characters, each element should be broken into its own line
Loading history...
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
947
                $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "+"; 0 found
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
Coding Style introduced by
Expected 1 space after "+"; 0 found
Loading history...
948
            }
949
        }
0 ignored issues
show
Coding Style introduced by
End comment for long condition not found; expected "//end for"
Loading history...
950
    }
951
952
    /**
953
     * @param string $property
954
     *
955
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
956
     */
957 28
    protected function hasProperty($property)
958
    {
959 28
        if ($this->classToExtend || (!$this->isNew && class_exists($this->mapperInfo->className()))) {
960
            // don't generate property if its already on the base class.
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
961 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $this->mapperInfo->className());
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
962 2
            if ($reflClass->hasProperty($property)) {
963 2
                return true;
964
            }
965
        }
966
967
        // check traits for existing property
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
968 28
        foreach ($this->getTraitsReflections() as $trait) {
969
            if ($trait->hasProperty($property)) {
970
                return true;
971
            }
972
        }
973
974
        return (
975 28
            isset($this->staticReflection[$this->mapperInfo->className()]) &&
0 ignored issues
show
Coding Style introduced by
Boolean operators are not allowed outside of control structure conditions
Loading history...
976 28
            in_array($property, $this->staticReflection[$this->mapperInfo->className()]['properties'])
977
        );
978
    }
979
980
    /**
981
     * @param string $method
982
     *
983
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
984
     */
985 28
    protected function hasMethod($method)
986
    {
987 28
        if ($this->classToExtend || (!$this->isNew && class_exists($this->mapperInfo->className()))) {
988
            // don't generate method if its already on the base class.
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
989 2
            $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $this->mapperInfo->className());
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
990
991 2
            if ($reflClass->hasMethod($method)) {
992 2
                return true;
993
            }
994
        }
995
996
        // check traits for existing method
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
997 28
        foreach ($this->getTraitsReflections() as $trait) {
998
            if ($trait->hasMethod($method)) {
999
                return true;
1000
            }
1001
        }
1002
1003
        return (
1004 28
            isset($this->staticReflection[$this->mapperInfo->className()]) &&
0 ignored issues
show
Coding Style introduced by
Boolean operators are not allowed outside of control structure conditions
Loading history...
1005 28
            in_array(strtolower($method), $this->staticReflection[$this->mapperInfo->className()]['methods'])
1006
        );
1007
    }
1008
1009
    /**
1010
     * Get class name relative to use
1011
     * 
1012
     * @param string $className
1013
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
1014
     */
1015 25
    protected function getRelativeClassName($className)
1016
    {
1017 25
        $className = ltrim($className, '\\');
1018
        
1019 25
        if ($this->hasNamespace($className)) {
1020 25
            return $this->getClassName($className);
1021
        } else {
1022 3
            return '\\' . $className;
1023
        }
1024
    }
1025
    
1026
    /**
1027
     * Get the class short name
1028
     * 
1029
     * @param string $className
1030
     *
1031
     * @return string
1032
     */
1033 28
    protected function getClassName($className)
1034
    {
1035 28
        $parts = explode('\\', $className);
1036 28
        return array_pop($parts);
1037
    }
1038
1039
    /**
1040
     * @param string $className
1041
     *
1042
     * @return string
1043
     */
1044 28
    protected function getNamespace($className)
1045
    {
1046 28
        $parts = explode('\\', $className);
1047 28
        array_pop($parts);
1048
        
1049 28
        return implode('\\', $parts);
1050
    }
1051
    
1052
    /**
1053
     * @param string $className
1054
     *
1055
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
1056
     */
1057 28
    protected function hasNamespace($className)
1058
    {
1059 28
        return strrpos($className, '\\') != 0;
1060
    }
1061
1062
    /**
1063
     * @return string
1064
     */
1065 2
    protected function getClassToExtendName()
1066
    {
1067 2
        $refl = new \ReflectionClass($this->getClassToExtend());
1068
1069 2
        return $this->getRelativeClassName($refl->getName());
1070
    }
1071
1072
    /**
1073
     * @return string
1074
     */
1075 3
    protected function getInterfacesToImplement()
1076
    {
1077 3
        $interfaces = [];
1078
        
1079 3
        foreach ($this->interfaces as $interface) {
1080 3
            $refl = new \ReflectionClass($interface);
1081
1082 3
            $interfaces[] = $this->getRelativeClassName($refl->getName());
1083
        }
1084
        
1085 3
        return implode(', ', $interfaces);
1086
    }
1087
    
1088
    /**
1089
     * @param Mapper $mapper
0 ignored issues
show
introduced by
Doc comment for parameter $mapper does not match actual variable name <undefined>
Loading history...
Coding Style introduced by
Superfluous parameter comment
Loading history...
1090
     *
1091
     * @return \ReflectionClass[]
1092
     */
1093 28
    protected function getTraitsReflections()
1094
    {
1095 28
        if ($this->isNew) {
1096 28
            return [];
1097
        }
1098
        
1099
        $reflClass = new \ReflectionClass($this->mapperInfo->className());
1100
1101
        $traits = array();
0 ignored issues
show
Coding Style introduced by
Short array syntax must be used to define arrays
Loading history...
1102
1103
        while ($reflClass !== false) {
1104
            $traits = array_merge($traits, $reflClass->getTraits());
0 ignored issues
show
Bug introduced by
It seems like $reflClass->getTraits() can also be of type null; however, parameter $arrays of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1104
            $traits = array_merge($traits, /** @scrutinizer ignore-type */ $reflClass->getTraits());
Loading history...
1105
1106
            $reflClass = $reflClass->getParentClass();
1107
        }
1108
1109
        return $traits;
1110
    }
1111
    
1112
    /**
1113
     * @param string $code
1114
     * @param int    $num
0 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for parameter type
Loading history...
1115
     *
1116
     * @return string
1117
     */
1118 28
    protected function prefixCodeWithSpaces($code, $num = 1)
1119
    {
1120 28
        $lines = explode("\n", $code);
1121
1122 28
        foreach ($lines as $key => $value) {
1123 28
            if ( ! empty($value)) {
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after opening bracket; 1 found
Loading history...
Coding Style introduced by
First condition of a multi-line IF statement must directly follow the opening parenthesis
Loading history...
introduced by
There should be no white space after an opening "("
Loading history...
introduced by
A unary operator statement must not be followed by a space
Loading history...
1124 28
                $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key];
1125
            }
1126
        }
1127
1128 28
        return implode("\n", $lines);
1129
    }
1130
    
1131
    /**
1132
     * Get string representation of a value
1133
     * 
1134
     * @param mixed $value
1135
     *
1136
     * @return string
1137
     */
1138 4
    protected function stringfyValue($value)
1139
    {
1140 4
        if (is_array($value)) {
1141
            if (empty($value)) {
1142
                return '[]';
1143
            }
1144
            
1145
            return var_export($value, true);
1146
        }
1147
        
1148 4
        if (null === $value) {
1149
            return 'null';
1150
        }
1151
        
1152 4
        if (is_string($value)) {
1153 3
            return "'" . $value . "'";
1154
        }
1155
        
1156 2
        if (is_bool($value)) {
1157 2
            return $value ? 'true' : 'false';
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
1158
        }
1159
1160
        return $value;
1161
    }
1162
1163
    /**
1164
     * Get the php 7.4 property type hint
1165
     *
1166
     * This method will map invalid type hint to value one (ex: double -> float)
1167
     * It will also resolve the relative class name if the type is a class
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
1168
     *
1169
     * @param string $type The property type declared by field phpType()
1170
     * @param bool $nullable Does the property should be nullable
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
1171
     *
1172
     * @return string
1173
     *
1174
     * @see TypeInterface::phpType()
1175
     *
1176
     * @todo use directly the property info object ?
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
1177
     */
1178 7
    protected function getPropertyTypeHint(string $type, bool $nullable): string
1179
    {
1180 7
        if (class_exists($type)) {
1181 7
            $type = $this->getRelativeClassName($type);
1182
        } else {
1183 7
            $type = self::PROPERTY_TYPE_MAP[$type] ?? $type;
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
1184
        }
1185
1186 7
        return ($nullable ? '?' : '') . $type;
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
1187
    }
1188
1189
    /**
1190
     * Get the php 7.4 property type hint for a simple property
1191
     *
1192
     * If typed properties are disabled, this method will return an empty string
1193
     * The returned type hint will be prefixed by a single space
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
1194
     *
1195
     * @param PropertyInfo $property
1196
     *
1197
     * @return string
1198
     */
1199 28
    protected function getPropertyTypeHintForSimpleProperty(PropertyInfo $property): string
1200
    {
1201 28
        if (!$this->useTypedProperties) {
1202 26
            return '';
1203
        }
1204
1205 7
        return ' ' . $this->getPropertyTypeHint($property->phpType(), $property->isNullable());
1206
    }
1207
1208
    /**
1209
     * Get the php 7.4 property type hint for a object property (i.e. relation or embedded)
1210
     *
1211
     * If typed properties are disabled, this method will return an empty string
1212
     * The returned type hint will be prefixed by a single space
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
1213
     *
1214
     * - Embedded properties will not be marked as nullable
1215
     * - Relations will always be nullable
1216
     * - This method will also resolve collection relations and the wrapper class if provided
1217
     *
1218
     * @param ObjectPropertyInfo $property
1219
     *
1220
     * @return string
1221
     */
1222 25
    protected function getPropertyTypeHintForObject(ObjectPropertyInfo $property): string
1223
    {
1224 25
        if (!$this->useTypedProperties) {
1225 23
            return '';
1226
        }
1227
1228 7
        $type = $property->className();
1229
1230 7
        if ($property->isArray()) {
1231 5
            if ($property->wrapper() === null) {
1232 4
                $type = 'array';
1233
            } else {
1234 1
                $repository = $this->prime->repository($type);
1235 1
                $type = $repository->collectionFactory()->wrapperClass($property->wrapper());
0 ignored issues
show
Bug introduced by
It seems like $property->wrapper() can also be of type callable; however, parameter $wrapper of Bdf\Prime\Collection\Col...Factory::wrapperClass() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1235
                $type = $repository->collectionFactory()->wrapperClass(/** @scrutinizer ignore-type */ $property->wrapper());
Loading history...
1236
            }
1237
        }
1238
1239 7
        return ' ' . $this->getPropertyTypeHint($type, $property->isRelation());
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type null; however, parameter $type of Bdf\Prime\Entity\EntityG...::getPropertyTypeHint() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1239
        return ' ' . $this->getPropertyTypeHint(/** @scrutinizer ignore-type */ $type, $property->isRelation());
Loading history...
1240
    }
1241
1242
    //---------------------- mutators
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// ---------------------- mutators" but found "//---------------------- mutators"
Loading history...
1243
1244
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $numSpaces should have a doc-comment as per coding-style.
Loading history...
1245
     * Sets the number of spaces the exported class should have.
1246
     *
1247
     * @api
1248
     */
1249 1
    public function setNumSpaces(int $numSpaces): void
1250
    {
1251 1
        $this->spaces = str_repeat(' ', $numSpaces);
1252 1
        $this->numSpaces = $numSpaces;
1253 1
    }
1254
1255
    /**
1256
     * Gets the indentation spaces
1257
     */
1258 1
    public function getNumSpaces(): int
1259
    {
1260 1
        return $this->numSpaces;
1261
    }
1262
1263
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $extension should have a doc-comment as per coding-style.
Loading history...
1264
     * Sets the extension to use when writing php files to disk.
1265
     *
1266
     * @api
1267
     */
1268 1
    public function setExtension(string $extension): void
1269
    {
1270 1
        $this->extension = $extension;
1271 1
    }
1272
1273
    /**
1274
     * Get the file extension
1275
     */
1276 1
    public function getExtension(): string
1277
    {
1278 1
        return $this->extension;
1279
    }
1280
1281
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $classToExtend should have a doc-comment as per coding-style.
Loading history...
1282
     * Sets the name of the class the generated classes should extend from.
1283
     *
1284
     * @api
1285
     */
1286 3
    public function setClassToExtend(string $classToExtend): void
1287
    {
1288 3
        $this->classToExtend = $classToExtend;
1289 3
    }
1290
1291
    /**
1292
     * Get the class to extend
1293
     */
1294 29
    public function getClassToExtend(): ?string
1295
    {
1296 29
        return $this->classToExtend;
1297
    }
1298
1299
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $interface should have a doc-comment as per coding-style.
Loading history...
1300
     * Add interface to implement
1301
     *
1302
     * @api
1303
     */
1304 2
    public function addInterface(string $interface)
1305
    {
1306 2
        $this->interfaces[$interface] = $interface;
1307 2
    }
1308
1309
    /**
1310
     * Sets the interfaces
1311
     *
1312
     * @param string[] $interfaces
1313
     *
1314
     * @api
1315
     */
1316 2
    public function setInterfaces(array $interfaces): void
1317
    {
1318 2
        $this->interfaces = $interfaces;
1319 2
    }
1320
1321
    /**
1322
     * Get the registered interfaces
1323
     */
1324 1
    public function getInterfaces(): array
1325
    {
1326 1
        return $this->interfaces;
1327
    }
1328
1329
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $trait should have a doc-comment as per coding-style.
Loading history...
1330
     * Add trait
1331
     *
1332
     * @api
1333
     */
1334 2
    public function addTrait(string $trait)
1335
    {
1336 2
        $this->traits[$trait] = $trait;
1337 2
    }
1338
1339
    /**
1340
     * Sets the traits
1341
     *
1342
     * @param string[] $traits
1343
     *
1344
     * @api
1345
     */
1346 1
    public function setTraits(array $traits): void
1347
    {
1348 1
        $this->traits = $traits;
1349 1
    }
1350
1351
    /**
1352
     * Get the registered traits
1353
     */
1354 1
    public function getTraits(): array
1355
    {
1356 1
        return $this->traits;
1357
    }
1358
1359
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $visibility should have a doc-comment as per coding-style.
Loading history...
1360
     * Sets the class fields visibility for the entity (can either be private or protected).
1361
     *
1362
     * @throws \InvalidArgumentException
1363
     *
1364
     * @api
1365
     */
1366 2
    public function setFieldVisibility(string $visibility): void
1367
    {
1368 2
        if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) {
1369
            throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility);
1370
        }
1371
1372 2
        $this->fieldVisibility = $visibility;
1373 2
    }
1374
1375
    /**
1376
     * Get the field visibility
1377
     */
1378 1
    public function getFieldVisibility(): string
1379
    {
1380 1
        return $this->fieldVisibility;
1381
    }
1382
1383
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $bool should have a doc-comment as per coding-style.
Loading history...
1384
     * Sets whether or not to try and update the entity if it already exists.
1385
     *
1386
     * @api
1387
     */
1388 1
    public function setUpdateEntityIfExists(bool $bool): void
1389
    {
1390 1
        $this->updateEntityIfExists = $bool;
1391 1
    }
1392
1393
    /**
1394
     * Get the flag for updating the entity
1395
     */
1396 1
    public function getUpdateEntityIfExists(): bool
1397
    {
1398 1
        return $this->updateEntityIfExists;
1399
    }
1400
1401
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $bool should have a doc-comment as per coding-style.
Loading history...
1402
     * Sets whether or not to regenerate the entity if it exists.
1403
     *
1404
     * @api
1405
     */
1406 1
    public function setRegenerateEntityIfExists(bool $bool): void
1407
    {
1408 1
        $this->regenerateEntityIfExists = $bool;
1409 1
    }
1410
1411
    /**
1412
     * Get the flag for regenerating entity
1413
     */
1414 1
    public function getRegenerateEntityIfExists(): bool
1415
    {
1416 1
        return $this->regenerateEntityIfExists;
1417
    }
1418
1419
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $bool should have a doc-comment as per coding-style.
Loading history...
1420
     * Sets whether or not to generate stub methods for the entity.
1421
     *
1422
     * @api
1423
     */
1424 2
    public function setGenerateStubMethods(bool $bool): void
1425
    {
1426 2
        $this->generateEntityStubMethods = $bool;
1427 2
    }
1428
1429
    /**
1430
     * Get the flag for generating stub methods
1431
     */
1432 1
    public function getGenerateStubMethods(): bool
1433
    {
1434 1
        return $this->generateEntityStubMethods;
1435
    }
1436
1437
    /**
1438
     * Sets whether or not the get mehtod will be suffixed by 'get'.
1439
     *
1440
     * @param bool $bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
1441
     *
1442
     * @return void
0 ignored issues
show
introduced by
If there is no return value for a function, there must not be a @return tag.
Loading history...
1443
     *
1444
     * @api
1445
     */
1446 2
    public function useGetShortcutMethod($bool = true)
1447
    {
1448 2
        $this->useGetShortcutMethod = $bool;
1449 2
    }
1450
1451
    /**
1452
     * Get the flag for get mehtod name.
1453
     */
1454 1
    public function getUseGetShortcutMethod(): bool
1455
    {
1456 1
        return $this->useGetShortcutMethod;
1457
    }
1458
1459
    /**
1460
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
1461
     */
1462
    public function getUseTypedProperties(): bool
1463
    {
1464
        return $this->useTypedProperties;
1465
    }
1466
1467
    /**
1468
     * Enable usage of php 7.4 type properties
1469
     *
1470
     * @param bool $useTypedProperties
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
1471
     */
1472 7
    public function useTypedProperties(bool $useTypedProperties = true): void
1473
    {
1474 7
        $this->useTypedProperties = $useTypedProperties;
1475 7
    }
1476
}
1477