Passed
Pull Request — master (#10)
by Sébastien
09:47
created

PropertyMetadataBuilder::configure()   B

Complexity

Conditions 10
Paths 10

Size

Total Lines 41
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 11.5625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 23
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 41
ccs 18
cts 24
cp 0.75
crap 11.5625
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Bdf\Serializer\Metadata\Builder;
4
5
use Bdf\Serializer\Context\DenormalizationContext;
6
use Bdf\Serializer\Context\NormalizationContext;
7
use Bdf\Serializer\Metadata\PropertyMetadata;
8
use Bdf\Serializer\PropertyAccessor\MethodAccessor;
9
use Bdf\Serializer\PropertyAccessor\PropertyAccessorInterface;
10
use Bdf\Serializer\Type\TypeFactory;
11
use Bdf\Serializer\Util\AccessorGuesser;
12
use ReflectionClass;
13
use ReflectionException;
14
15
/**
16
 * PropertyMetadataBuilder
17
 *
18
 * @author  Seb
19
 */
20
class PropertyMetadataBuilder
21
{
22
    /**
23
     * The owner reflection class
24
     *
25
     * @var ReflectionClass
26
     */
27
    private $reflection;
28
29
    /**
30
     * The property name
31
     *
32
     * @var string
33
     */
34
    private $name;
35
36
    /**
37
     * The property alias
38
     *
39
     * @var string|null
40
     */
41
    private $alias;
42
43
    /**
44
     * The property type
45
     *
46
     * @var string|null
47
     */
48
    private $type;
49
50
    /**
51
     * The property groups
52
     *
53
     * @var array
54
     */
55
    private $groups = [];
56
57
    /**
58
     * The property accessor
59
     *
60
     * @var PropertyAccessorInterface|array|null
61
     */
62
    private $customAccessor;
63
64
    /**
65
     * The getter accessor
66
     *
67
     * @var PropertyAccessorInterface|string|null
68
     */
69
    private $getter;
70
71
    /**
72
     * The setter accessor
73
     *
74
     * @var PropertyAccessorInterface|string|null
75
     */
76
    private $setter;
77
78
    /**
79
     * The version when the property has been added.
80
     *
81
     * @var string|null
82
     */
83
    private $since;
84
85
    /**
86
     * The version when the property has been removed.
87
     *
88
     * @var string|null
89
     */
90
    private $until;
91
92
    /**
93
     * The read only state of the property.
94
     *
95
     * @var bool
96
     */
97
    private $readOnly = false;
98
99
    /**
100
     * The inline state of the property.
101
     *
102
     * @var bool
103
     */
104
    private $inline = false;
105
106
    /**
107
     * The context options for normalization.
108
     *
109
     * @var null|array
110
     */
111
    private $normalizationOptions;
112
113
    /**
114
     * The context options for denormalization.
115
     *
116
     * @var null|array
117
     */
118
    private $denormalizationOptions;
119
120
    /**
121
     * PropertyMetadataBuilder constructor.
122
     *
123
     * @param ReflectionClass $reflection
124
     * @param string $name
125
     */
126 228
    public function __construct(ReflectionClass $reflection, string $name)
127
    {
128 228
        $this->reflection = $reflection;
129 228
        $this->name = $name;
130
    }
131
132
    /**
133
     * Build the property metadata
134
     *
135
     * @return PropertyMetadata
136
     */
137 228
    public function build(): PropertyMetadata
138
    {
139 228
        $property = new PropertyMetadata($this->reflection->name, $this->name);
140 228
        $property->setType(TypeFactory::createType($this->type));
141 228
        $property->setAlias($this->alias ?: $this->name);
142 228
        $property->setGroups($this->groups);
143 228
        $property->setAccessor($this->buildAccessor());
144 228
        $property->setSince($this->since);
145 228
        $property->setUntil($this->until);
146 228
        $property->setReadOnly($this->readOnly === true);
147 228
        $property->setInline($this->inline === true);
148 228
        $property->setNormalizationOptions($this->normalizationOptions);
149 228
        $property->setDenormalizationOptions($this->denormalizationOptions);
150
151 228
        $defaultValues = $this->reflection->getDefaultProperties();
152 228
        if (isset($defaultValues[$this->name])) {
153 28
            $property->setDefaultValue($defaultValues[$this->name]);
154
        }
155
156
        // Tag the property as typed property
157 228
        if (PHP_VERSION_ID >= 70400) {
158
            try {
159 228
                $property->isPhpTyped = $this->reflection->getProperty($this->name)->hasType();
160 10
            } catch (ReflectionException $exception) {
161
                // The property could be virtual.
162
            }
163
        }
164
165 228
        $this->clear();
166
167 228
        return $property;
168
    }
169
170
    /**
171
     * Build the property accessor
172
     *
173
     * @return PropertyAccessorInterface
174
     */
175 228
    private function buildAccessor(): PropertyAccessorInterface
176
    {
177 228
        if ($this->customAccessor instanceof PropertyAccessorInterface) {
178
            return $this->customAccessor;
179
        }
180
181 228
        if ($this->setter !== null || $this->getter !== null) {
182 16
            return AccessorGuesser::getMethodAccessor($this->reflection, $this->name, $this->getter, $this->setter, $this->readOnly === true);
183
        }
184
185 212
        return AccessorGuesser::getPropertyAccessor($this->reflection, $this->name);
186
    }
187
188
    /**
189
     * Set the property type
190
     *
191
     * @param null|string $type
192
     *
193
     * @return $this
194
     */
195 188
    public function type(?string $type)
196
    {
197 188
        $this->type = $type;
198
199 188
        return $this;
200
    }
201
202
    /**
203
     * Set the property type as collection
204
     *
205
     * @return $this
206
     */
207 8
    public function collection()
208
    {
209 8
        $this->type .= '[]';
210
211 8
        return $this;
212
    }
213
214
    /**
215
     * Set the property type as collection of a given type
216
     *
217
     * @param string $subType
218
     *
219
     * @return $this
220
     */
221 4
    public function collectionOf($subType)
222
    {
223 4
        return $this->type($subType)->collection();
224
    }
225
226
    /**
227
     * Set the property type as collection wrapper of a given type
228
     *
229
     * @param string $subType
230
     *
231
     * @return $this
232
     */
233 2
    public function wrapperOf($subType)
234
    {
235 2
        $this->type .= "<$subType>";
236
237 2
        return $this;
238
    }
239
240
    /**
241
     * Set the property alias
242
     *
243
     * @param string|null $alias
244
     *
245
     * @return $this
246
     */
247 50
    public function alias($alias)
248
    {
249 50
        $this->alias = $alias;
250
251 50
        return $this;
252
    }
253
254
    /**
255
     * Get the property alias
256
     *
257
     * @return string|null
258
     */
259 178
    public function getAlias(): ?string
260
    {
261 178
        return $this->alias;
262
    }
263
264
    /**
265
     * Set the property groups
266
     *
267
     * @param array $groups
268
     *
269
     * @return $this
270
     */
271 62
    public function groups(array $groups)
272
    {
273 62
        $this->groups = $groups;
274
275 62
        return $this;
276
    }
277
278
    /**
279
     * Add a property group
280
     *
281
     * @param string $group
282
     *
283
     * @return $this
284
     */
285 2
    public function addGroup(string $group)
286
    {
287 2
        $this->groups[] = $group;
288
289 2
        return $this;
290
    }
291
292
    /**
293
     * Set the property accessor
294
     *
295
     * @param PropertyAccessorInterface $accessor
296
     *
297
     * @return $this
298
     */
299
    public function accessor(PropertyAccessorInterface $accessor)
300
    {
301
        $this->customAccessor = $accessor;
302
303
        return $this;
304
    }
305
306
    /**
307
     * Set the property accessor
308
     *
309
     * A accessor as string will be considered as a method
310
     *
311
     * @param PropertyAccessorInterface|string $getter
312
     *
313
     * @return $this
314
     */
315 12
    public function readWith($getter)
316
    {
317 12
        $this->getter = $getter;
318
319 12
        return $this;
320
    }
321
322
    /**
323
     * Set the property accessor
324
     *
325
     * @param PropertyAccessorInterface|string $setter
326
     *
327
     * @return $this
328
     */
329 10
    public function writeWith($setter)
330
    {
331 10
        $this->setter = $setter;
332
333 10
        return $this;
334
    }
335
336
    /**
337
     * Set a virtual property.
338
     *
339
     * @param string $getter
340
     *
341
     * @return $this
342
     */
343 2
    public function virtual(string $getter)
344
    {
345 2
        $this->readWith($getter);
346 2
        $this->readOnly();
347
348 2
        return $this;
349
    }
350
351
    /**
352
     * Set the version when the property has been added
353
     *
354
     * @param string $version
355
     *
356
     * @return $this
357
     */
358 52
    public function since(string $version)
359
    {
360 52
        $this->since = $version;
361
362 52
        return $this;
363
    }
364
365
    /**
366
     * Set the property read only.
367
     *
368
     * @param bool $flag
369
     *
370
     * @return $this
371
     */
372 10
    public function readOnly(bool $flag = true)
373
    {
374 10
        $this->readOnly = $flag;
375
376 10
        return $this;
377
    }
378
379
    /**
380
     * Set the property inline.
381
     * The properties of this property will be added as the same level.
382
     *
383
     * @param bool $flag
384
     *
385
     * @return $this
386
     */
387 10
    public function inline(bool $flag = true)
388
    {
389 10
        $this->inline = $flag;
390
391 10
        return $this;
392
    }
393
394
    /**
395
     * Set the version when the property has been removed
396
     *
397
     * @param string $version
398
     *
399
     * @return $this
400
     */
401 42
    public function until(string $version)
402
    {
403 42
        $this->until = $version;
404
405 42
        return $this;
406
    }
407
408
    /**
409
     * Add a normalization option
410
     *
411
     * @param string $option
412
     * @param mixed $value
413
     *
414
     * @return $this
415
     */
416 24
    public function normalization(string $option, $value)
417
    {
418 24
        $this->normalizationOptions[$option] = $value;
419
420 24
        return $this;
421
    }
422
423
    /**
424
     * Add a denormalization option
425
     *
426
     * @param string $option
427
     * @param mixed $value
428
     *
429
     * @return $this
430
     */
431 16
    public function denormalization(string $option, $value)
432
    {
433 16
        $this->denormalizationOptions[$option] = $value;
434
435 16
        return $this;
436
    }
437
438
    /**
439
     * Set the date time format
440
     *
441
     * @param string $format
442
     *
443
     * @return $this
444
     */
445 10
    public function dateFormat(string $format)
446
    {
447 10
        $this->normalization(NormalizationContext::DATETIME_FORMAT, $format);
448 10
        $this->denormalization(DenormalizationContext::DATETIME_FORMAT, $format);
449
450 10
        return $this;
451
    }
452
453
    /**
454
     * Set the internal date timezone
455
     *
456
     * @param string $timezone
457
     *
458
     * @return $this
459
     */
460 10
    public function timezone(string $timezone)
461
    {
462 10
        $this->denormalization(DenormalizationContext::TIMEZONE, $timezone);
463
464 10
        return $this;
465
    }
466
467
    /**
468
     * Set the serialized date timezone
469
     *
470
     * @param string $timezone
471
     *
472
     * @return $this
473
     */
474 10
    public function toTimezone(string $timezone)
475
    {
476 10
        $this->normalization(NormalizationContext::TIMEZONE, $timezone);
477 10
        $this->denormalization(DenormalizationContext::TIMEZONE_HINT, $timezone);
478
479 10
        return $this;
480
    }
481
482
    /**
483
     * The property will be normalize if its value is null
484
     *
485
     * @param bool $flag
486
     *
487
     * @return $this
488
     */
489 10
    public function conserveNull(bool $flag = true)
490
    {
491 10
        $this->normalization(NormalizationContext::NULL, $flag);
492
493 10
        return $this;
494
    }
495
496
    /**
497
     * Keep the default value of the property
498
     *
499
     * @param bool $flag
500
     *
501
     * @return $this
502
     */
503 8
    public function conserveDefault(bool $flag = false)
504
    {
505 8
        $this->normalization(NormalizationContext::REMOVE_DEFAULT_VALUE, $flag);
506
507 8
        return $this;
508
    }
509
510
    /**
511
     * Import options in the builder
512
     * Legacy method, should not be used
513
     *
514
     * @param array $values
515
     *
516
     * @return $this
517
     */
518 178
    public function configure(array $values)
519
    {
520 178
        foreach ($values as $property => $value) {
521 46
            switch ($property) {
522 46
                case 'type':
523 2
                    $this->type($value);
524 2
                    break;
525
526 46
                case 'group':
527 44
                case 'groups':
528 46
                    $this->groups((array)$value);
529 46
                    break;
530
531 44
                case 'alias':
532 44
                case 'serializedName':
533 10
                    $this->alias($value);
534 10
                    break;
535
536 34
                case 'since':
537 34
                    $this->since($value);
538 34
                    break;
539
540
                case 'until':
541
                    $this->until($value);
542
                    break;
543
544
                case 'readOnly':
545
                    $this->readOnly((bool)$value);
546
                    break;
547
548
//                case 'maxDepth':
549
//                    $this->$property = $value;
550
//                    break;
551
//
552
//                case 'inline':
553
//                    $this->$property = (bool)$value;
554
//                    break;
555
            }
556
        }
557
558 178
        return $this;
559
    }
560
561
    /**
562
     * Clear all reference
563
     */
564 228
    private function clear(): void
565
    {
566 228
        $this->customAccessor = $this->setter = $this->getter = null;
567
    }
568
}
569