ElementTrait::getSourceOptions()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 0
cts 16
cp 0
rs 9.584
c 0
b 0
f 0
cc 3
nc 3
nop 0
crap 12
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://raw.githubusercontent.com/flipboxfactory/craft-link/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/craft-link
7
 */
8
9
namespace flipbox\craft\link\types;
10
11
use Craft;
12
use craft\base\Element;
13
use craft\base\ElementInterface;
14
use flipbox\craft\link\fields\Link;
15
16
/**
17
 * @author Flipbox Factory <[email protected]>
18
 * @since 1.0.0
19
 */
20
trait ElementTrait
21
{
22
    use BaseTrait {
23
        settings as baseSettings;
24
        attributes as baseAttributes;
25
    }
26
27
    /**
28
     * @var int
29
     */
30
    private $elementId;
31
32
    /**
33
     * @var Element|null
34
     */
35
    private $element;
36
37
    /**
38
     * @var string|string[]|null The source keys that this field can relate elements from (used if
39
     * [[allowMultipleSources]] is set to true)
40
     */
41
    public $sources = '*';
42
43
    /**
44
     * @var string|null The source key that this field can relate elements from (used if
45
     * [[allowMultipleSources]] is set to false)
46
     */
47
    public $source;
48
49
    /**
50
     * @var int|null The site that this field should relate elements from
51
     */
52
    public $targetSiteId;
53
54
    /**
55
     * @var bool Whether to allow multiple source selection in the settings
56
     */
57
    public $allowMultipleSources = true;
58
59
    /**
60
     * @var string|null The label that should be used on the selection input
61
     */
62
    public $selectionLabel;
63
64
    /**
65
     * @var int Whether each site should get its own unique set of relations
66
     */
67
    public $localizeRelations = false;
68
69
    /**
70
     * @var bool Whether to allow the “Large Thumbnails” view mode
71
     */
72
    protected $allowLargeThumbsView = false;
73
74
    /**
75
     * @var string|null The view mode
76
     */
77
    public $viewMode;
78
79
    /**
80
     * @var string|null The JS class that should be initialized for the input
81
     */
82
    protected $inputJsClass;
83
84
    /**
85
     * Returns the element class associated with this link type.
86
     *
87
     * @return string
88
     */
89
    abstract protected static function elementType(): string;
90
91
    /**
92
     * @return string
93
     */
94
    abstract public function getElementText(): string;
95
96
    /**
97
     * @return string
98
     */
99
    abstract public function getElementUrl(): string;
100
101
    /**
102
     * @inheritdoc
103
     */
104
    public function settings(): array
105
    {
106
        return array_merge(
107
            $this->baseSettings(),
0 ignored issues
show
Bug introduced by
The method baseSettings() does not exist on flipbox\craft\link\types\ElementTrait. Did you maybe mean settings()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
108
            [
109
                'sources',
110
                'targetSiteId',
111
                'viewMode',
112
                'selectionLabel',
113
                'localizeRelations'
114
            ]
115
        );
116
    }
117
118
    /**
119
     * @inheritdoc
120
     */
121
    public function attributes()
122
    {
123
        return array_merge(
124
            $this->baseAttributes(),
0 ignored issues
show
Bug introduced by
The method baseAttributes() does not exist on flipbox\craft\link\types\ElementTrait. Did you maybe mean attributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
125
            [
126
                'elementId'
127
            ]
128
        );
129
    }
130
131
    /**
132
     * @inheritdoc
133
     */
134
    public function getUrl(): string
135
    {
136
        return $this->getElementUrl();
137
    }
138
139
    /**
140
     * @inheritdoc
141
     */
142
    public function getText()
143
    {
144
        if ($this->allowText && $this->overrideText !== null) {
145
            return $this->overrideText;
146
        }
147
        return $this->getElementText();
148
    }
149
150
    /**
151
     * @return int|null
152
     */
153
    public function getElementId()
154
    {
155
        return $this->elementId;
156
    }
157
158
    /**
159
     * @param $elementId
160
     */
161
    public function setElementId($elementId)
162
    {
163
        if (is_array($elementId)) {
164
            $elementId = reset($elementId);
165
        }
166
        $this->elementId = (int)$elementId;
167
168
        // Clear element cache on change
169
        if ($this->element === false
170
            || ($this->element && $this->element->getId() !== $this->elementId)
171
        ) {
172
            $this->element = null;
173
        }
174
    }
175
176
    /**
177
     * @return ElementInterface|Element|null
178
     */
179
    protected function getElement()
180
    {
181
        if ($this->element === null) {
182
            $this->element = $this->lookupElement() ?: false;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->lookupElement() ?: false of type object<craft\base\ElementInterface> or false is incompatible with the declared type object<craft\base\Element>|null of property $element.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
183
        }
184
185
        return $this->element === false ? null : $this->element;
186
    }
187
188
    /**
189
     * @return ElementInterface|null
190
     */
191
    protected function lookupElement()
192
    {
193
        if ($this->elementId === null) {
194
            return null;
195
        }
196
197
        return Craft::$app->getElements()->getElementById(
198
            $this->elementId,
199
            static::elementType(),
200
            $this->targetSiteId
201
        );
202
    }
203
204
    /**
205
     * Normalizes the available sources into select input options.
206
     *
207
     * @return array
208
     */
209
    public function getSourceOptions(): array
210
    {
211
        $options = [];
212
        $optionNames = [];
213
214
        foreach ($this->availableSources() as $source) {
215
            // Make sure it's not a heading
216
            if (!isset($source['heading'])) {
217
                $options[] = [
218
                    'label' => $source['label'],
219
                    'value' => $source['key']
220
                ];
221
                $optionNames[] = $source['label'];
222
            }
223
        }
224
225
        // Sort alphabetically
226
        array_multisort($optionNames, SORT_NATURAL | SORT_FLAG_CASE, $options);
227
228
        return $options;
229
    }
230
231
    /**
232
     * Returns the sources that should be available to choose from within the field's settings
233
     *
234
     * @return array
235
     */
236
    protected function availableSources(): array
237
    {
238
        return Craft::$app->getElementIndexes()->getSources(static::elementType(), 'modal');
239
    }
240
241
    /**
242
     * Returns the HTML for the View Mode setting.
243
     *
244
     * @return string|null
245
     * @throws \yii\base\Exception
246
     */
247
    public function getViewModeFieldHtml()
248
    {
249
        $supportedViewModes = $this->supportedViewModes();
250
251
        if (count($supportedViewModes) === 1) {
252
            return null;
253
        }
254
255
        $viewModeOptions = [];
256
257
        foreach ($supportedViewModes as $key => $label) {
258
            $viewModeOptions[] = ['label' => $label, 'value' => $key];
259
        }
260
261
        return Craft::$app->getView()->renderTemplateMacro(
262
            '_includes/forms',
263
            'selectField',
264
            [
265
            [
266
                'label' => Craft::t('app', 'View Mode'),
267
                'instructions' => Craft::t('app', 'Choose how the field should look for authors.'),
268
                'id' => 'viewMode',
269
                'name' => 'viewMode',
270
                'options' => $viewModeOptions,
271
                'value' => $this->viewMode
272
            ]
273
            ]
274
        );
275
    }
276
277
    /**
278
     * Returns the field’s supported view modes.
279
     *
280
     * @return array
281
     */
282
    protected function supportedViewModes(): array
283
    {
284
        $viewModes = [
285
            'list' => Craft::t('app', 'List'),
286
        ];
287
288
        if ($this->allowLargeThumbsView) {
289
            $viewModes['large'] = Craft::t('app', 'Large Thumbnails');
290
        }
291
292
        return $viewModes;
293
    }
294
295
    /**
296
     * Returns the site ID that target elements should have.
297
     *
298
     * @param  ElementInterface|null $element
299
     * @return int
300
     * @throws \craft\errors\SiteNotFoundException
301
     */
302
    protected function targetSiteId(ElementInterface $element = null): int
303
    {
304
        /**
305
 * @var Element|null $element
306
*/
307
        if (Craft::$app->getIsMultiSite()) {
308
            if ($this->targetSiteId) {
309
                return $this->targetSiteId;
310
            }
311
312
            if ($element !== null) {
313
                return $element->siteId;
314
            }
315
        }
316
317
        return Craft::$app->getSites()->getCurrentSite()->id;
318
    }
319
320
    /**
321
     * Returns the default [[selectionLabel]] value.
322
     *
323
     * @return string The default selection label
324
     */
325
    public static function defaultSelectionLabel(): string
326
    {
327
        return Craft::t('app', 'Choose');
328
    }
329
330
    /**
331
     * Returns an array of variables that should be passed to the input template.
332
     *
333
     * @param  Link                  $field
334
     * @param  ElementInterface|null $element
335
     * @return array
336
     * @throws \craft\errors\SiteNotFoundException
337
     */
338
    protected function inputTemplateVariables(
339
        Link $field,
340
        ElementInterface $element = null
341
    ): array {
342
        $selectionCriteria = $this->inputSelectionCriteria();
343
        $selectionCriteria['enabledForSite'] = null;
344
        $selectionCriteria['siteId'] = $this->targetSiteId($element);
345
346
        return [
347
            'jsClass' => $this->inputJsClass,
348
            'elementType' => static::elementType(),
349
            'id' => Craft::$app->getView()->formatInputId('elementId'),
350
            'fieldId' => $field->id,
351
            'storageKey' => 'field.' . $field->id,
352
            'name' => 'elementId',
353
            'elements' => [$this->getElement()],
354
            'sources' => $this->inputSources(),
355
            'criteria' => $selectionCriteria,
356
            'sourceElementId' => !empty($element->id) ? $element->id : null,
357
            'limit' => 1,
358
            'viewMode' => $this->viewMode(),
359
            'selectionLabel' => $this->selectionLabel ? Craft::t(
360
                'site',
361
                $this->selectionLabel
362
            ) : static::defaultSelectionLabel(),
363
        ];
364
    }
365
366
    /**
367
     * Returns any additional criteria parameters limiting which elements the field should be able to select.
368
     *
369
     * @return array
370
     */
371
    protected function inputSelectionCriteria(): array
372
    {
373
        return [];
374
    }
375
376
    /**
377
     * Returns the field’s current view mode.
378
     *
379
     * @return string
380
     */
381
    protected function viewMode(): string
382
    {
383
        $supportedViewModes = $this->supportedViewModes();
384
        $viewMode = $this->viewMode;
385
386
        if ($viewMode && isset($supportedViewModes[$viewMode])) {
387
            return $viewMode;
388
        }
389
390
        return 'list';
391
    }
392
393
    /**
394
     * Returns an array of the source keys the field should be able to select elements from.
395
     *
396
     * @return array|string
397
     */
398
    protected function inputSources()
399
    {
400
        if ($this->allowMultipleSources) {
401
            $sources = $this->sources;
402
        } else {
403
            $sources = [$this->source];
404
        }
405
406
        return $sources;
407
    }
408
}
409