Completed
Branch develop (6195ed)
by Nate
06:16
created

Link::normalizeValue()   B

Complexity

Conditions 10
Paths 21

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 0
loc 40
ccs 0
cts 30
cp 0
rs 7.6666
c 0
b 0
f 0
cc 10
nc 21
nop 2
crap 110

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/link/license
6
 * @link       https://www.flipboxfactory.com/software/link/
7
 */
8
9
namespace flipbox\craft\link\fields;
10
11
use Craft;
12
use craft\base\ElementInterface;
13
use craft\base\Field;
14
use craft\helpers\ArrayHelper;
15
use craft\helpers\Db;
16
use craft\helpers\Json;
17
use flipbox\craft\link\Link as LinkPlugin;
18
use flipbox\craft\link\types\TypeInterface;
19
use flipbox\craft\link\validators\LinkValidator;
20
use flipbox\craft\link\web\assets\settings\Settings;
21
use yii\db\Schema;
22
23
/**
24
 * @author Flipbox Factory <[email protected]>
25
 * @since 1.0.0
26
 */
27
class Link extends Field
28
{
29
30
    /**
31
     * Type objects that have been configured via the admin
32
     *
33
     * @var TypeInterface[]
34
     */
35
    protected $types = [];
36
37
    /**
38
     * Raw configurations that have been configured via the admin
39
     *
40
     * @var array
41
     */
42
    protected $typeConfigs = [];
43
44
    /**
45
     * @return TypeInterface[]
46
     * @throws \yii\base\InvalidConfigException
47
     */
48
    public function getTypes()
49
    {
50
        // Make sure all un-resolved configs are resolved
51
        $this->resolveConfigs();
52
53
        return $this->types;
54
    }
55
56
    /**
57
     * @param array $types
58
     * @return $this
59
     */
60
    public function setTypes(array $types)
61
    {
62
        foreach ($types as $identifier => $type) {
63
            $identifier = is_array($type) ? ArrayHelper::getValue($type, 'identifier', $identifier) : $identifier;
64
            $this->typeConfigs[$identifier] = $type;
65
        }
66
        return $this;
67
    }
68
69
    /**
70
     * @param string $identifier
71
     * @return TypeInterface|null
72
     * @throws \yii\base\InvalidConfigException
73
     */
74
    public function getType(string $identifier)
75
    {
76
        // Is it already an object?
77
        if (!array_key_exists($identifier, $this->types)) {
78
            // Can we create it?
79
            if (!$type = $this->createFromConfig($identifier)) {
80
                return null;
81
            }
82
83
            $this->types[$identifier] = $type;
84
        }
85
86
        return clone $this->types[$identifier];
87
    }
88
89
    /**
90
     * @inheritdoc
91
     */
92
    public static function displayName(): string
93
    {
94
        return Craft::t('link', 'Link');
95
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100
    public function getContentColumnType(): string
101
    {
102
        return Schema::TYPE_TEXT;
103
    }
104
105
    /**
106
     * @inheritdoc
107
     * @throws \Twig_Error_Loader
108
     * @throws \yii\base\Exception
109
     * @throws \yii\base\InvalidConfigException
110
     */
111
    public function getSettingsHtml()
112
    {
113
114
        $view = Craft::$app->getView();
115
116
        $view->registerAssetBundle(Settings::class);
117
118
        return $view->renderTemplate(
119
            'link/_components/fieldtypes/Link/settings',
120
            [
121
                'field' => $this,
122
                'types' => LinkPlugin::getInstance()->findAllTypes(),
123
                'namespace' => $view->getNamespace()
124
            ]
125
        );
126
    }
127
128
    /**
129
     * @inheritdoc
130
     * @throws \Twig_Error_Loader
131
     * @throws \yii\base\Exception
132
     */
133
    public function getInputHtml($value, ElementInterface $element = null): string
134
    {
135
        return Craft::$app->getView()->renderTemplate(
136
            'link/_components/fieldtypes/Link/input',
137
            [
138
                'field' => $this,
139
                'value' => $value,
140
                'element' => $element
141
            ]
142
        );
143
    }
144
145
    /**
146
     * @inheritdoc
147
     */
148
    public function serializeValue($value, ElementInterface $element = null)
149
    {
150
        if ($value === null) {
151
            return $value;
152
        }
153
154
        if ($value instanceof TypeInterface) {
155
            $value = array_merge(
156
                [
157
                    'identifier' => $value->getIdentifier(),
158
                ],
159
                $value->getProperties()
160
            );
161
        }
162
163
        return Db::prepareValueForDb($value);
164
    }
165
166
    /**
167
     * @inheritdoc
168
     * @throws \yii\base\InvalidConfigException
169
     */
170
    public function getSettings(): array
171
    {
172
        $settings = parent::getSettings();
173
174
        // Merge the type settings
175
        foreach ($this->getTypes() as $identifier => $type) {
176
            $settings['types'][$identifier] = array_merge(
177
                ['class' => get_class($type)],
178
                $type->getSettings()
179
            );
180
        }
181
182
        return $settings;
183
    }
184
185
    /**
186
     * @inheritdoc
187
     */
188
    public function getElementValidationRules(): array
189
    {
190
        return [
191
            [
192
                LinkValidator::class
193
            ]
194
        ];
195
    }
196
197
    /**
198
     * @param $value
199
     * @param ElementInterface|null $element
200
     * @return array|TypeInterface|mixed|object|null
201
     * @throws \yii\base\InvalidConfigException
202
     */
203
    public function normalizeValue($value, ElementInterface $element = null)
204
    {
205
        if ($value instanceof TypeInterface) {
206
            return $value;
207
        }
208
209
        if (is_string($value) && !empty($value)) {
210
            $value = Json::decodeIfJson($value);
211
        }
212
213
        if (!is_array($value)) {
214
            return null;
215
        }
216
217
        // Get the type by identifier
218
        if ($identifier = ArrayHelper::remove($value, 'identifier')) {
219
            $type = $this->getType($identifier);
220
        } else {
221
            if ($class = ArrayHelper::remove($value, 'class')) {
222
                $type = new $class;
223
            }
224
        }
225
226
        if (empty($type) || !$type instanceof TypeInterface) {
227
            return null;
228
        }
229
230
        // When saving via the admin, there may be multiple 'types' configured
231
        if ($types = ArrayHelper::remove($value, 'types')) {
232
            $value = array_merge(
233
                ArrayHelper::remove($types, $identifier, []),
234
                $value
235
            );
236
        }
237
238
        // Populate
239
        $type->populate($value);
240
241
        return $type;
242
    }
243
244
    /**
245
     * Create objects from all (remaining) configurations
246
     *
247
     * @throws \yii\base\InvalidConfigException
248
     */
249
    private function resolveConfigs()
250
    {
251
        foreach ($this->typeConfigs as $identifier => $config) {
252
            $this->resolveConfig($identifier, $config);
253
        }
254
        $this->typeConfigs = [];
255
    }
256
257
    /**
258
     * @param string $identifier
259
     * @param array  $config
260
     * @return TypeInterface|null
261
     * @throws \yii\base\InvalidConfigException
262
     */
263
    private function resolveConfig(string $identifier, array $config)
264
    {
265
        // Create new
266
        /**
267
 * @var TypeInterface $type
268
*/
269
        if (!$type = $this->createType($config)) {
270
            return null;
271
        }
272
273
        $type->setIdentifier($identifier);
274
275
        // Cache it
276
        $this->types[$identifier] = $type;
277
278
        return $type;
279
    }
280
281
    /**
282
     * @param $type
283
     * @return array|object|null
284
     * @throws \yii\base\InvalidConfigException
285
     */
286
    private function createType($type)
287
    {
288
        if ($type instanceof TypeInterface) {
289
            return $type;
290
        }
291
292
        if (!is_array($type)) {
293
            $type = ['class' => $type];
294
        }
295
296
        $type = Craft::createObject(
297
            $type
298
        );
299
300
        if (!$type instanceof TypeInterface) {
301
            return null;
302
        }
303
304
        return $type;
305
    }
306
307
    /**
308
     * @param string $identifier
309
     * @return TypeInterface|null
310
     * @throws \yii\base\InvalidConfigException
311
     */
312
    private function createFromConfig(string $identifier)
313
    {
314
        if (!$config = ArrayHelper::remove($this->typeConfigs, $identifier)) {
315
            return null;
316
        }
317
318
        return $this->resolveConfig($identifier, $config);
319
    }
320
}
321