Completed
Push — master ( 49ecce...d9744c )
by Maxime
07:20 queued 01:27
created

Enum::__wakeup()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 3
nc 2
nop 0
1
<?php
2
3
/*
4
 * This file is part of the "elao/enum" package.
5
 *
6
 * Copyright (C) Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\Enum\Bridge\Symfony\Validator\Constraint;
12
13
use Elao\Enum\EnumInterface;
14
use Symfony\Component\Validator\Constraints\Choice;
15
use Symfony\Component\Validator\Constraints\ChoiceValidator;
16
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
17
18
/**
19
 * @Annotation
20
 * @Target({"PROPERTY", "METHOD", "ANNOTATION"})
21
 */
22
class Enum extends Choice
23
{
24
    /** @var string */
25
    public $class;
26
27
    /**
28
     * Set to true in order to validate enum values instead of instances.
29
     *
30
     * @var bool
31
     */
32
    public $asValue = false;
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function __construct($options)
38
    {
39
        parent::__construct($options);
40
41
        $this->strict = true;
42
43
        if (!is_a($this->class, EnumInterface::class, true)) {
44
            throw new ConstraintDefinitionException(sprintf(
45
                'The "class" option value must be a class FQCN implementing "%s". "%s" given.',
46
                EnumInterface::class,
47
                $this->class
48
            ));
49
        }
50
51
        // Normalize choices
52
        if (\is_array($this->choices)) {
53
            $choices = [];
54
            foreach ($this->choices as $choiceValue) {
55
                if (false === \call_user_func([$this->class, 'accepts'], $choiceValue)) {
56
                    throw new ConstraintDefinitionException(sprintf(
57
                        'Choice %s is not a valid value for enum type "%s".',
58
                        json_encode($choiceValue),
59
                        $this->class
60
                    ));
61
                }
62
63
                $choices[] = $this->asValue ? $choiceValue : \call_user_func([$this->class, 'get'], $choiceValue);
64
            }
65
66
            $this->choices = $choices;
67
        }
68
69
        // only set the callback if no choice list set
70
        if (!\is_array($this->choices)) {
71
            $this->callback = $this->asValue ? [$this->class, 'values'] : [$this->class, 'instances'];
72
        }
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function validatedBy()
79
    {
80
        return ChoiceValidator::class;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function getDefaultOption()
87
    {
88
        return 'class';
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function getRequiredOptions()
95
    {
96
        return ['class'];
97
    }
98
99
    /**
100
     * Fixup deserialized enum instances by replacing them with actual multiton instances,
101
     * so strict comparison works.
102
     *
103
     * {@inheritdoc}
104
     */
105
    public function __wakeup()
106
    {
107
        if (!$this->asValue && \is_array($this->choices)) {
108
            $this->choices = array_map(function (EnumInterface $enum): EnumInterface {
109
                /** @var string|EnumInterface $enumClass */
110
                $enumClass = \get_class($enum);
111
112
                return $enumClass::get($enum->getValue());
113
            }, $this->choices);
114
        }
115
    }
116
}
117