Passed
Push — develop ( 56da09...d1ee6a )
by Andrew
07:12
created

Field::superTableFieldsOfType()   B

Complexity

Conditions 8
Paths 12

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 17
nc 12
nop 3
dl 0
loc 31
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\helpers;
13
14
use nystudio107\seomatic\Seomatic;
15
use nystudio107\seomatic\fields\SeoSettings as SeoSettingsField;
16
use nystudio107\seomatic\fields\Seomatic_Meta as Seomatic_MetaField;
17
use nystudio107\seomatic\services\MetaBundles;
18
19
use Craft;
20
use craft\base\Element;
21
use craft\base\Field as BaseField;
22
use craft\base\Volume;
23
use craft\elements\User;
24
use craft\ckeditor\Field as CKEditorField;
25
use craft\elements\MatrixBlock;
26
use craft\fields\Assets as AssetsField;
27
use craft\fields\Matrix as MatrixField;
28
use craft\fields\PlainText as PlainTextField;
29
use craft\fields\Tags as TagsField;
30
use craft\models\FieldLayout;
31
use craft\redactor\Field as RedactorField;
32
33
use verbb\supertable\fields\SuperTableField;
0 ignored issues
show
Bug introduced by
The type verbb\supertable\fields\SuperTableField was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use verbb\supertable\elements\SuperTableBlockElement as SuperTableBlock;
0 ignored issues
show
Bug introduced by
The type verbb\supertable\elements\SuperTableBlockElement was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
36
use benf\neo\Field as NeoField;
0 ignored issues
show
Bug introduced by
The type benf\neo\Field was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
use benf\neo\elements\Block as NeoBlock;
0 ignored issues
show
Bug introduced by
The type benf\neo\elements\Block was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
39
use yii\base\InvalidConfigException;
40
41
/**
42
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
43
 * @package   Seomatic
44
 * @since     3.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
45
 */
