Completed
Push — master ( cef71e...189e10 )
by Nate
01:56
created

Domains::afterElementSave()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 9
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 2
crap 2
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/domains/license
6
 * @link       https://www.flipboxfactory.com/software/domains/
7
 */
8
9
namespace flipbox\domains\fields;
10
11
use Craft;
12
use craft\base\Element;
13
use craft\base\ElementInterface;
14
use craft\base\Field;
15
use craft\elements\db\ElementQuery;
16
use craft\elements\db\ElementQueryInterface;
17
use craft\helpers\ArrayHelper;
18
use craft\helpers\StringHelper;
19
use flipbox\domains\db\DomainsQuery;
20
use flipbox\domains\Domains as DomainsPlugin;
21
use flipbox\domains\models\Domain;
22
use flipbox\domains\validators\DomainsValidator;
23
24
/**
25
 * @author Flipbox Factory <[email protected]>
26
 * @since 1.0.0
27
 */
28
class Domains extends Field
29
{
30
    /**
31
     * @var bool
32
     */
33
    public $unique = true;
34
35
    /**
36
     * @var int|null The maximum number of relations this field can have (used if [[allowLimit]] is set to true)
37
     */
38
    public $limit;
39
40
    /**
41
     * @var bool Whether to allow the Limit setting
42
     */
43
    public $allowLimit = true;
44
45
    /**
46
     * @var string
47
     */
48
    public $defaultStatus = 'pending';
49
50
    /**
51
     * @inheritdoc
52
     */
53
    public static function displayName(): string
54
    {
55
        return Craft::t('domains', 'Domains');
56
    }
57
58
    /**
59
     * @inheritdoc
60
     */
61
    public static function hasContentColumn(): bool
62
    {
63
        return false;
64
    }
65
66
    /**
67
     * @inheritdoc
68
     */
69
    public function getElementValidationRules(): array
70
    {
71
        $rules = parent::getElementValidationRules();
72
73
        $rules[] = [
74
            DomainsValidator::class,
75
            'field' => $this
76
        ];
77
78
        return $rules;
79
    }
80
81
    /**
82
     * @inheritdoc
83
     */
84
    public function normalizeValue($value, ElementInterface $element = null)
85
    {
86
        // All good
87
        if ($value instanceof DomainsQuery) {
88
            return $value;
89
        }
90
91
        /** @var Element|null $element */
92
        $query = (new DomainsQuery($this))
93
            ->siteId($this->targetSiteId($element));
94
95
        // $value will be an array of domains
96
        if (is_array($value)) {
97
            $this->modifyQueryInputValue($query, $value, $element);
98
        } elseif ($value === '') {
99
            $this->modifyQueryEmptyValue($query);
100
        } else {
101
            $this->modifyQuery($query, $value, $element);
102
        }
103
104
        if ($this->allowLimit && $this->limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
105
            $query->limit($this->limit);
106
        }
107
108
        return $query;
109
    }
110
111
    /**
112
     * @param DomainsQuery $query
113
     * @param array $value
114
     * @param ElementInterface|null $element
115
     */
116
    private function modifyQueryInputValue(DomainsQuery $query, array $value, ElementInterface $element = null)
117
    {
118
        $models = [];
119
        $sortOrder = 0;
120
        foreach ($value as $val) {
121
            if (!is_array($val)) {
122
                $val = [
123
                    'domain' => $value,
124
                    'status' => $this->defaultStatus
125
                ];
126
            }
127
128
            $models[] = new Domain(
129
                $this,
130
                [
131
                    'domain' => ArrayHelper::getValue($val, 'domain'),
132
                    'status' => ArrayHelper::getValue($val, 'status'),
133
                    'element' => $element,
134
                    'sortOrder' => $sortOrder++
135
                ]
136
            );
137
        }
138
        $query->setCachedResult($models);
139
    }
140
141
    /**
142
     * @param DomainsQuery $query
143
     */
144
    private function modifyQueryEmptyValue(DomainsQuery $query)
145
    {
146
        $query->setCachedResult([]);
147
    }
148
149
    /**
150
     * @param DomainsQuery $query
151
     * @param string $value
152
     * @param ElementInterface|null $element
153
     */
154
    private function modifyQuery(DomainsQuery $query, string $value = null, ElementInterface $element = null)
155
    {
156
        if ($value !== '' && $element && $element->getId()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $element->getId() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
157
            $query->elementId($element->getId());
158
        } else {
159
            $query->elementId(false);
160
            $query->domain(false);
161
        }
162
    }
163
164
    /**
165
     * Returns the site ID that target elements should have.
166
     *
167
     * @param ElementInterface|null $element
168
     *
169
     * @return int
170
     */
171
    protected function targetSiteId(ElementInterface $element = null): int
172
    {
173
        /** @var Element|null $element */
174
        if (Craft::$app->getIsMultiSite()) {
175
            if ($element !== null) {
176
                return $element->siteId;
177
            }
178
        }
179
180
        return Craft::$app->getSites()->currentSite->id;
181
    }
182
183
    /**
184
     * @inheritdoc
185
     */
186
    public function modifyElementsQuery(ElementQueryInterface $query, $value)
187
    {
188
        /** @var ElementQuery $query */
189
        if ($value === 'not :empty:') {
190
            $value = ':notempty:';
191
        }
192
193
        if ($value === ':notempty:' || $value === ':empty:') {
194
            $fieldService = DomainsPlugin::getInstance()->getField();
195
            $alias = $fieldService->getTableAlias($this);
196
            $name = $fieldService->getTableName($this);
197
            $operator = ($value === ':notempty:' ? '!=' : '=');
198
199
            $query->subQuery->andWhere(
200
                "(select count([[{$alias}.id]]) from " .
201
                $name .
202
                " {{{$alias}}} where [[{$alias}.elementId]] = [[elements.id]]) {$operator} 0"
203
            );
204
        } else {
205
            if ($value !== null) {
206
                return false;
207
            }
208
        }
209
210
        return null;
211
    }
212
213
    // Events
214
    // -------------------------------------------------------------------------
215
216
    /**
217
     * @inheritdoc
218
     */
219
    public function afterSave(bool $isNew)
220
    {
221
        DomainsPlugin::getInstance()->getField()->saveSettings($this);
222
        parent::afterSave($isNew);
223
    }
224
225
    /**
226
     * @inheritdoc
227
     */
228
    public function afterDelete()
229
    {
230
        DomainsPlugin::getInstance()->getField()->delete($this);
231
        parent::afterDelete();
232
    }
233
234
    /**
235
     * @inheritdoc
236
     */
237
    public function afterElementSave(ElementInterface $element, bool $isNew)
238
    {
239
        // Associate/Dissociate
240
        DomainsPlugin::getInstance()->getRelationship()->resolve(
241
            $this,
242
            $element->getFieldValue($this->handle),
243
            $element
244
        );
245
246
        parent::afterElementSave($element, $isNew);
247
    }
248
249
    /**
250
     * @inheritdoc
251
     *
252
     * @param DomainsQuery $value
253
     */
254
    public function getInputHtml($value, ElementInterface $element = null): string
255
    {
256
        $input = '<input type="hidden" name="' . $this->handle . '" value="">';
257
258
        $tableHtml = $this->getTableHtml($value, $element, false);
259
260
        if ($tableHtml) {
261
            $input .= $tableHtml;
262
        }
263
264
        return $input;
265
    }
266
267
    /**
268
     * Returns the field's input HTML.
269
     *
270
     * @param mixed $value
271
     * @param ElementInterface|null $element
272
     * @param bool $static
273
     *
274
     * @return string
275
     */
276
    private function getTableHtml($value, ElementInterface $element = null, bool $static): string
0 ignored issues
show
Unused Code introduced by
The parameter $element is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
277
    {
278
        $columns = [
279
            'domain' => [
280
                'heading' => 'Domain',
281
                'handle' => 'domain',
282
                'type' => 'singleline'
283
            ],
284
            'status' => [
285
                'heading' => 'Status',
286
                'handle' => 'status',
287
                'type' => 'select',
288
                'options' => $this->getStatuses()
289
            ]
290
        ];
291
292
        if (!empty($columns)) {
293
            // Translate the column headings
294
            foreach ($columns as &$column) {
295
                if (!empty($column['heading'])) {
296
                    $column['heading'] = Craft::t('site', $column['heading']);
0 ignored issues
show
Bug introduced by
It seems like $column['heading'] can also be of type array; however, yii\BaseYii::t() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
297
                }
298
            }
299
            unset($column);
300
301
            $id = Craft::$app->getView()->formatInputId($this->handle);
302
303
            return Craft::$app->getView()->renderTemplate(
304
                'domains/_components/fieldtypes/Domains/input',
305
                [
306
                    'id' => $id,
307
                    'name' => $this->handle,
308
                    'cols' => $columns,
309
                    'rows' => $value->all(),
310
                    'static' => $static
311
                ]
312
            );
313
        }
314
315
        return null;
316
    }
317
318
    /**
319
     * @return array
320
     */
321
    public function getStatuses(): array
322
    {
323
        return [
324
            'enabled' => Craft::t('domains', 'Enabled'),
325
            'pending' => Craft::t('domains', 'Pending'),
326
            'disabled' => Craft::t('domains', 'Disabled')
327
        ];
328
    }
329
330
331
    /**
332
     * @param DomainsQuery|null $value
333
     *
334
     * @inheritdoc
335
     */
336
    public function getSearchKeywords($value, ElementInterface $element): string
337
    {
338
        if (!$value) {
339
            return '';
340
        }
341
342
        $domains = [];
343
344
        foreach ($value->all() as $domain) {
345
            array_push($domains, $domain->domain);
346
        }
347
348
        return StringHelper::toString($domains, ' ');
349
    }
350
}
351