PropertyMetadataBuilder::configure()   B
last analyzed

Complexity

Conditions 10
Paths 10

Size

Total Lines 41
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 11.7759

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 17
cts 23
cp 0.7391
crap 11.7759
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 240
    public function __construct(ReflectionClass $reflection, string $name)
127
    {
128 240
        $this->reflection = $reflection;
129 240
        $this->name = $name;
130
    }
131
132
    /**
133
     * Build the property metadata
134
     *
135
     * @return PropertyMetadata
136
     */
137 240
    public function build(): PropertyMetadata
138
    {
139 240
        $property = new PropertyMetadata($this->reflection->name, $this->name);
140 240
        $property->setType(TypeFactory::createType($this->type));
141 240
        $property->setAlias($this->alias ?: $this->name);
142 240
        $property->setGroups($this->groups);
143 240
        $property->setAccessor($this->buildAccessor());
144 240
        $property->setSince($this->since);
145 240
        $property->setUntil($this->until);
146 240
        $property->setReadOnly($this->readOnly === true);
147 240
        $property->setInline($this->inline === true);
148 240
        $property->setNormalizationOptions($this->normalizationOptions);
149 240
        $property->setDenormalizationOptions($this->denormalizationOptions);
150
151 240
        $defaultValues = $this->reflection->getDefaultProperties();
152 240
        if (array_key_exists($this->name, $defaultValues)) {
153 214
            $property->setDefaultValue($defaultValues[$this->name]);
154
        }
155
156
        // Tag the property as typed property
157 240
        if (PHP_VERSION_ID >= 70400) {
158
            try {
159 240
                $property->isPhpTyped = $this->reflection->getProperty($this->name)->hasType();
160 10
            } catch (ReflectionException $exception) {
161
                // The property could be virtual.
162
            }
163
        }
164
165 240
        $this->clear();
166
167 240
        return $property;
168
    }
169
170
    /**
171
     * Build the property accessor
172
     *
173
     * @return PropertyAccessorInterface
174
     */
175 240
    private function buildAccessor(): PropertyAccessorInterface
176
    {
177 240
        if ($this->customAccessor instanceof PropertyAccessorInterface) {
178
            return $this->customAccessor;
179
        }
180
181 240
        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 224
        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 200
    public function type(?string $type)
196
    {
197 200
        $this->type = $type;
198
199 200
        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 54
    public function alias($alias)
248
    {
249 54
        $this->alias = $alias;
250
251 54
        return $this;
252
    }
253
254
    /**
255
     * Get the property alias
256
     *
257
     * @return string|null
258
     */
259 190
    public function getAlias(): ?string
260
    {
261 190
        return $this->alias;
262
    }
263
264
    /**
265
     * Set the property groups
266
     *
267
     * @param array $groups
268
     *
269
     * @return $this
270
     */
271 66
    public function groups(array $groups)
272
    {
273 66
        $this->groups = $groups;
274
275 66
        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 56
    public function since(string $version)
359
    {
360 56
        $this->since = $version;
361
362 56
        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 46
    public function until(string $version)
402
    {
403 46
        $this->until = $version;
404
405 46
        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 190
    public function configure(array $values)
519
    {
520 190
        foreach ($values as $property => $value) {
521
            switch ($property) {
522 50
                case 'type':
523 2
                    $this->type($value);
524 2
                    break;
525
526 50
                case 'group':
527 48
                case 'groups':
528 50
                    $this->groups((array)$value);
529 50
                    break;
530
531 48
                case 'alias':
532 48
                case 'serializedName':
533 10
                    $this->alias($value);
534 10
                    break;
535
536 38
                case 'since':
537 38
                    $this->since($value);
538 38
                    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 190
        return $this;
559
    }
560
561
    /**
562
     * Clear all reference
563
     */
564 240
    private function clear(): void
565
    {
566 240
        $this->customAccessor = $this->setter = $this->getter = null;
567
    }
568
}
569