Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
75.51% |
37 / 49 |
|
84.62% |
11 / 13 |
CRAP | |
0.00% |
0 / 1 |
Define | |
75.51% |
37 / 49 |
|
84.62% |
11 / 13 |
37.71 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
noKey | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
key | |
57.69% |
15 / 26 |
|
0.00% |
0 / 1 |
10.71 | |||
value | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
arrayDefine | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
isIndexArrayDefine | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isAssocArrayDefine | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isExchange | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
isKeyExchange | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
isValueExchange | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
nestedTypeDefineExists | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
isAllowKeyAction | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
defineConflict | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * @license MIT |
5 | * @author hazuki3417<hazuki3417@gmail.com> |
6 | * @copyright 2022 hazuki3417 all rights reserved. |
7 | */ |
8 | |
9 | namespace Selen\Schema\Exchange; |
10 | |
11 | use Selen\Schema\Exchange\Define\Key; |
12 | |
13 | class Define |
14 | { |
15 | public const KEY_ACTION_NONE = 'none'; |
16 | public const KEY_ACTION_ADD = 'add'; |
17 | public const KEY_ACTION_REMOVE = 'remove'; |
18 | public const KEY_ACTION_RENAME = 'rename'; |
19 | public const KEY_ACTIONS = [ |
20 | self::KEY_ACTION_NONE, |
21 | self::KEY_ACTION_ADD, |
22 | self::KEY_ACTION_REMOVE, |
23 | self::KEY_ACTION_RENAME, |
24 | ]; |
25 | |
26 | /** @var Key */ |
27 | public $key; |
28 | |
29 | /** @var KeyExchangeInterface|callable|null */ |
30 | public $keyExchangeExecute; |
31 | |
32 | /** @var ValueExchangeInterface|callable|null */ |
33 | public $valueExchangeExecute; |
34 | |
35 | /** @var ArrayDefine|null */ |
36 | public $arrayDefine; |
37 | |
38 | /** @var bool */ |
39 | private $haveCalledValue = false; |
40 | |
41 | /** @var bool */ |
42 | private $haveCalledArrayDefine = false; |
43 | |
44 | /** |
45 | * インスタンスを生成します |
46 | * |
47 | * @return Define |
48 | */ |
49 | private function __construct(Key $key) |
50 | { |
51 | $this->key = $key; |
52 | } |
53 | |
54 | /** |
55 | * 添字配列(index)の定義を生成します |
56 | */ |
57 | public static function noKey(): Define |
58 | { |
59 | // TODO: noKeyが指定されたときのkeyActionの処理を実装する |
60 | return new self(new Key(null)); |
61 | } |
62 | |
63 | /** |
64 | * 連想配列(assoc)の定義を生成します |
65 | * |
66 | * @param KeyExchangeInterface|callable|null $execute |
67 | * |
68 | * @throws \InvalidArgumentException 引数の型が不正なときに発生します |
69 | * @throws \ValueError 引数の値が不正なときに発生します |
70 | */ |
71 | public static function key(string|int $name, string $action = self::KEY_ACTION_NONE, $execute = null): Define |
72 | { |
73 | $format = 'Invalid %s %s. expected %s %s.'; |
74 | |
75 | // if ($name === null) { |
76 | // $allowType = ['integer', 'string']; |
77 | // $mes = \sprintf($format, '$name', 'type', 'type', \implode(', ', $allowType)); |
78 | // throw new \InvalidArgumentException($mes); |
79 | // } |
80 | |
81 | if (!self::isAllowKeyAction($action)) { |
82 | $mes = \sprintf($format, '$action', 'value', 'value', \implode(', ', self::KEY_ACTIONS)); |
83 | throw new \ValueError($mes); |
84 | } |
85 | |
86 | /** @var bool[] */ |
87 | $allowTypeList = [ |
88 | \is_null($execute), |
89 | \is_callable($execute), |
90 | ($execute instanceof KeyExchangeInterface), |
91 | ]; |
92 | |
93 | if (!\in_array(true, $allowTypeList, true)) { |
94 | $allowType = [null, 'callable', KeyExchangeInterface::class]; |
95 | $mes = \sprintf($format, '$execute', 'type', 'type', \implode(', ', $allowType)); |
96 | throw new \InvalidArgumentException($mes); |
97 | } |
98 | |
99 | $key = new Key($name); |
100 | |
101 | switch (true) { |
102 | case $action === self::KEY_ACTION_ADD: |
103 | $key = $key->enableAdd(); |
104 | break; |
105 | case $action === self::KEY_ACTION_REMOVE: |
106 | $key = $key->enableRemove(); |
107 | break; |
108 | case $action === self::KEY_ACTION_RENAME: |
109 | $key = $key->enableRename(); |
110 | break; |
111 | default: |
112 | break; |
113 | } |
114 | $self = new self($key); |
115 | $self->keyExchangeExecute = $execute; |
116 | |
117 | return $self; |
118 | } |
119 | |
120 | /** |
121 | * @throws \LogicException メソッドの呼び出し順が不正なときに発生します |
122 | */ |
123 | public function value(ValueExchangeInterface|callable|null $execute = null): Define |
124 | { |
125 | if ($this->defineConflict()) { |
126 | throw new \LogicException('Invalid method call. cannot call value method after arrayDefine.'); |
127 | } |
128 | |
129 | $this->haveCalledValue = true; |
130 | $this->valueExchangeExecute = $execute; |
131 | return $this; |
132 | } |
133 | |
134 | /** |
135 | * @throws \LogicException メソッドの呼び出し順が不正なときに発生します |
136 | * |
137 | * @param Define $define 定義を指定します |
138 | */ |
139 | public function arrayDefine(Define ...$define): Define |
140 | { |
141 | if ($this->defineConflict()) { |
142 | throw new \LogicException('Invalid method call. cannot call arrayDefine method after value.'); |
143 | } |
144 | |
145 | // NOTE: 引数の指定がない場合はそのまま通す(エラーにしない) |
146 | |
147 | $this->haveCalledArrayDefine = true; |
148 | $this->arrayDefine = new ArrayDefine(...$define); |
149 | |
150 | return $this; |
151 | } |
152 | |
153 | /** |
154 | * IndexArray(keyなし)か確認します |
155 | * |
156 | * @return bool IndexArrayの場合はtrueを、それ以外の場合はfalseを返します |
157 | */ |
158 | public function isIndexArrayDefine(): bool |
159 | { |
160 | return $this->key->getName() === null; |
161 | } |
162 | |
163 | /** |
164 | * AssocArray(keyあり)か確認します |
165 | * |
166 | * @return bool AssocArrayの場合はtrueを、それ以外の場合はfalseを返します |
167 | */ |
168 | public function isAssocArrayDefine(): bool |
169 | { |
170 | return $this->key->getName() !== null; |
171 | } |
172 | |
173 | /** |
174 | * 変換処理を実行するか判定します。 |
175 | * |
176 | * @return bool 変換する場合はtrueを、それ以外の場合はfalseを返します |
177 | */ |
178 | public function isExchange(): bool |
179 | { |
180 | return $this->isKeyExchange() || $this->isValueExchange(); |
181 | } |
182 | |
183 | /** |
184 | * keyの変換処理を実行するか判定します。 |
185 | * |
186 | * @return bool 変換する場合はtrueを、それ以外の場合はfalseを返します |
187 | */ |
188 | public function isKeyExchange(): bool |
189 | { |
190 | return |
191 | $this->key->isAddKey() |
192 | || $this->key->isRemoveKey() |
193 | || $this->key->isRenameKey(); |
194 | } |
195 | |
196 | /** |
197 | * valueの変換処理を実行するか判定します。 |
198 | * |
199 | * @return bool 変換する場合はtrueを、それ以外の場合はfalseを返します |
200 | */ |
201 | public function isValueExchange(): bool |
202 | { |
203 | // NOTE: defineConflictでチェックしているので、片方のみの判定でも良い |
204 | return $this->valueExchangeExecute !== null && $this->arrayDefine === null; |
205 | } |
206 | |
207 | /** |
208 | * ネストされた定義が存在するか確認します |
209 | * |
210 | * @return bool 存在する場合はtrueを、それ以外の場合はfalseを返します |
211 | */ |
212 | public function nestedTypeDefineExists(): bool |
213 | { |
214 | // NOTE: defineConflictでチェックしているので、片方のみの判定でも良い |
215 | return $this->valueExchangeExecute === null && $this->arrayDefine !== null; |
216 | } |
217 | |
218 | private static function isAllowKeyAction(string $name): bool |
219 | { |
220 | return \in_array($name, self::KEY_ACTIONS, true); |
221 | } |
222 | |
223 | /** |
224 | * 定義呼び出しが競合しているか確認します |
225 | * |
226 | * @return bool 競合する場合はtrueを、それ以外の場合はfalseを返します |
227 | */ |
228 | private function defineConflict() |
229 | { |
230 | return $this->haveCalledValue || $this->haveCalledArrayDefine; |
231 | } |
232 | } |