EnumMappingBehavior::validateAttributes()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 0
1
<?php
2
3
/**
4
 * @author Roman Varkuta <[email protected]>
5
 * @license MIT
6
 * @see https://github.com/myclabs/php-enum
7
 * @version 2.0
8
 */
9
10
declare(strict_types=1);
11
12
namespace Kartavik\Yii2\Behaviors;
13
14
use MyCLabs\Enum\Enum;
15
use yii\base;
16
use yii\db;
17
18
/**
19
 * Class EnumMappingBehavior
20
 *
21
 * ```php
22
 * return [
23
 *      'enum' => [
24
 *          'class' => \Kartavik\Yii2\Behaviors\EnumMappingBehavior::class,
25
 *          'map' => [
26
 *              'attribute1' => FirstYourEnum::class,
27
 *              'attribute2' => SecondYourEnum::class,
28
 *          ],
29
 *          'attributesType' => [
30
 *              'attribute1' => 'integer',
31
 *              'attribute2' => 'float',
32
 *          ],
33
 *      ],
34
 * ];
35
 * ```
36
 *
37
 * @package Kartavik\Yii2\Behaviors
38
 * @since 1.0
39
 */
40
class EnumMappingBehavior extends base\Behavior
41
{
42
    public const EVENT_TO_ENUMS = 'toEnums';
43
    public const EVENT_TO_VALUES = 'toValues';
44
45
    /**
46
     * Key used for EnumMappingBehavior class, value is array of attributes that must be converted into this enum
47
     *
48
     * ```php
49
     * [
50
     *      'attribute1' => FirstYourEnum::class,
51
     *      'attribute2' => SecondYourEnum::class,
52
     * ]
53
     * ```
54
     *
55
     * @var array
56
     * @since 2.0
57
     */
58
    public $map;
59
60
    /**
61
     * In some cases database enum type can work only with string, so this parameter help behaviour to cast variable to
62
     * needs type
63
     *
64
     * ```php
65
     * [
66
     *      'attribute1' => 'integer',
67
     *      'attribute2' => 'float',
68
     * ]
69
     * ```
70
     *
71
     * @var array
72
     * @since 1.1
73
     */
74
    public $attributesType = [];
75
76
    /**
77
     * If you want use keys for mapping just add related attribute to this property
78
     *
79
     * ```php
80
     * [
81
     *      'attribute1', // values for this attribute will be as key in enum
82
     * ]
83
     * ```
84
     *
85
     * @var array
86
     * @since 2.2
87
     */
88
    public $useKeyFor = [];
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function events(): array
94
    {
95
        return [
96
            EnumMappingBehavior::EVENT_TO_ENUMS => 'toEnums',
97
            EnumMappingBehavior::EVENT_TO_VALUES => 'toValues',
98
            db\ActiveRecord::EVENT_AFTER_FIND => EnumMappingBehavior::EVENT_TO_ENUMS,
99
            db\ActiveRecord::EVENT_AFTER_INSERT => EnumMappingBehavior::EVENT_TO_ENUMS,
100
            db\ActiveRecord::EVENT_AFTER_UPDATE => EnumMappingBehavior::EVENT_TO_ENUMS,
101
            db\ActiveRecord::EVENT_BEFORE_INSERT => EnumMappingBehavior::EVENT_TO_VALUES,
102
            db\ActiveRecord::EVENT_BEFORE_UPDATE => EnumMappingBehavior::EVENT_TO_VALUES,
103
        ];
104
    }
105
106
    /**
107
     * @throws base\InvalidConfigException
108
     */
109
    public function toValues(): void
110
    {
111
        $this->validateAttributes();
112
113
        foreach ($this->map as $attribute => $enum) {
114
            $value = $this->owner->{$attribute};
115
116
            if ($value instanceof $enum) {
117
                /** @var Enum $value */
118
                $enumValue = $this->isUseKey($attribute) ? $value->getKey() : $value->getValue();
119
                $this->castTypeIfExist($enumValue, $attribute);
120
                $this->owner->{$attribute} = $enumValue;
121
            }
122
        }
123
    }
124
125
    /**
126
     * @throws base\InvalidConfigException
127
     * @throws \UnexpectedValueException
128
     */
129
    public function toEnums(): void
130
    {
131
        $this->validateAttributes();
132
133
        foreach ($this->map as $attribute => $enum) {
134
            $value = $this->owner->{$attribute};
135
136
            if (!$value instanceof Enum) {
137
                $this->castTypeIfExist($value, $attribute);
138
                $this->owner->{$attribute} = isset($this->owner->{$attribute}) && $this->isUseKey($attribute)
139
                    ? \call_user_func([$enum, $value])
140
                    : new $enum($value);
141
            }
142
        }
143
    }
144
145
    /**
146
     * @param mixed  $variable
147
     * @param string $attribute
148
     */
149
    protected function castTypeIfExist(&$variable, string $attribute): void
150
    {
151
        if (isset($this->attributesType[$attribute])) {
152
            \settype($variable, $this->attributesType[$attribute]);
153
        }
154
    }
155
156
    /**
157
     * @throws base\InvalidConfigException
158
     */
159
    protected function validateAttributes(): void
160
    {
161
        foreach ($this->map as $attribute => $enum) {
162
            if (!\class_exists($enum) || !\in_array(Enum::class, \class_parents($enum), true)) {
163
                throw new base\InvalidConfigException("Class [{$enum}] must exist and implement " . Enum::class);
164
            }
165
        }
166
    }
167
168
    protected function isUseKey(string $attribute): bool
169
    {
170
        return \in_array($attribute, $this->useKeyFor, \true);
171
    }
172
}
173