Completed
Push — master ( 1c36bc...5b21ea )
by Vincent
06:59
created

HydratorGenerator::getValidVariableName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 3
c 1
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Bdf\Prime\Entity\Hydrator;
4
5
use Bdf\Prime\Entity\Hydrator\Generator\AccessorResolver;
6
use Bdf\Prime\Entity\Hydrator\Generator\AttributeInfo;
7
use Bdf\Prime\Entity\Hydrator\Generator\AttributesResolver;
8
use Bdf\Prime\Entity\Hydrator\Generator\ClassAccessor;
9
use Bdf\Prime\Entity\Hydrator\Generator\CodeGenerator;
10
use Bdf\Prime\Entity\Hydrator\Generator\EmbeddedInfo;
11
use Bdf\Prime\Entity\Hydrator\Generator\TypeAccessor;
12
use Bdf\Prime\Exception\HydratorException;
13
use Bdf\Prime\Mapper\Mapper;
14
use Bdf\Prime\Mapper\SingleTableInheritanceMapper;
15
use Bdf\Prime\ServiceLocator;
16
17
/**
18
 * Generator for hydrator classes
19
 */
20
class HydratorGenerator
21
{
22
    /**
23
     * The stub hydrator file name
24
     *
25
     * @var string
26
     */
27
    private $stub = __DIR__.'/Generator/stubs/hydrator.php.stub';
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
28
29
    /**
30
     * @var CodeGenerator
31
     */
32
    private $code;
33
34
    /**
35
     * @var ClassAccessor
36
     */
37
    private $accessor;
38
39
    /**
40
     * @var AccessorResolver
41
     */
42
    private $accessors;
43
44
    /**
45
     * @var AttributesResolver
46
     */
47
    private $resolver;
48
49
    /**
50
     * @var ServiceLocator
51
     */
52
    private $prime;
53
54
    /**
55
     * @var Mapper
56
     */
57
    private $mapper;
58
59
    /**
60
     * @var string
61
     */
62
    private $className;
63
64
    /**
65
     * @var string
66
     */
67
    private $interface = HydratorGeneratedInterface::class;
68
69
    /**
70
     * @var array
71
     */
72
    private $embeddedHydrators = [];
73
74
75
    /**
76
     * HydratorGenerator constructor.
77
     *
78
     * @param ServiceLocator $prime
79
     * @param Mapper $mapper
80
     * @param string $className
81
     *
82
     * @throws HydratorException
0 ignored issues
show
introduced by
Comment missing for @throws tag in function comment
Loading history...
83
     */
84 94
    public function __construct(ServiceLocator $prime, Mapper $mapper, $className)
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before function; 2 found
Loading history...
85
    {
86 94
        $this->prime = $prime;
87 94
        $this->mapper = $mapper;
88 94
        $this->className = $className;
89
90 94
        $this->code = new CodeGenerator();
91 94
        $this->accessor = $this->makeAccessor();
92 94
        $this->resolver = new AttributesResolver($mapper, $prime);
93 94
        $this->accessors = new AccessorResolver($this->accessor, $this->resolver, $this->code);
94 94
    }
95
96 94
    private function makeAccessor()
0 ignored issues
show
Coding Style introduced by
Private method name "HydratorGenerator::makeAccessor" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing doc comment for function makeAccessor()
Loading history...
introduced by
Missing function doc comment
Loading history...
97
    {
98 94
        $subClass = [];
99
100
        // The mapper has inheritance, and it's not the inherited one
101
        if (
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after opening bracket; newline found
Loading history...
Coding Style introduced by
First condition of a multi-line IF statement must directly follow the opening parenthesis
Loading history...
102 94
            $this->mapper instanceof SingleTableInheritanceMapper
0 ignored issues
show
Coding Style introduced by
Each line in a multi-line IF statement must begin with a boolean operator
Loading history...
103 94
            && !in_array(get_class($this->mapper), $this->mapper->getDiscriminatorMap())
104
        ) {
105 5
            $subClass = $this->mapper->getEntityMap();
106
        }
107
108 94
        return new ClassAccessor($this->className, ClassAccessor::SCOPE_INHERIT, $subClass);
109
    }
110
111
    /**
112
     * Get the hydrator namespace
113
     *
114
     * @return string
115
     */
116 94
    public function hydratorNamespace()
117
    {
118 94
        return implode('\\', array_slice(explode('\\', $this->className), 0, -1));
119
    }
120
121
    /**
122
     * Get the hydrator class name, without namespace
123
     *
124
     * @return string
125
     */
126 94
    public function hydratorClassName()
127
    {
128 94
        return 'Hydrator_' . str_replace('\\', '_', $this->className);
129
    }
130
131
    /**
132
     * Get the full class name (namespace + class name)
133
     *
134
     * @return string
135
     */
136 76
    public function hydratorFullClassName()
137
    {
138 76
        return $this->hydratorNamespace() . '\\' . $this->hydratorClassName();
139
    }
140
141
    /**
142
     * Generate the hydrator class code
143
     *
144
     * @return string
145
     */
146 27
    public function generate()
147
    {
148 27
        $this->resolveHydrators();
149
150 27
        return $this->hydratorTemplate();
151
    }
152
153
    /**
154
     * Resolve hydrator properties
155
     */
156 27
    protected function resolveHydrators()
157
    {
158 27
        $classes = [];
159
160 27
        foreach ($this->resolver->rootEmbeddeds() as $embedded) {
161 22
            foreach ($embedded->classes() as $class) {
162
                // For now (1.6) hydrators are used only for hydrate / extract. Remove the isImportable if hydrator are use in mapping context.
163 22
                if ($class === $this->className || !$this->resolver->isEntity($class) || $this->resolver->isImportable($class)) {
164 21
                    continue;
165
                }
166
167 1
                if (!isset($classes[$class])) {
168 1
                    $classes[$class] = true;
169
170 1
                    $property = '__' . str_replace('\\', '_', $class) . '_hydrator';
171 22
                    $this->embeddedHydrators[$class] = $property;
172
                }
173
            }
174
        }
175 27
    }
176
177
    /**
178
     * Get the hydrator class template
179
     *
180
     * @return string
181
     */
182 27
    protected function hydratorTemplate()
183
    {
184 27
        return $this->code->generate($this->stub, [
185 27
            'namespace'                 => $this->code->namespace($this->hydratorNamespace()),
186 27
            'normalizedEntityClassName' => $this->normalizeClassName($this->className),
187 27
            'hydratorClassName'         => $this->hydratorClassName(),
188 27
            'hydratorInterface'         => $this->normalizeClassName($this->interface),
189 27
            'properties'                => $this->code->properties($this->embeddedHydrators),
190 27
            'constructor'               => $this->code->simpleConstructor($this->embeddedHydrators),
191 27
            'hydrateBody'               => $this->generateHydrateBody(),
192 25
            'extractBody'               => $this->generateExtractBody(),
193 25
            'flatExtractBody'           => $this->generateFlatExtract(),
194 25
            'flatHydrateBody'           => $this->generateFlatHydrate(),
195 25
            'extractOneBody'            => $this->generateExtractOneBody(),
196 25
            'hydrateOneBody'            => $this->generateHydrateOneBody(),
197 25
            'entityClassName'           => $this->className,
198 25
            'embeddedClasses'           => $this->generateEmbeddedClasses(),
199
        ]);
200
    }
201
202
    /**
203
     * Generate the hydrate() method body
204
     *
205
     * @return string
206
     */
207 27
    protected function generateHydrateBody()
208
    {
209 27
        $out = '';
210
211 27
        foreach ($this->resolver->rootAttributes() as $attribute) {
212
            $out .= <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
213 27
if (isset(\$data['{$attribute->name()}'])) {
214 27
{$this->code->indent($this->generateAttributeHydrate($attribute), 1)}
215
}
216
217
218
PHP;
219
        }
220
221 25
        return $out;
222
    }
223
224
    /**
225
     * Generate the hydration code for one attribute
226
     *
227
     * @param AttributeInfo $attribute
228
     *
229
     * @return string
230
     */
231 27
    protected function generateAttributeHydrate(AttributeInfo $attribute)
232
    {
233 27
        $out = '';
234
235 27
        $value = '$data[\''.$attribute->name().'\']';
236
237 27
        if ($attribute->isEmbedded()) {
238
            $out .= <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
239 22
if (is_array({$value})) {
240 22
{$this->code->indent($this->generateEmbeddedHydrate($attribute), 1)}
241
} else {
242 22
    {$this->accessor->setter('$object', $attribute->property(), $value)};
243
}
244
PHP;
245
        } else {
246 25
            $out .= $this->accessor->setter('$object', $attribute->property(), $value).';';
247
        }
248
249 25
        return $out;
250
    }
251
252
    /**
253
     * Generate embedded hydrator
254
     *
255
     * @param AttributeInfo $attribute
256
     *
257
     * @return string
258
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag in function comment
Loading history...
259 22
    protected function generateEmbeddedHydrate(AttributeInfo $attribute)
260
    {
261
        // We can have multiple entity classes for one attribute : morph
262 22
        $varName = '$__rel_' . str_replace('.', '_', $attribute->name());
263
264 22
        $hydrators = [];
265
266 22
        foreach ($attribute->embedded()->classes() as $class) {
267 22
            if ($this->resolver->isImportable($class)) {
268
                // For other objects (Collections) use import() method
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
269 21
                $hydrators[$this->normalizeClassName($class)] = "{$varName}->import(\$data['{$attribute->name()}']);";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $varName 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
270 1
            } elseif ($this->resolver->isEntity($class)) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
271
                // For Entities, use hydrators
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
272 1
                $hydrators[$this->normalizeClassName($class)] = "{$this->generateEmbeddedHydrator($class)}->hydrate({$varName}, \$data['{$attribute->name()}']);";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $class 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $varName 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
273
            } else {
274 22
                throw new HydratorException($class, 'Cannot generate embedded hydration for the property "'.$attribute->name().'"');
275
            }
276
        }
277
278
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
279 22
{$varName} = {$this->accessor->getter('$object', $attribute->property())};
280
281 22
{$this->code->switchIntanceOf($varName, $hydrators)}
282
PHP;
283
284
    }
0 ignored issues
show
Coding Style introduced by
Function closing brace must go on the next line following the body; found 1 blank lines before brace
Loading history...
285
286
    /**
287
     * @param string $class
288
     *
289
     * @return string
290
     */
291 1
    protected function generateEmbeddedHydrator($class)
292
    {
293 1
        if ($class === $this->className) {
294
            return '$this';
295
        }
296
297 1
        return '$this->' . $this->embeddedHydrators[$class];
298
    }
299
300
    /**
301
     * Add the root namespace
302
     *
303
     * @param string $className
304
     *
305
     * @return string
306
     */
307 27
    protected function normalizeClassName($className)
308
    {
309 27
        return '\\' . ltrim($className, '\\');
310
    }
311
312
    /**
313
     * Generate the embedded entities classes list
314
     *
315
     * @return string
316
     */
317 25
    protected function generateEmbeddedClasses()
318
    {
319 25
        return $this->code->export(array_keys($this->embeddedHydrators));
320
    }
321
322
    /**
323
     * Generate the {@link HydratorInterface::extract()} method's body
324
     *
325
     * @return string
326
     */
327 25
    protected function generateExtractBody()
328
    {
329
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
330
if (empty(\$attributes)) {
331 25
{$this->code->indent($this->generateExtractAll(), 1)}
332
} else {
333 25
{$this->code->indent($this->generateExtractSelected(), 1)}
334
}
335
PHP;
336
337
    }
0 ignored issues
show
Coding Style introduced by
Function closing brace must go on the next line following the body; found 1 blank lines before brace
Loading history...
338
339
    /**
340
     * Generate extract method's code for extract all attributes
341
     *
342
     * @return string
343
     */
344 25
    protected function generateExtractAll()
345
    {
346 25
        $lines = [];
347
348 25
        foreach ($this->resolver->rootAttributes() as $attribute) {
349 25
            $lines[] = "'{$attribute->name()}' => ({$this->generateExtractValue($attribute)})";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
350
        }
351
352 25
        return 'return [' . implode(', ', $lines) . '];';
353
    }
354
355
    /**
356
     * Generate extract method's code for extract select attributes
357
     *
358
     * @return string
359
     */
360 25
    protected function generateExtractSelected()
361
    {
362 25
        $extracts = '';
363
364 25
        foreach ($this->resolver->rootAttributes() as $attribute) {
365
            $extracts .= <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
366 25
if (isset(\$attributes['{$attribute->name()}'])) {
367 25
    \$values['{$attribute->name()}'] = {$this->generateExtractValue($attribute)};
368
}
369
370
PHP;
371
        }
372
373
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
374
\$attributes = array_flip(\$attributes);
375
\$values = [];
376
377 25
{$extracts}
378
379
return \$values;
380
PHP;
381
    }
382
383
    /**
384
     * Generate the extraction code for one attribute
385
     *
386
     * @param AttributeInfo $attribute
387
     *
388
     * @return string
389
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag in function comment
Loading history...
390 25
    protected function generateExtractValue(AttributeInfo $attribute)
391
    {
392 25
        $line = '';
393
394 25
        if ($attribute->isEmbedded()) {
395 22
            $varName = '$__rel_' . str_replace('.', '_', $attribute->name());
396 22
            $line .= '(' . $varName . ' = '.$this->accessor->getter('$object', $attribute->property()) . ") === null ? null : ";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal ) === null ? null : 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...
397
398 22
            foreach ($attribute->embedded()->classes() as $class) {
399 22
                if ($this->resolver->isImportable($class)) {
400 21
                    $line .= "({$varName} instanceof {$this->normalizeClassName($class)} ? {$varName}->export() : ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $varName 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $class 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...
401 1
                } elseif ($this->resolver->isEntity($class)) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
402 1
                    $line .= "({$varName} instanceof {$this->normalizeClassName($class)} ? {$this->generateEmbeddedHydrator($class)}->extract({$varName}) : ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $varName 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $class 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...
403
                } else {
404 22
                    throw new HydratorException($class, 'Cannot generate embedded hydration for the property "'.$attribute->name().'"');
405
                }
406
            }
407
408 22
            $line .= $varName.str_repeat(')', count($attribute->embedded()->classes()));
409
410 22
            return $line;
411
        }
412
413 23
        $line .= $this->accessor->getter('$object', $attribute->property());
414
415 23
        return $line;
416
    }
417
418
    /**
419
     * Generate the flatExtract (i.e. Mapper::prepareToRepository) method body
420
     *
421
     * @return string
422
     */
423 25
    protected function generateFlatExtract()
424
    {
425
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
426
if (empty(\$attributes)) {
427 25
{$this->code->indent($this->generateFlatExtractAll(), 1)}
428
} else {
429 25
{$this->code->indent($this->generateFlatExtractSelected(), 1)}
430
}
431
PHP;
432
    }
433
434
    /**
435
     * Generate extract method's code for extract all attributes
436
     *
437
     * @return string
438
     */
439 25
    protected function generateFlatExtractAll()
440
    {
441 25
        $lines = [];
442 25
        $embeddeds = [];
443
444 25
        foreach ($this->resolver->attributes() as $attribute) {
445 25
            if ($attribute->isEmbedded()) {
446 16
                $accessor = $this->accessors->embedded($attribute->embedded());
447
448 16
                $embeddeds[] = <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
449 16
{$accessor->getEmbedded('$__embedded')}
0 ignored issues
show
Coding Style introduced by
Variable "__embedded" is not in valid camel caps format
Loading history...
450 16
\$data['{$attribute->name()}'] = {$accessor->getter('$__embedded', $attribute->property())};
0 ignored issues
show
Coding Style introduced by
Variable "__embedded" is not in valid camel caps format
Loading history...
451
PHP;
452
            } else {
453 25
                $lines[] = "'{$attribute->name()}' => ({$this->accessor->getter('$object', $attribute->property())})";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
454
            }
455
        }
456
457 25
        $lines = implode(', ', $lines);
458 25
        $embeddeds = implode(PHP_EOL, $embeddeds);
459
460
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
461 25
\$data = [{$lines}];
462 25
{$embeddeds}
463
464
return \$data;
465
PHP;
466
    }
467
468
    /**
469
     * Generate the extract method's code for extract selected attributes
470
     *
471
     * @return string
472
     */
473 25
    protected function generateFlatExtractSelected()
474
    {
475 25
        $lines = '';
476
477 25
        foreach ($this->resolver->attributes() as $attribute) {
478 25
            if ($attribute->isEmbedded()) {
479 16
                $accessor = $this->accessors->embedded($attribute->embedded());
480
481
                $code = <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
482 16
{$accessor->getEmbedded('$__embedded')}
0 ignored issues
show
Coding Style introduced by
Variable "__embedded" is not in valid camel caps format
Loading history...
483 16
\$data['{$attribute->name()}'] = {$accessor->getter('$__embedded', $attribute->property())};
0 ignored issues
show
Coding Style introduced by
Variable "__embedded" is not in valid camel caps format
Loading history...
484
PHP;
485
            } else {
486 23
                $code = "\$data['{$attribute->name()}'] = {$this->accessor->getter('$object', $attribute->property())};";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
487
            }
488
489
            $lines .= <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
490 25
if (isset(\$attributes['{$attribute->name()}'])) {
491 25
{$this->code->indent($code, 1)}
492
}
493
494
PHP;
495
        }
496
497
        return <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
498
\$data = [];
499
500 25
{$lines}
501
502
return \$data;
503
PHP;
504
    }
505
506
    /**
507
     * Generate the flatHydrate method's body
508
     *
509
     * @return string
510
     */
511 25
    protected function generateFlatHydrate()
512
    {
513 25
        $types = new TypeAccessor($this->code);
514
515 25
        $out = '';
516 25
        $set = [];
517 25
        $relationKeys = [];
518
519 25
        foreach ($this->mapper->relations() as $property => $metadata) {
520 14
            $relationKeys[$metadata['localKey']] = true;
521
        }
522
523 25
        foreach ($this->resolver->attributes() as $attribute) {
524 25
            $set[$attribute->field()] = $this->generateAttributeFlatHydrate($attribute, $relationKeys, $types);
525
        }
526
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
527
528 25
        foreach ($set as $field => $declaration) {
529
            $out .= <<<PHP
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
530 25
if (array_key_exists('{$field}', \$data)) {
531 25
{$this->code->indent($declaration, 1)}
532
}
533
534
535
PHP;
536
        }
537
538 25
        return $types->generateDeclaration().$out;
539
    }
540
541
    /**
542
     * Generate flat hydration for one attribute
543
     *
544
     * @param AttributeInfo $attribute
545
     * @param array $relationKeys
546
     * @param TypeAccessor $types
547
     *
548
     * @return string
549
     */
550 25
    protected function generateAttributeFlatHydrate(AttributeInfo $attribute, array $relationKeys, TypeAccessor $types)
0 ignored issues
show
Unused Code introduced by
The parameter $relationKeys is not used and could be removed. ( Ignorable by Annotation )

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

550
    protected function generateAttributeFlatHydrate(AttributeInfo $attribute, /** @scrutinizer ignore-unused */ array $relationKeys, TypeAccessor $types)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
The method parameter $relationKeys is never used
Loading history...
551
    {
552 25
        $options = '';
553 25
        if ($attribute->phpOptions()) {
554 5
            $options = "\$this->__metadata->fields['{$attribute->field()}']['phpOptions']";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
555
        }
556
557 25
        $target = "\$value";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal \$value 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...
558 25
        $out = $target.' = '.$types->generateFromDatabase($attribute->type(), '$data[\''.$attribute->field().'\']', $options);
559
560 25
        if (!$attribute->isEmbedded()) {
561 23
            return $out."\n".$this->accessor->setter('$object', $attribute->name(), $target, false).';';
562
        }
563
564 16
        return $this->code->lines([
565 16
            $out,
566 16
            $this->accessors
567 16
                ->embedded($attribute->embedded())
0 ignored issues
show
Coding Style introduced by
Space found before object operator
Loading history...
introduced by
Object operator not indented correctly; expected 14 spaces but found 16
Loading history...
568 16
                ->fullSetter($attribute->property(), $target, '$__embedded', '$data').';'
0 ignored issues
show
Coding Style introduced by
Space found before object operator
Loading history...
introduced by
A comma should follow the last multiline array item. Found: ';'
Loading history...
569
        ]);
570
    }
571
572
    /**
573
     * Generate the extractOne() method's body
574
     *
575
     * @return string
576
     */
577 25
    protected function generateExtractOneBody()
578
    {
579 25
        $cases = [];
580
581 25
        foreach ($this->resolver->attributes() as $attribute) {
582 25
            $cases[$attribute->name()] = $this->generateExtractOneCaseAttribute($attribute);
583
        }
584
585 25
        foreach ($this->resolver->embeddeds() as $embedded) {
586 20
            $cases[$embedded->path()] = $this->generateExtractOneCaseEmbedded($embedded);
587
        }
588
589 25
        return $this->code->switch(
590 25
            '$attribute',
591 25
            $cases,
592
            <<<'PHP'
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
593 25
throw new \InvalidArgumentException('Cannot read from attribute "'.$attribute.'" : it\'s not declared');
594
PHP
595
        );
596
    }
597
598
    /**
599
     * Generate one case for extractOne switch, for attribute
600
     *
601
     * @param AttributeInfo $attribute
602
     *
603
     * @return string
604
     */
605 25
    protected function generateExtractOneCaseAttribute(AttributeInfo $attribute)
606
    {
607 25
        if (!$attribute->isEmbedded()) {
608 23
            return "return {$this->accessor->getter('$object', $attribute->property())};";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $this 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...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $attribute 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...
609
        }
610
611 16
        $accessor = $this->accessors->embedded($attribute->embedded());
612
613 16
        return $accessor->getEmbedded('$__embedded').$this->code->eol().'return '.$accessor->getter('$__embedded', $attribute->property()).';';
614
    }
615
616
    /**
617
     * Generate one case for extractOne switch, for embedded
618
     *
619
     * @param EmbeddedInfo $embedded
620
     *
621
     * @return string
622
     */
623 20
    protected function generateExtractOneCaseEmbedded(EmbeddedInfo $embedded)
624
    {
625 20
        $varName = '$__' . str_replace('.', '_', $embedded->path());
626 20
        $code = $this->accessors->embedded($embedded)->getEmbedded($varName, false);
627
628 20
        return $this->code->lines([$code, 'return '.$varName.';']);
629
    }
630
631
    /**
632
     * Generate hydrateOne() method's body
633
     *
634
     * @return string
635
     */
636 25
    protected function generateHydrateOneBody()
637
    {
638 25
        $cases = [];
639
640 25
        foreach ($this->resolver->attributes() as $attribute) {
641 25
            $cases[$attribute->name()] = $this->generateHydrateOneCaseAttribute($attribute);
642
        }
643
644 25
        foreach ($this->resolver->embeddeds() as $embedded) {
645 20
            $cases[$embedded->path()] = $this->generateHydrateOneCaseEmbedded($embedded);
646
        }
647
648 25
        return $this->code->switch(
649 25
            '$attribute',
650 25
            $cases,
651
            <<<'PHP'
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
652 25
throw new \InvalidArgumentException('Cannot write to attribute "'.$attribute.'" : it\'s not declared');
653
PHP
654
0 ignored issues
show
Coding Style introduced by
Empty lines are not allowed in multi-line function calls
Loading history...
655
        );
656
    }
657
658
    /**
659
     * Generate one case for hydrateOne switch, for attribute
660
     *
661
     * @todo Exception on hydrate unresolved embedded attribute (like MapperHydrator)
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...
662
     *
663
     * @param AttributeInfo $attribute
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
664
     *
665
     * @return string
666
     */
667 25
    protected function generateHydrateOneCaseAttribute($attribute)
0 ignored issues
show
introduced by
Type hint "AttributeInfo" missing for $attribute
Loading history...
668
    {
669 25
        if (!$attribute->isEmbedded()) {
670 23
            return $this->accessor->setter('$object', $attribute->property(), '$value', false).';';
671
        }
672
673 16
        return $this->accessors
674 16
                ->embedded($attribute->embedded())
0 ignored issues
show
Coding Style introduced by
Object operator not indented correctly; expected 12 spaces but found 16
Loading history...
Coding Style introduced by
Space found before object operator
Loading history...
introduced by
Object operator not indented correctly; expected 10 spaces but found 16
Loading history...
675 16
                ->fullSetter($attribute->property(), '$value', '$__embedded').';'
0 ignored issues
show
Coding Style introduced by
Object operator not indented correctly; expected 12 spaces but found 16
Loading history...
Coding Style introduced by
Space found before object operator
Loading history...
676
            ;
0 ignored issues
show
Coding Style introduced by
Space found before semicolon; expected "';';" but found "';'
;"
Loading history...
677
    }
678
679
    /**
680
     * Generate one case for hydrateOne switch, for embedded
681
     *
682
     * @param EmbeddedInfo $embedded
683
     *
684
     * @return string
685
     */
686 20
    protected function generateHydrateOneCaseEmbedded(EmbeddedInfo $embedded)
687
    {
688 20
        if ($embedded->isRoot()) {
689 20
            return $this->accessor->setter('$object', $embedded->path(), '$value', false).';';
690
        }
691
692 3
        return $this->accessors
693 3
                ->embedded($embedded->parent())
0 ignored issues
show
Coding Style introduced by
Object operator not indented correctly; expected 12 spaces but found 16
Loading history...
Coding Style introduced by
Space found before object operator
Loading history...
introduced by
Object operator not indented correctly; expected 10 spaces but found 16
Loading history...
694 3
                ->fullSetter($embedded->property(), '$value').';'
0 ignored issues
show
Coding Style introduced by
Object operator not indented correctly; expected 12 spaces but found 16
Loading history...
Coding Style introduced by
Space found before object operator
Loading history...
695
            ;
0 ignored issues
show
Coding Style introduced by
Space found before semicolon; expected "';';" but found "';'
;"
Loading history...
696
    }
697
}
698