46
class Field
47
{
48
    // Constants
49
    // =========================================================================
50
51
    const TEXT_FIELD_CLASS_KEY = 'text';
52
    const ASSET_FIELD_CLASS_KEY = 'asset';
53
    const BLOCK_FIELD_CLASS_KEY = 'block';
54
    const SEO_SETTINGS_CLASS_KEY = 'seo';
55
    const OLD_SEOMATIC_META_CLASS_KEY = 'Seomatic_Meta';
56
57
    const FIELD_CLASSES = [
58
        self::TEXT_FIELD_CLASS_KEY  => [
59
            CKEditorField::class,
60
            PlainTextField::class,
61
            MatrixField::class,
62
            RedactorField::class,
63
            TagsField::class,
64
            NeoField::class,
65
            SuperTableField::class,
66
        ],
67
        self::ASSET_FIELD_CLASS_KEY => [
68
            AssetsField::class,
69
        ],
70
        self::BLOCK_FIELD_CLASS_KEY => [
71
            MatrixField::class,
72
            NeoField::class,
73
            SuperTableField::class,
74
        ],
75
        self::SEO_SETTINGS_CLASS_KEY => [
76
            SeoSettingsField::class,
77
        ],
78
        self::OLD_SEOMATIC_META_CLASS_KEY => [
79
            Seomatic_MetaField::class,
80
        ],
81
    ];
82
83
    // Static Properties
84
    // =========================================================================
85
86
    /**
87
     * @var array Memoization cache
88
     */
89
    public static $fieldsOfTypeFromLayoutCache = [];
90
91
    /**
92
     * @var array Memoization cache
93
     */
94
    public static $matrixFieldsOfTypeCache = [];
95
96
    /**
97
     * @var array Memoization cache
98
     */
99
    public static $neoFieldsOfTypeCache = [];
100
101
    /**
102
     * @var array Memoization cache
103
     */
104
    public static $superTableFieldsOfTypeCache = [];
105
106
    // Static Methods
107
    // =========================================================================
108
109
    /**
110
     * Return all of the fields from the $layout that are of the type
111
     * $fieldClassKey
112
     *
113
     * @param string      $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
114
     * @param FieldLayout $layout
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
115
     * @param bool        $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
116
     *
117
     * @return array
118
     */
119
    public static function fieldsOfTypeFromLayout(
120
        string $fieldClassKey,
121
        FieldLayout $layout,
122
        bool $keysOnly = true
123
    ): array {
124
        $foundFields = [];
125
        if (!empty(self::FIELD_CLASSES[$fieldClassKey])) {
126
            // Cache me if you can
127
            $memoKey = $fieldClassKey.$layout->id.($keysOnly ? 'keys' : 'nokeys');
128
            if (!empty(self::$fieldsOfTypeFromLayoutCache[$memoKey])) {
129
                return self::$fieldsOfTypeFromLayoutCache[$memoKey];
130
            }
131
            $fieldClasses = self::FIELD_CLASSES[$fieldClassKey];
132
            $fields = $layout->getFields();
133
            /** @var  $field BaseField */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
134
            foreach ($fields as $field) {
135
                /** @var array $fieldClasses */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
136
                foreach ($fieldClasses as $fieldClass) {
137
                    if ($field instanceof $fieldClass) {
138
                        $foundFields[$field->handle] = $field->name;
139
                    }
140
                }
141
            }
142
            // Return only the keys if asked
143
            if ($keysOnly) {
144
                $foundFields = array_keys($foundFields);
145
            }
146
            // Cache for future use
147
            self::$fieldsOfTypeFromLayoutCache[$memoKey] = $foundFields;
148
        }
149
150
        return $foundFields;
151
    }
152
153
    /**
154
     * Return all of the fields in the $element of the type $fieldClassKey
155
     *
156
     * @param Element $element
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
157
     * @param string  $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
158
     * @param bool    $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
159
     *
160
     * @return array
161
     */
162
    public static function fieldsOfTypeFromElement(
163
        Element $element,
164
        string $fieldClassKey,
165
        bool $keysOnly = true
166
    ): array {
167
        $foundFields = [];
168
        $layout = $element->getFieldLayout();
169
        if ($layout !== null) {
170
            $foundFields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
171
        }
172
173
        return $foundFields;
174
    }
175
176
    /**
177
     * Return all of the fields from Users layout of the type $fieldClassKey
178
     *
179
     * @param string  $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter type; 2 found
Loading history...
180
     * @param bool    $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 4 found
Loading history...
181
     *
182
     * @return array
183
     */
184
    public static function fieldsOfTypeFromUsers(string $fieldClassKey, bool $keysOnly = true): array
185
    {
186
        $layout = Craft::$app->getFields()->getLayoutByType(User::class);
187
188
        return self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
189
    }
190
191
    /**
192
     * Return all of the fields from all Asset Volume layouts of the type
193
     * $fieldClassKey
194
     *
195
     * @param string $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
196
     * @param bool   $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
197
     *
198
     * @return array
199
     */
200
    public static function fieldsOfTypeFromAssetVolumes(string $fieldClassKey, bool $keysOnly = true): array
201
    {
202
        $foundFields = [];
203
        $volumes = Craft::$app->getVolumes()->getAllVolumes();
204
        foreach ($volumes as $volume) {
205
            /** @var Volume $volume */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
206
            try {
207
                $layout = $volume->getFieldLayout();
208
            } catch (InvalidConfigException $e) {
209
                $layout = null;
210
            }
211
            if ($layout) {
212
                /** @noinspection SlowArrayOperationsInLoopInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
213
                $foundFields = array_merge(
214
                    $foundFields,
215
                    self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
216
                );
217
            }
218
        }
219
220
        return $foundFields;
221
    }
222
223
    /**
224
     * Return all of the fields from all Global Set layouts of the type
225
     * $fieldClassKey
226
     *
227
     * @param string $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
228
     * @param bool   $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
229
     *
230
     * @return array
231
     */
232
    public static function fieldsOfTypeFromGlobals(string $fieldClassKey, bool $keysOnly = true): array
233
    {
234
        $foundFields = [];
235
        $globals = Craft::$app->getGlobals()->getAllSets();
236
        foreach ($globals as $global) {
237
            $layout = $global->getFieldLayout();
238
            if ($layout) {
239
                $fields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
240
                // Prefix the keys with the global set name
241
                $prefix = $global->handle;
242
                $fields = array_combine(
243
                    array_map(function ($key) use ($prefix) {
244
                        return $prefix.'.'.$key;
245
                    }, array_keys($fields)),
246
                    $fields
247
                );
248
                // Merge with any fields we've already found
249
                /** @noinspection SlowArrayOperationsInLoopInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
250
                $foundFields = array_merge(
251
                    $foundFields,
252
                    $fields
0 ignored issues
show
Bug introduced by
It seems like $fields can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

252
                    /** @scrutinizer ignore-type */ $fields
Loading history...
253
                );
254
            }
255
        }
256
257
        return $foundFields;
258
    }
259
260
    /**
261
     * Return all of the fields from the $sourceBundleType in the $sourceHandle
262
     * of the type $fieldClassKey
263
     *
264
     * @param string $sourceBundleType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
265
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
266
     * @param string $fieldClassKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
267
     * @param bool   $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
268
     *
269
     * @return array
270
     */
271
    public static function fieldsOfTypeFromSource(
272
        string $sourceBundleType,
273
        string $sourceHandle,
274
        string $fieldClassKey,
275
        bool $keysOnly = true
276
    ): array {
277
        $foundFields = [];
278
        $layouts = [];
279
        // Get the layouts
280
        if ($sourceBundleType !== MetaBundles::GLOBAL_META_BUNDLE) {
281
            $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($sourceBundleType);
282
            if ($seoElement !== null) {
283
                $layouts = $seoElement::fieldLayouts($sourceHandle);
284
            }
285
        }
286
        // Iterate through the layouts looking for the fields of the type $fieldType
287
        foreach ($layouts as $layout) {
288
            /** @noinspection SlowArrayOperationsInLoopInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
289
            $foundFields = array_merge(
290
                $foundFields,
291
                self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
292
            );
293
        }
294
295
        return $foundFields;
296
    }
297
298
    /**
299
     * Return all of the fields in the $matrixBlock of the type $fieldType class
300
     *
301
     * @param MatrixBlock $matrixBlock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
302
     * @param string      $fieldType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
303
     * @param bool        $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
304
     *
305
     * @return array
306
     */
307
    public static function matrixFieldsOfType(MatrixBlock $matrixBlock, string $fieldType, bool $keysOnly = true): array
308
    {
309
        $foundFields = [];
310
311
        try {
312
            $matrixBlockTypeModel = $matrixBlock->getType();
313
        } catch (InvalidConfigException $e) {
314
            $matrixBlockTypeModel = null;
315
        }
316
        if ($matrixBlockTypeModel) {
317
            // Cache me if you can
318
            $memoKey = $fieldType.$matrixBlock->id.($keysOnly ? 'keys' : 'nokeys');
319
            if (!empty(self::$matrixFieldsOfTypeCache[$memoKey])) {
320
                return self::$matrixFieldsOfTypeCache[$memoKey];
321
            }
322
            $fields = $matrixBlockTypeModel->getFields();
323
            /** @var  $field BaseField */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
324
            foreach ($fields as $field) {
325
                if ($field instanceof $fieldType) {
326
                    $foundFields[$field->handle] = $field->name;
327
                }
328
            }
329
            // Return only the keys if asked
330
            if ($keysOnly) {
331
                $foundFields = array_keys($foundFields);
332
            }
333
            // Cache for future use
334
            self::$matrixFieldsOfTypeCache[$memoKey] = $foundFields;
335
        }
336
337
        return $foundFields;
338
    }
339
340
341
    /**
342
     * Return all of the fields in the $neoBlock of the type $fieldType class
343
     *
344
     * @param NeoBlock $neoBlock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
345
     * @param string   $fieldType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
346
     * @param bool     $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
347
     *
348
     * @return array
349
     */
350
    public static function neoFieldsOfType(NeoBlock $neoBlock, string $fieldType, bool $keysOnly = true): array
351
    {
352
        $foundFields = [];
353
354
        try {
355
            $neoBlockTypeModel = $neoBlock->getType();
356
        } catch (InvalidConfigException $e) {
357
            $neoBlockTypeModel = null;
358
        }
359
        if ($neoBlockTypeModel) {
360
            // Cache me if you can
361
            $memoKey = $fieldType.$neoBlock->id.($keysOnly ? 'keys' : 'nokeys');
362
            if (!empty(self::$neoFieldsOfTypeCache[$memoKey])) {
363
                return self::$neoFieldsOfTypeCache[$memoKey];
364
            }
365
            $fields = $neoBlockTypeModel->getFields();
366
            /** @var  $field BaseField */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
367
            foreach ($fields as $field) {
368
                if ($field instanceof $fieldType) {
369
                    $foundFields[$field->handle] = $field->name;
370
                }
371
            }
372
            // Return only the keys if asked
373
            if ($keysOnly) {
374
                $foundFields = array_keys($foundFields);
375
            }
376
            // Cache for future use
377
            self::$neoFieldsOfTypeCache[$memoKey] = $foundFields;
378
        }
379
380
        return $foundFields;
381
    }
382
383
    /**
384
     * Return all of the fields in the $superTableBlock of the type $fieldType class
385
     *
386
     * @param SuperTableBlock $superTableBlock
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
387
     * @param string          $fieldType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
388
     * @param bool            $keysOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
389
     *
390
     * @return array
391
     */
392
    public static function superTableFieldsOfType(SuperTableBlock $superTableBlock, string $fieldType, bool $keysOnly = true): array
393
    {
394
        $foundFields = [];
395
396
        try {
397
            $superTableBlockTypeModel = $superTableBlock->getType();
398
        } catch (InvalidConfigException $e) {
399
            $superTableBlockTypeModel = null;
400
        }
401
        if ($superTableBlockTypeModel) {
402
            // Cache me if you can
403
            $memoKey = $fieldType.$superTableBlock->id.($keysOnly ? 'keys' : 'nokeys');
404
            if (!empty(self::$superTableFieldsOfTypeCache[$memoKey])) {
405
                return self::$superTableFieldsOfTypeCache[$memoKey];
406
            }
407
            $fields = $superTableBlockTypeModel->getFields();
408
            /** @var  $field BaseField */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
409
            foreach ($fields as $field) {
410
                if ($field instanceof $fieldType) {
411
                    $foundFields[$field->handle] = $field->name;
412
                }
413
            }
414
            // Return only the keys if asked
415
            if ($keysOnly) {
416
                $foundFields = array_keys($foundFields);
417
            }
418
            // Cache for future use
419
            self::$superTableFieldsOfTypeCache[$memoKey] = $foundFields;
420
        }
421
422
        return $foundFields;
423
    }
424
425
}
426