Passed
Push — develop ( 7e4bcd...4ac306 )
by Andrew
04:31
created

Field::getElementRootClass()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 8
nop 1
dl 0
loc 16
rs 10
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\Category;
26
use craft\elements\Entry;
27
use craft\elements\MatrixBlock;
28
use craft\fields\Assets as AssetsField;
29
use craft\fields\Matrix as MatrixField;
30
use craft\fields\PlainText as PlainTextField;
31
use craft\fields\Tags as TagsField;
32
use craft\models\FieldLayout;
33
use craft\redactor\Field as RedactorField;
34
35
use craft\commerce\Plugin as CommercePlugin;
0 ignored issues
show
Bug introduced by
The type craft\commerce\Plugin 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...
36
use craft\commerce\elements\Product;
0 ignored issues
show
Bug introduced by
The type craft\commerce\elements\Product 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
38
use yii\base\InvalidConfigException;
39
40
/**
41
 * @author    nystudio107
42
 * @package   Seomatic
43
 * @since     3.0.0
44
 */
45
class Field
46
{
47
    // Constants
48
    // =========================================================================
49
50
    const TEXT_FIELD_CLASS_KEY = 'text';
51
    const ASSET_FIELD_CLASS_KEY = 'asset';
52
    const BLOCK_FIELD_CLASS_KEY = 'block';
53
    const SEO_SETTINGS_CLASS_KEY = 'seo';
54
    const OLD_SEOMATIC_META_CLASS_KEY = 'Seomatic_Meta';
55
56
    const FIELD_CLASSES = [
57
        self::TEXT_FIELD_CLASS_KEY  => [
58
            CKEditorField::class,
59
            PlainTextField::class,
60
            MatrixField::class,
61
            RedactorField::class,
62
            TagsField::class,
63
        ],
64
        self::ASSET_FIELD_CLASS_KEY => [
65
            AssetsField::class,
66
        ],
67
        self::BLOCK_FIELD_CLASS_KEY => [
68
            MatrixField::class,
69
        ],
70
        self::SEO_SETTINGS_CLASS_KEY => [
71
            SeoSettingsField::class,
72
        ],
73
        self::OLD_SEOMATIC_META_CLASS_KEY => [
74
            Seomatic_MetaField::class,
75
        ],
76
    ];
77
78
    // Static Methods
79
    // =========================================================================
80
81
    /**
82
     * Return all of the fields from the $layout that are of the type
83
     * $fieldClassKey
84
     *
85
     * @param string      $fieldClassKey
86
     * @param FieldLayout $layout
87
     * @param bool        $keysOnly
88
     *
89
     * @return array
90
     */
91
    public static function fieldsOfTypeFromLayout(
92
        string $fieldClassKey,
93
        FieldLayout $layout,
94
        bool $keysOnly = true
95
    ): array {
96
        $foundFields = [];
97
        if (!empty(self::FIELD_CLASSES[$fieldClassKey])) {
98
            $fieldClasses = self::FIELD_CLASSES[$fieldClassKey];
99
            $fields = $layout->getFields();
100
            /** @var  $field BaseField */
101
            foreach ($fields as $field) {
102
                /** @var array $fieldClasses */
103
                foreach ($fieldClasses as $fieldClass) {
104
                    if ($field instanceof $fieldClass) {
105
                        $foundFields[$field->handle] = $field->name;
106
                    }
107
                }
108
            }
109
        }
110
111
        // Return only the keys if asked
112
        if ($keysOnly) {
113
            $foundFields = array_keys($foundFields);
114
        }
115
116
        return $foundFields;
117
    }
118
119
    /**
120
     * Return all of the fields in the $element of the type $fieldClassKey
121
     *
122
     * @param Element $element
123
     * @param string  $fieldClassKey
124
     * @param bool    $keysOnly
125
     *
126
     * @return array
127
     */
128
    public static function fieldsOfTypeFromElement(
129
        Element $element,
130
        string $fieldClassKey,
131
        bool $keysOnly = true
132
    ): array {
133
        $foundFields = [];
134
        $layout = $element->getFieldLayout();
135
        if ($layout !== null) {
136
            $foundFields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
137
        }
138
139
        return $foundFields;
140
    }
141
142
    /**
143
     * Return all of the fields from Users layout of the type $fieldClassKey
144
     *
145
     * @param string  $fieldClassKey
146
     * @param bool    $keysOnly
147
     *
148
     * @return array
149
     */
150
    public static function fieldsOfTypeFromUsers(string $fieldClassKey, bool $keysOnly = true): array
151
    {
152
        $layout = Craft::$app->getFields()->getLayoutByType(User::class);
153
154
        return self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
155
    }
156
157
    /**
158
     * Return all of the fields from all Asset Volume layouts of the type
159
     * $fieldClassKey
160
     *
161
     * @param string $fieldClassKey
162
     * @param bool   $keysOnly
163
     *
164
     * @return array
165
     */
166
    public static function fieldsOfTypeFromAssetVolumes(string $fieldClassKey, bool $keysOnly = true): array
167
    {
168
        $foundFields = [];
169
        $volumes = Craft::$app->getVolumes()->getAllVolumes();
170
        foreach ($volumes as $volume) {
171
            /** @var Volume $volume */
172
            try {
173
                $layout = $volume->getFieldLayout();
174
            } catch (InvalidConfigException $e) {
175
                $layout = null;
176
            }
177
            if ($layout) {
178
                $foundFields = array_merge(
179
                    $foundFields,
180
                    self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
181
                );
182
            }
183
        }
184
185
        return $foundFields;
186
    }
187
188
    /**
189
     * Return all of the fields from all Global Set layouts of the type
190
     * $fieldClassKey
191
     *
192
     * @param string $fieldClassKey
193
     * @param bool   $keysOnly
194
     *
195
     * @return array
196
     */
197
    public static function fieldsOfTypeFromGlobals(string $fieldClassKey, bool $keysOnly = true): array
198
    {
199
        $foundFields = [];
200
        $globals = Craft::$app->getGlobals()->getAllSets();
201
        foreach ($globals as $global) {
202
            $layout = $global->getFieldLayout();
203
            if ($layout) {
204
                $fields = self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly);
205
                // Prefix the keys with the global set name
206
                $prefix = $global->handle;
207
                $fields = array_combine(
208
                    array_map(function ($key) use ($prefix) {
209
                        return $prefix.'.'.$key;
210
                    }, array_keys($fields)),
211
                    $fields
212
                );
213
                // Merge with any fields we've already found
214
                $foundFields = array_merge(
215
                    $foundFields,
216
                    $fields
217
                );
218
            }
219
        }
220
221
        return $foundFields;
222
    }
