Passed
Push — develop ( 559c3d...7a286f )
by Andrew
09:37
created

MetaItem::tagAttributes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 10
ccs 0
cts 7
cp 0
crap 6
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\base;
13
14
use nystudio107\seomatic\Seomatic;
15
use nystudio107\seomatic\helpers\ArrayHelper;
16
use nystudio107\seomatic\helpers\Dependency;
17
use nystudio107\seomatic\models\MetaJsonLd;
18
19
use Craft;
20
21
use yii\helpers\Inflector;
22
23
/**
24
 * @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...
25
 * @package   Seomatic
26
 * @since     3.0.0
27
 */
28
abstract class MetaItem extends FluentModel implements MetaItemInterface
29
{
30
    // Traits
31
    // =========================================================================
32
33
    use MetaItemTrait;
34
35
    // Constants
36
    // =========================================================================
37
38
    const ARRAY_PROPERTIES = [
39
    ];
40
41
    // Public Methods
42
    // =========================================================================
43
44
    /**
45
     * @inheritdoc
46
     */
47 1
    public function init()
48
    {
49 1
        parent::init();
50
        // Set any per-environment attributes
51 1
        if (!Seomatic::$previewingMetaContainers || Seomatic::$headlessRequest) {
52 1
            $attributes = [];
53 1
            $envVars = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $envVars is dead and can be removed.
Loading history...
54
            try {
55 1
                $envVars = ArrayHelper::getValue($this->environment, Seomatic::$environment);
56
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
57
            }
58 1
            if (\is_array($envVars)) {
59
                foreach ($envVars as $key => $value) {
60
                    $attributes[$key] = $value;
61
                }
62
            }
63 1
            $this->setAttributes($attributes, false);
64
        }
65 1
    }
66
67
    /**
68
     * @inheritdoc
69
     */
70
    public function rules()
71
    {
72
        $rules = parent::rules();
73
        $rules = array_merge($rules, [
74
            [['include', 'key'], 'required'],
75
            [['include'], 'boolean'],
76
            [['key'], 'string'],
77
            [['environment'], 'safe'],
78
            [['dependencies'], 'safe'],
79
            [['tagAttrs'], 'safe'],
80
        ]);
81
82
        return $rules;
83
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88
    public function fields()
89
    {
90
        $fields = parent::fields();
91
        switch ($this->scenario) {
92
            case 'render':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
93
                $fields = array_diff_key(
94
                    $fields,
95
                    array_flip([
96
                        'include',
97
                        'key',
98
                        'environment',
99
                        'dependencies',
100
                        'tagAttrs',
101
                    ])
102
                );
103
                break;
104
        }
105
106
        return $fields;
107
    }
108
109
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $data should have a doc-comment as per coding-style.
Loading history...
110
     * @inheritdoc
111
     */
112 1
    public function prepForRender(&$data): bool
113
    {
114 1
        if ($this->include) {
115 1
            return Dependency::validateDependencies($this->dependencies);
116
        }
117
118
        return false;
119
    }
120
121
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $params should have a doc-comment as per coding-style.
Loading history...
122
     * @inheritdoc
123
     */
124
    public function render(array $params = []): string
125
    {
126
        return '';
127
    }
128
129
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $params should have a doc-comment as per coding-style.
Loading history...
130
     * @inheritdoc
131
     */
132
    public function renderAttributes(array $params = []): array
133
    {
134
        return [];
135
    }
136
137
    /**
138
     * Add debug logging for the MetaItem
139
     *
140
     * @param string $errorLabel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
141
     * @param array  $scenarios
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
142
     */
143
    public function debugMetaItem(
144
        $errorLabel = 'Error: ',
145
        array $scenarios = ['default' => 'error']
146
    ) {
147
        $isMetaJsonLdModel = false;
148
        if (is_subclass_of($this, MetaJsonLd::class)) {
149
            $isMetaJsonLdModel = true;
150
        }
151
        $modelScenarios = $this->scenarios();
152
        $scenarios = array_intersect_key($scenarios, $modelScenarios);
153
        foreach ($scenarios as $scenario => $logLevel) {
154
            $this->setScenario($scenario);
155
            if (!$this->validate()) {
156
                $extraInfo = '';
157
                // Add a URL to the schema.org type if this is a MetaJsonLD object
158
                if ($isMetaJsonLdModel) {
159
                    /** @var  $this MetaJsonLd */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
160
                    $extraInfo = ' for http://schema.org/' . $this->type;
161
                }
162
                $errorMsg =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
163
                    Craft::t('seomatic', 'Scenario: "')
164
                    . $scenario
165
                    . '"'
166
                    . $extraInfo
167
                    . PHP_EOL
168
                    . print_r($this->render(), true);
0 ignored issues
show
Bug introduced by
Are you sure print_r($this->render(), true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

168
                    . /** @scrutinizer ignore-type */ print_r($this->render(), true);
Loading history...
169
                Craft::info($errorMsg, __METHOD__);
170
                foreach ($this->errors as $param => $errors) {
171
                    $errorMsg = Craft::t('seomatic', $errorLabel) . $param;
172
                    /** @var array $errors */
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...
173
                    foreach ($errors as $error) {
174
                        $errorMsg .= ' -> ' . $error;
175
                        // Change the error level depending on the error message if this is a MetaJsonLD object
176
                        if ($isMetaJsonLdModel) {
177
                            if (strpos($error, 'recommended') !== false) {
178
                                $logLevel = 'warning';
179
                            }
180
                            if (strpos($error, 'required') !== false
181
                                || strpos($error, 'Must be') !== false
182
                            ) {
183
                                $logLevel = 'error';
184
                            }
185
                        }
186
                    }
187
                    Craft::info(strtoupper($logLevel).' - '.$errorMsg, __METHOD__);
188
                    // Extra debugging info for MetaJsonLd objects
189
                    if ($isMetaJsonLdModel) {
190
                        /** @var MetaJsonLd $className  */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
191
                        $className = \get_class($this);
192
                        if (!empty($className::$schemaPropertyDescriptions[$param])) {
193
                            $errorMsg = Craft::t('seomatic', $errorLabel) . $param;
194
                            /** @var $className MetaJsonLd */
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...
195
                            $errorMsg .= ' -> ' . $className::$schemaPropertyDescriptions[$param];
196
                            Craft::info($errorMsg, __METHOD__);
197
                        }
198
                    }
199
                }
200
            }
201
        }
202
    }
203
204
    /**
205
     * Return an array of tag attributes, normalizing the keys
206
     *
207
     * @return array
208
     */
209
    public function tagAttributes(): array
210
    {
211
        $tagAttributes = array_merge($this->toArray(), $this->tagAttrs);
212
        $tagAttributes = array_filter($tagAttributes);
213
        foreach ($tagAttributes as $key => $value) {
214
            ArrayHelper::rename($tagAttributes, $key, Inflector::slug(Inflector::titleize($key)));
215
        }
216
        ksort($tagAttributes);
217
218
        return $tagAttributes;
219
    }
220
221
    /**
222
     * Return an array of arrays that contain the meta tag attributes
223
     *
224
     * @return array
225
     */
226
    public function tagAttributesArray(): array
227
    {
228
        $result = [];
229
        $optionsCount = 1;
230
        $scenario = $this->scenario;
231
        $this->setScenario('render');
232
        $options = $this->tagAttributes();
233
        $this->setScenario($scenario);
234
235
        // See if any of the potentially array properties actually are
236
        foreach (static::ARRAY_PROPERTIES as $arrayProperty) {
237
            if (!empty($options[$arrayProperty]) && \is_array($options[$arrayProperty])) {
238
                $optionsCount = \count($options[$arrayProperty]) > $optionsCount
239
                    ? \count($options[$arrayProperty]) : $optionsCount;
240
            }
241
        }
242
        // Return an array of resulting options
243
        while ($optionsCount--) {
244
            $resultOptions = $options;
245
            foreach ($resultOptions as $key => $value) {
246
                $resultOptions[$key] = (\is_array($value) && isset($value[$optionsCount]))
247
                    ? $value[$optionsCount] : $value;
248
            }
249
            $result[] = $resultOptions;
250
        }
251
252
        return $result;
253
    }
254
255
    /**
256
     * Validate the passed in $attribute as either an array or a string
257
     *
258
     * @param mixed $attribute the attribute currently being validated
259
     * @param mixed $params    the value of the "params" given in the rule
260
     */
261
    public function validateStringOrArray(
262
        $attribute,
263
        $params
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

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

263
        /** @scrutinizer ignore-unused */ $params

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

Loading history...
264
    ) {
265
        $validated = false;
266
        if (\is_string($attribute)) {
267
            $validated = true;
268
        }
269
        if (\is_array($attribute)) {
270
            $validated = true;
271
        }
272
        if (!$validated) {
273
            $this->addError($attribute, 'Must be either a string or an array');
274
        }
275
    }
276
}
277