Completed
Push — master ( 6cd6d9...f28a9d )
by Nate
01:18
created

Link::normalizeValue()   C

Complexity

Conditions 10
Paths 22

Size

Total Lines 47
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 0
loc 47
ccs 0
cts 38
cp 0
rs 5.1578
c 0
b 0
f 0
cc 10
eloc 25
nc 22
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\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\link\Link as LinkPlugin;
18
use flipbox\link\types\TypeInterface;
19
use flipbox\link\validators\LinkValidator;
20
use flipbox\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
     */
47
    public function getTypes()
48
    {
49
        // Make sure all un-resolved configs are resolved
50
        $this->resolveConfigs();
51
52
        return $this->types;
53
    }
54
55
    /**
56
     * @param array $types
57
     * @return $this
58
     */
59
    public function setTypes(array $types)
60
    {
61
        foreach ($types as $identifier => $type) {
62
            $identifier = is_array($type) ? ArrayHelper::getValue($type, 'identifier', $identifier) : $identifier;
63
            $this->typeConfigs[$identifier] = $type;
64
        }
65
        return $this;
66
    }
67
68
    /**
69
     * @param string $identifier
70
     * @return TypeInterface
71
     */
72
    public function getType(string $identifier)
73
    {
74
        // Is it already an object?
75
        if (!array_key_exists($identifier, $this->types)) {
76
            // Can we create it?
77
            if (!$type = $this->createFromConfig($identifier)) {
78
                return null;
79
            }
80
81
            $this->types[$identifier] = $type;
82
        }
83
84
        return clone $this->types[$identifier];
85
    }
86
87
    /**
88
     * @inheritdoc
89
     */
90
    public static function displayName(): string
91
    {
92
        return Craft::t('link', 'Link');
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    public function getContentColumnType(): string
99
    {
100
        return Schema::TYPE_TEXT;
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106
    public function getSettingsHtml()
107
    {
108
109
        $view = Craft::$app->getView();
110
111
        $view->registerAssetBundle(Settings::class);
112
113
        return $view->renderTemplate(
114
            'link/_components/fieldtypes/Link/settings',
115
            [
116
                'field' => $this,
117
                'types' => LinkPlugin::getInstance()->getType()->findAll(),
118
                'namespace' => $view->getNamespace()
119
            ]
120
        );
121
    }
122
123
    /**
124
     * @inheritdoc
125
     */
126
    public function getInputHtml($value, ElementInterface $element = null): string
127
    {
128
        return Craft::$app->getView()->renderTemplate(
129
            'link/_components/fieldtypes/Link/input',
130
            [
131
                'field' => $this,
132
                'value' => $value,
133
                'element' => $element
134
            ]
135
        );
136
    }
137
138
    /**
139
     * @inheritdoc
140
     */
141
    public function serializeValue($value, ElementInterface $element = null)
142
    {
143
        if ($value === null) {
144
            return $value;
145
        }
146
147
        if ($value instanceof TypeInterface) {
148
            $value = array_merge(
149
                [
150
                    'identifier' => $value->getIdentifier(),
151
                ],
152
                $value->getProperties()
153
            );
154
        }
155
156
        return Db::prepareValueForDb($value);
157
    }
158
159
    /**
160
     * @inheritdoc
161
     */
162
    public function getSettings(): array
163
    {
164
        $settings = parent::getSettings();
165
166
        // Merge the type settings
167
        foreach ($this->getTypes() as $identifier => $type) {
168
            $settings['types'][$identifier] = array_merge(
169
                ['class' => get_class($type)],
170
                $type->getSettings()
171
            );
172
        }
173
174
        return $settings;
175
    }
176
177
    /**
178
     * @inheritdoc
179
     */
180
    public function getElementValidationRules(): array
181
    {
182
        return [
183
            [
184
                LinkValidator::class
185
            ]
186
        ];
187
    }
188
189
    /**
190
     * @param mixed $value
191
     * @param ElementInterface|null $element
192
     * @return array|mixed|null|object
193
     */
194
    public function normalizeValue($value, ElementInterface $element = null)
195
    {
196
        if (is_string($value) && !empty($value)) {
197
            $value = Json::decodeIfJson($value);
198
        }
199
200
        if ($value instanceof TypeInterface) {
201
            return $value;
202
        }
203
204
        if (!is_array($value)) {
205
            return null;
206
        }
207
208
        // Get the type by identifier
209
        if ($identifier = ArrayHelper::remove($value, 'identifier')) {
210
            $type = $this->getType($identifier);
211
        } else {
212
            if ($class = ArrayHelper::remove($value, 'class')) {
213
                $type = LinkPlugin::getInstance()->getType()->create($class);
214
            }
215
        }
216
217
        if (empty($type) || !$type instanceof TypeInterface) {
218
            return null;
219
        }
220
221
        // When saving via the admin, there may be multiple 'types' configured
222
        if ($types = ArrayHelper::remove($value, 'types')) {
223
            $value = array_merge(
224
                ArrayHelper::remove($types, $identifier, []),
225
                $value
226
            );
227
        }
228
229
        LinkPlugin::getInstance()->getType()->populate(
230
            $type,
231
            array_filter(
232
                $value,
233
                function($var){
234
                    return !is_null($var);
235
                }
236
            )
237
        );
238
239
        return $type;
240
    }
241
242
    /**
243
     * Create objects from all (remaining) configurations
244
     *
245
     * @return void
246
     */
247
    private function resolveConfigs()
248
    {
249
        foreach ($this->typeConfigs as $identifier => $config) {
250
            $this->resolveConfig($identifier, $config);
251
        }
252
        $this->typeConfigs = [];
253
    }
254
255
    /**
256
     * @param string $identifier
257
     * @param array $config
258
     * @return null|object
259
     */
260
    private function resolveConfig(string $identifier, array $config)
261
    {
262
        // cCreate new
263
        if (!$type = LinkPlugin::getInstance()->getType()->create($config)) {
264
            return null;
265
        }
266
267
        $type->setIdentifier($identifier);
268
269
        // Cache it
270
        $this->types[$identifier] = $type;
271
272
        return $type;
273
    }
274
275
    /**
276
     * @param string $identifier
277
     * @return null|object
278
     */
279
    private function createFromConfig(string $identifier)
280
    {
281
        if (!$config = ArrayHelper::remove($this->typeConfigs, $identifier)) {
282
            return null;
283
        }
284
285
        return $this->resolveConfig($identifier, $config);
286
    }
287
}
288