223
224
    /**
225
     * Return all of the fields from the $sourceBundleType in the $sourceHandle
226
     * of the type $fieldClassKey
227
     *
228
     * @param string $sourceBundleType
229
     * @param string $sourceHandle
230
     * @param string $fieldClassKey
231
     * @param bool   $keysOnly
232
     *
233
     * @return array
234
     */
235
    public static function fieldsOfTypeFromSource(
236
        string $sourceBundleType,
237
        string $sourceHandle,
238
        string $fieldClassKey,
239
        bool $keysOnly = true
240
    ): array {
241
        $foundFields = [];
242
        $layouts = [];
243
        // Get the layouts
244
        switch ($sourceBundleType) {
245
            case MetaBundles::GLOBAL_META_BUNDLE:
246
                break;
247
248
            case MetaBundles::SECTION_META_BUNDLE:
249
                $entryTypes = Craft::$app->getSections()->getSectionByHandle($sourceHandle)->getEntryTypes();
250
                foreach ($entryTypes as $entryType) {
251
                    $layouts[] = Craft::$app->getFields()->getLayoutById($entryType->fieldLayoutId);
252
                }
253
                break;
254
255
            case MetaBundles::CATEGORYGROUP_META_BUNDLE:
256
                try {
257
                    $layoutId = Craft::$app->getCategories()->getGroupByHandle($sourceHandle)->getFieldLayoutId();
258
                } catch (InvalidConfigException $e) {
259
                    $layoutId = null;
260
                }
261
                if ($layoutId) {
262
                    $layouts[] = Craft::$app->getFields()->getLayoutById($layoutId);
263
                }
264
                break;
265
            case MetaBundles::PRODUCT_META_BUNDLE:
266
                if (Seomatic::$commerceInstalled) {
267
                    $commerce = CommercePlugin::getInstance();
268
                    if ($commerce !== null) {
269
                        try {
270
                            $layoutId = $commerce->productTypes->getProductTypeByHandle($sourceHandle)->getFieldLayoutId();
271
                        } catch (InvalidConfigException $e) {
272
                            $layoutId = null;
273
                        }
274
                        if ($layoutId) {
275
                            $layouts[] = Craft::$app->getFields()->getLayoutById($layoutId);
276
                        }
277
                    }
278
                }
279
                break;
280
        }
281
        // Iterate through the layouts looking for the fields of the type $fieldType
282
        foreach ($layouts as $layout) {
283
            $foundFields = array_merge(
284
                $foundFields,
285
                self::fieldsOfTypeFromLayout($fieldClassKey, $layout, $keysOnly)
286
            );
287
        }
288
289
        return $foundFields;
290
    }
291
292
    /**
293
     * Return all of the fields in the $matrixBlock of the type $fieldType class
294
     *
295
     * @param MatrixBlock $matrixBlock
296
     * @param string      $fieldType
297
     * @param bool        $keysOnly
298
     *
299
     * @return array
300
     */
301
    public static function matrixFieldsOfType(MatrixBlock $matrixBlock, string $fieldType, bool $keysOnly = true): array
302
    {
303
        $foundFields = [];
304
305
        try {
306
            $matrixBlockTypeModel = $matrixBlock->getType();
307
        } catch (InvalidConfigException $e) {
308
            $matrixBlockTypeModel = null;
309
        }
310
        if ($matrixBlockTypeModel) {
311
            $fields = $matrixBlockTypeModel->getFields();
312
            /** @var  $field BaseField */
313
            foreach ($fields as $field) {
314
                if ($field instanceof $fieldType) {
315
                    $foundFields[$field->handle] = $field->name;
316
                }
317
            }
318
        }
319
320
        // Return only the keys if asked
321
        if ($keysOnly) {
322
            $foundFields = array_keys($foundFields);
323
        }
324
325
        return $foundFields;
326
    }
327
328
    /**
329
     * Get the root class of a passed in Element
330
     *
331
     * @param Element $element
332
     *
333
     * @return string
334
     */
335
    public static function getElementRootClass(Element $element): string
336
    {
337
        // By default, just use the class name
338
        $className = \get_class($element);
339
        // Handle sub-classes of specific types we know about
340
        if ($element instanceof Entry) {
341
            $className = Entry::class;
342
        }
343
        if ($element instanceof Category) {
344
            $className = Category::class;
345
        }
346
        if ($element instanceof Product) {
347
            $className = Product::class;
348
        }
349
350
        return $className;
351
    }
352
}
353