Completed
Push — master ( 161f33...20f2fb )
by Sébastien
09:38
created

PropertyMetadataBuilder::clear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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