Passed
Push — v3 ( 01a338...22e12d )
by Andrew
53:06 queued 24:15
created

src/helpers/Field.php (1 issue)

Labels
Severity
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;
34
use verbb\supertable\elements\SuperTableBlockElement as SuperTableBlock;
35
36
use benf\neo\Field as NeoField;
37
use benf\neo\elements\Block as NeoBlock;
38
39
use besteadfast\preparsefield\fields\PreparseFieldType;
0 ignored issues
show
The type besteadfast\preparsefield\fields\PreparseFieldType 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...
40
41
use yii\base\InvalidConfigException;
42
43
/**
44
 * @author    nystudio107
45
 * @package   Seomatic
46
 * @since     3.0.0
47
 */
48
class Field
49
{
50
    // Constants
51
    // =========================================================================
52
53
    const TEXT_FIELD_CLASS_KEY = 'text';
54
    const ASSET_FIELD_CLASS_KEY = 'asset';
55
    const BLOCK_FIELD_CLASS_KEY = 'block';
56
    const SEO_SETTINGS_CLASS_KEY = 'seo';
57
    const OLD_SEOMATIC_META_CLASS_KEY = 'Seomatic_Meta';
58
59
    const FIELD_CLASSES = [
60
        self::TEXT_FIELD_CLASS_KEY  => [
61
            CKEditorField::class,
62
            PlainTextField::class,
63
            MatrixField::class,
64
            RedactorField::class,
65
            TagsField::class,
66
            NeoField::class,
67
            SuperTableField::class,
68
            PreparseFieldType::class,
69
        ],
70
        self::ASSET_FIELD_CLASS_KEY => [
71
            AssetsField::class,
72
        ],
73
        self::BLOCK_FIELD_CLASS_KEY => [
74
            MatrixField::class,
75
            NeoField::class,
76
            SuperTableField::class,
77
        ],
78
        self::SEO_SETTINGS_CLASS_KEY => [
79
            SeoSettingsField::class,
80
        ],
81
        self::OLD_SEOMATIC_META_CLASS_KEY => [
82
            Seomatic_MetaField::class,
83
        ],
84
    ];
85
86
    // Static Properties
87
    // =========================================================================
88
89
    /**
90
     * @var array Memoization cache
91
     */
92
    public static $fieldsOfTypeFromLayoutCache = [];
93
94
    /**
95
     * @var array Memoization cache
96
     */
97
    public static $matrixFieldsOfTypeCache = [];
98
99
    /**
100
     * @var array Memoization cache
101
     */
102
    public static $neoFieldsOfTypeCache = [];
103
104
    /**
105
     * @var array Memoization cache
106
     */
107
    public static $superTableFieldsOfTypeCache = [];
108
109
    // Static Methods
110
    // =========================================================================
111
112
    /**
113
     * Return all of the fields from the $layout that are of the type
114
     * $fieldClassKey
115
     *
116
     * @param string      $fieldClassKey
117
     * @param FieldLayout $layout
118
     * @param bool        $keysOnly
119
     *
120
     * @return array
121
     */
122
    public static function fieldsOfTypeFromLayout(
123
        string $fieldClassKey,
124
        FieldLayout $layout,
125
        bool $keysOnly = true
126
    ): array {
127
        $foundFields = [];
128
        if (!empty(self::FIELD_CLASSES[$fieldClassKey])) {
129
            // Cache me if you can
130
            $memoKey = $fieldClassKey.$layout->id.($keysOnly ? 'keys' : 'nokeys');
131
            if (!empty(self::$fieldsOfTypeFromLayoutCache[$memoKey])) {
132
                return self::$fieldsOfTypeFromLayoutCache[$memoKey];
133
            }
134
            $fieldClasses = self::FIELD_CLASSES[$fieldClassKey];
135
            $fields = $layout->getFields();
136
            /** @var  $field BaseField */
137
            foreach ($fields as $field) {
138
                /** @var array $fieldClasses */
139
                foreach ($fieldClasses as $fieldClass) {
140
                    if ($field instanceof $fieldClass) {
141
                        $foundFields[$field->handle] = $field->name;
142
                    }
143
                }
144
            }
145
            // Return only the keys if asked
146
            if ($keysOnly) {
147
                $foundFields = array_keys($foundFields);
148
            }
149
            // Cache for future use
150
            self::$fieldsOfTypeFromLayoutCache[$memoKey] = $foundFields;
151
        }
152
153
        return $foundFields;
154
    }
155
156
    /**
157
     * Return all of the fields in the $element of the type $fieldClassKey
158
     *
159
     * @param Element $element
160
     * @param string  $fieldClassKey
161
     * @param bool    $keysOnly
162
     *
163
     * @return array
164
     */
165
    public static function fieldsOfTypeFromElement(
166
        Element $element,
167
        string $fieldClassKey,
168
        bool $keysOnly = true
169
    ): array {
170
        $foundFields = [];
171
        $layout = $element->getFieldLayout();
172
        if ($layout !== null) {
173
            $foundFields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
174
        }
175
176
        return $foundFields;
177
    }
178
179
    /**
180
     * Return all of the fields from Users layout of the type $fieldClassKey
181
     *
182
     * @param string  $fieldClassKey
183
     * @param bool    $keysOnly
184
     *
185
     * @return array
186
     */
187
    public static function fieldsOfTypeFromUsers(string $fieldClassKey, bool $keysOnly = true): array
188
    {
189
        $layout = Craft::$app->getFields()->getLayoutByType(User::class);
190
191
        return self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
192
    }
193
194
    /**
195
     * Return all of the fields from all Asset Volume layouts of the type
196
     * $fieldClassKey
197
     *
198
     * @param string $fieldClassKey
199
     * @param bool   $keysOnly
200
     *
201
     * @return array
202
     */
203
    public static function fieldsOfTypeFromAssetVolumes(string $fieldClassKey, bool $keysOnly = true): array
204
    {
205
        $foundFields = [];
206
        $volumes = Craft::$app->getVolumes()->getAllVolumes();
207
        foreach ($volumes as $volume) {
208
            /** @var Volume $volume */
209
            try {
210
                $layout = $volume->getFieldLayout();
211
            } catch (InvalidConfigException $e) {
212
                $layout = null;
213
            }
214
            if ($layout) {
215
                /** @noinspection SlowArrayOperationsInLoopInspection */
216
                $foundFields = array_merge(
217
                    $foundFields,
218
                    self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
219
                );
220
            }
221
        }
222
223
        return $foundFields;
224
    }
225
226
    /**
227
     * Return all of the fields from all Global Set layouts of the type
228
     * $fieldClassKey
229
     *
230
     * @param string $fieldClassKey
231
     * @param bool   $keysOnly
232
     *
233
     * @return array
234
     */
235
    public static function fieldsOfTypeFromGlobals(string $fieldClassKey, bool $keysOnly = true): array
236
    {
237
        $foundFields = [];
238
        $globals = Craft::$app->getGlobals()->getAllSets();
239
        foreach ($globals as $global) {
240
            $layout = $global->getFieldLayout();
241
            if ($layout) {
242
                $fields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
243
                // Prefix the keys with the global set name
244
                $prefix = $global->handle;
245
                $fields = array_combine(
246
                    array_map(function ($key) use ($prefix) {
247
                        return $prefix.'.'.$key;
248
                    }, array_keys($fields)),
249
                    $fields
250
                );
251
                // Merge with any fields we've already found
252
                /** @noinspection SlowArrayOperationsInLoopInspection */
253
                $foundFields = array_merge(
254
                    $foundFields,
255
                    $fields
256
                );
257
            }
258
        }
259
260
        return $foundFields;
261
    }
262
263
    /**
264
     * Return all of the fields from the $sourceBundleType in the $sourceHandle
265
     * of the type $fieldClassKey
266
     *
267
     * @param string $sourceBundleType
268
     * @param string $sourceHandle
269
     * @param string $fieldClassKey
270
     * @param bool   $keysOnly
271
     *
272
     * @return array
273
     */
274
    public static function fieldsOfTypeFromSource(
275
        string $sourceBundleType,
276
        string $sourceHandle,
277
        string $fieldClassKey,
278
        bool $keysOnly = true
279
    ): array {
280
        $foundFields = [];
281
        $layouts = [];
282
        // Get the layouts
283
        if ($sourceBundleType !== MetaBundles::GLOBAL_META_BUNDLE) {
284
            $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($sourceBundleType);
285
            if ($seoElement !== null) {
286
                $layouts = $seoElement::fieldLayouts($sourceHandle);
287
            }
288
        }
289
        // Iterate through the layouts looking for the fields of the type $fieldType
290
        foreach ($layouts as $layout) {
291
            /** @noinspection SlowArrayOperationsInLoopInspection */
292
            $foundFields = array_merge(
293
                $foundFields,
294
                self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
295
            );
296
        }
297
298
        return $foundFields;
299
    }
300
301
    /**
302
     * Return all of the fields in the $matrixBlock of the type $fieldType class
303
     *
304
     * @param MatrixBlock $matrixBlock
305
     * @param string      $fieldType
306
     * @param bool        $keysOnly
307
     *
308
     * @return array
309
     */
310
    public static function matrixFieldsOfType(MatrixBlock $matrixBlock, string $fieldType, bool $keysOnly = true): array
311
    {
312
        $foundFields = [];
313
314
        try {
315
            $matrixBlockTypeModel = $matrixBlock->getType();
316
        } catch (InvalidConfigException $e) {
317
            $matrixBlockTypeModel = null;
318
        }
319
        if ($matrixBlockTypeModel) {
320
            // Cache me if you can
321
            $memoKey = $fieldType.$matrixBlock->id.($keysOnly ? 'keys' : 'nokeys');
322
            if (!empty(self::$matrixFieldsOfTypeCache[$memoKey])) {
323
                return self::$matrixFieldsOfTypeCache[$memoKey];
324
            }
325
            $fields = $matrixBlockTypeModel->getFields();
326
            /** @var  $field BaseField */
327
            foreach ($fields as $field) {
328
                if ($field instanceof $fieldType) {
329
                    $foundFields[$field->handle] = $field->name;
330
                }
331
            }
332
            // Return only the keys if asked
333
            if ($keysOnly) {
334
                $foundFields = array_keys($foundFields);
335
            }
336
            // Cache for future use
337
            self::$matrixFieldsOfTypeCache[$memoKey] = $foundFields;
338
        }
339
340
        return $foundFields;
341
    }
342
343
344
    /**
345
     * Return all of the fields in the $neoBlock of the type $fieldType class
346
     *
347
     * @param NeoBlock $neoBlock
348
     * @param string   $fieldType
349
     * @param bool     $keysOnly
350
     *
351
     * @return array
352
     */
353
    public static function neoFieldsOfType(NeoBlock $neoBlock, string $fieldType, bool $keysOnly = true): array
354
    {
355
        $foundFields = [];
356
357
        try {
358
            $neoBlockTypeModel = $neoBlock->getType();
359
        } catch (InvalidConfigException $e) {
360
            $neoBlockTypeModel = null;
361
        }
362
        if ($neoBlockTypeModel) {
363
            // Cache me if you can
364
            $memoKey = $fieldType.$neoBlock->id.($keysOnly ? 'keys' : 'nokeys');
365
            if (!empty(self::$neoFieldsOfTypeCache[$memoKey])) {
366
                return self::$neoFieldsOfTypeCache[$memoKey];
367
            }
368
            $fields = $neoBlockTypeModel->getFields();
369
            /** @var  $field BaseField */
370
            foreach ($fields as $field) {
371
                if ($field instanceof $fieldType) {
372
                    $foundFields[$field->handle] = $field->name;
373
                }
374
            }
375
            // Return only the keys if asked
376
            if ($keysOnly) {
377
                $foundFields = array_keys($foundFields);
378
            }
379
            // Cache for future use
380
            self::$neoFieldsOfTypeCache[$memoKey] = $foundFields;
381
        }
382
383
        return $foundFields;
384
    }
385
386
    /**
387
     * Return all of the fields in the $superTableBlock of the type $fieldType class
388
     *
389
     * @param SuperTableBlock $superTableBlock
390
     * @param string          $fieldType
391
     * @param bool            $keysOnly
392
     *
393
     * @return array
394
     */
395
    public static function superTableFieldsOfType(SuperTableBlock $superTableBlock, string $fieldType, bool $keysOnly = true): array
396
    {
397
        $foundFields = [];
398
399
        try {
400
            $superTableBlockTypeModel = $superTableBlock->getType();
401
        } catch (InvalidConfigException $e) {
402
            $superTableBlockTypeModel = null;
403
        }
404
        if ($superTableBlockTypeModel) {
405
            // Cache me if you can
406
            $memoKey = $fieldType.$superTableBlock->id.($keysOnly ? 'keys' : 'nokeys');
407
            if (!empty(self::$superTableFieldsOfTypeCache[$memoKey])) {
408
                return self::$superTableFieldsOfTypeCache[$memoKey];
409
            }
410
            $fields = $superTableBlockTypeModel->getFields();
411
            /** @var  $field BaseField */
412
            foreach ($fields as $field) {
413
                if ($field instanceof $fieldType) {
414
                    $foundFields[$field->handle] = $field->name;
415
                }
416
            }
417
            // Return only the keys if asked
418
            if ($keysOnly) {
419
                $foundFields = array_keys($foundFields);
420
            }
421
            // Cache for future use
422
            self::$superTableFieldsOfTypeCache[$memoKey] = $foundFields;
423
        }
424
425
        return $foundFields;
426
    }
427
428
}
429