Completed
Pull Request — master (#114)
by Maxime
01:33
created

Enum::__construct()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 7.6924
c 0
b 0
f 0
cc 9
nc 10
nop 1
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
//[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
23
class Enum extends Choice
24
{
25
    /** @var string */
26
    public $class;
27
28
    /**
29
     * Set to true in order to validate enum values instead of instances.
30
     *
31
     * @var bool
32
     */
33
    public $asValue = false;
34
35
    public function __construct(
36
        $class = null,
37
        ?array $choices = null,
38
        ?bool $asValue = null,
39
        $callback = null,
40
        ?bool $multiple = null,
41
        ?bool $strict = null,
42
        ?int $min = null,
43
        ?int $max = null,
44
        ?string $message = null,
45
        ?string $multipleMessage = null,
46
        ?string $minMessage = null,
47
        ?string $maxMessage = null,
48
        $groups = null,
49
        $payload = null
50
    ) {
51
        parent::__construct(
52
            $class, // "class" is the default option here and supersedes "choices" from parent class.
53
            $callback,
54
            $multiple,
55
            $strict,
56
            $min,
57
            $max,
58
            $message,
59
            $multipleMessage,
60
            $minMessage,
61
            $maxMessage,
62
            $groups,
63
            $payload,
64
        );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
65
66
        $this->asValue = $asValue ?? $this->asValue;
67
        // Choices are either provided as $class argument when used as "options" (Doctrine annotations style) and handled in parent class,
68
        // or provided with positional or named argument using PHP construct:
69
        $this->choices = $choices ?? $this->choices;
70
71
        if (!is_a($this->class, EnumInterface::class, true)) {
72
            throw new ConstraintDefinitionException(sprintf(
73
                'The "class" option value must be a class FQCN implementing "%s". "%s" given.',
74
                EnumInterface::class,
75
                $this->class
76
            ));
77
        }
78
79
        // Normalize choices
80
        if (\is_array($this->choices)) {
81
            $choices = [];
82
            foreach ($this->choices as $choiceValue) {
83
                if (false === \call_user_func([$this->class, 'accepts'], $choiceValue)) {
84
                    throw new ConstraintDefinitionException(sprintf(
85
                        'Choice %s is not a valid value for enum type "%s".',
86
                        json_encode($choiceValue),
87
                        $this->class
88
                    ));
89
                }
90
91
                $choices[] = $this->asValue ? $choiceValue : \call_user_func([$this->class, 'get'], $choiceValue);
92
            }
93
94
            $this->choices = $choices;
95
        }
96
97
        // only set the callback if no choice list set
98
        if (!\is_array($this->choices)) {
99
            // Check for a user provided callback first
100
            if ($this->callback) {
101
                $this->callback = [$this->class, $this->callback];
102
            } else {
103
                $this->callback = $this->asValue ? [$this->class, 'values'] : [$this->class, 'instances'];
104
            }
105
        }
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function validatedBy()
112
    {
113
        return ChoiceValidator::class;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function getDefaultOption()
120
    {
121
        return 'class';
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function getRequiredOptions()
128
    {
129
        return ['class'];
130
    }
131
132
    /**
133
     * Fixup deserialized enum instances by replacing them with actual multiton instances,
134
     * so strict comparison works.
135
     *
136
     * {@inheritdoc}
137
     */
138
    public function __wakeup()
139
    {
140
        if (!$this->asValue && \is_array($this->choices)) {
141
            $this->choices = array_map(static function (EnumInterface $enum): EnumInterface {
142
                /** @var string|EnumInterface $enumClass */
143
                $enumClass = \get_class($enum);
144
145
                return $enumClass::get($enum->getValue());
146
            }, $this->choices);
147
        }
148
    }
149
}
150