MetaBundle::behaviors()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 0
dl 0
loc 16
ccs 0
cts 6
cp 0
crap 6
rs 9.9666
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\models;
13
14
use craft\behaviors\EnvAttributeParserBehavior;
15
use craft\helpers\Json as JsonHelper;
16
use craft\validators\ArrayValidator;
17
use craft\validators\DateTimeValidator;
18
use DateTime;
19
use nystudio107\seomatic\base\FluentModel;
20
use nystudio107\seomatic\base\MetaContainer;
21
use nystudio107\seomatic\helpers\ArrayHelper;
22
use nystudio107\seomatic\helpers\MetaValue as MetaValueHelper;
23
use nystudio107\seomatic\Seomatic;
24
use nystudio107\seomatic\variables\SeomaticVariable;
25
use yii\behaviors\AttributeTypecastBehavior;
26
use function is_array;
27
use function is_string;
28
29
/**
30
 * @author    nystudio107
31
 * @package   Seomatic
32
 * @since     3.0.0
33
 */
34
class MetaBundle extends FluentModel
35
{
36
    // Properties
37
    // =========================================================================
38
39
    /**
40
     * @var string
41
     */
42
    public $bundleVersion;
43
44
    /**
45
     * @var string
46
     */
47
    public $sourceBundleType;
48
49
    /**
50
     * @var int
51
     */
52
    public $sourceId;
53
54
    /**
55
     * @var string
56
     */
57
    public $sourceName;
58
59
    /**
60
     * @var string
61
     */
62
    public $sourceHandle;
63
64
    /**
65
     * @var string
66
     */
67
    public $sourceType;
68
69
    /**
70
     * @var int|null
71
     */
72
    public $typeId;
73
74
    /**
75
     * @var string
76
     */
77
    public $sourceTemplate;
78
79
    /**
80
     * @var int
81
     */
82
    public $sourceSiteId;
83
84
    /**
85
     * @var array
86
     */
87
    public $sourceAltSiteSettings = [];
88
89
    /**
90
     * @var DateTime
91
     */
92
    public $sourceDateUpdated;
93
94
    /**
95
     * @var MetaGlobalVars|array|null
96
     */
97
    public $metaGlobalVars;
98
99
    /**
100
     * @var MetaSiteVars|array|null
101
     */
102
    public $metaSiteVars;
103
104
    /**
105
     * @var MetaSitemapVars|array|null
106
     */
107
    public $metaSitemapVars;
108
109
    /**
110
     * @var MetaContainer[]|array|null
111
     */
112
    public $metaContainers;
113
114
    /**
115
     * @var array
116
     */
117
    public $redirectsContainer;
118
119
    /**
120
     * @var FrontendTemplateContainer|array|null
121
     */
122
    public $frontendTemplatesContainer;
123
124
    /**
125
     * @var MetaBundleSettings|array|null
126
     */
127
    public $metaBundleSettings;
128
129
    // Methods
130
    // =========================================================================
131
132
    /**
133
     * Create a new meta bundle
134
     *
135
     * @param array $config
136
     * @param bool $parse Whether the resulting metabundle should be parsed
137
     *
138
     * @return null|MetaBundle
139
     */
140
    public static function create(array $config = [], bool $parse = true)
141
    {
142
        self::cleanProperties(__CLASS__, $config);
143
        $model = new MetaBundle($config);
144
        $model->normalizeMetaBundleData($parse);
145
146
        return $model;
147
    }
148
149
    /**
150
     * Normalizes the meta bundles’s data for use.
151
     *
152
     * This is called after meta bundle data is loaded, to allow it to be
153
     * parsed, models instantiated, etc.
154
     *
155
     * @param bool $parse Whether the resulting metabundle should be parsed
156
     */
157
    public function normalizeMetaBundleData(bool $parse = true)
158
    {
159
        // Decode any JSON data
160
        $properties = $this->getAttributes();
161
        foreach ($properties as $property => $value) {
162
            if (!empty($value) && is_string($value)) {
163
                $this->$property = JsonHelper::decodeIfJson($value);
164
            }
165
        }
166
167
        // Meta global variables
168
        if (is_array($this->metaGlobalVars)) {
169
            $this->metaGlobalVars = MetaGlobalVars::create($this->metaGlobalVars);
170
        }
171
        // Meta site variables
172
        if (is_array($this->metaSiteVars)) {
173
            $this->metaSiteVars = MetaSiteVars::create($this->metaSiteVars);
174
        }
175
        // Meta sitemap variables
176
        if (is_array($this->metaSitemapVars)) {
177
            $this->metaSitemapVars = MetaSitemapVars::create($this->metaSitemapVars);
178
        }
179
        // Meta bundle settings
180
        if (is_array($this->metaBundleSettings)) {
181
            $this->metaBundleSettings = MetaBundleSettings::create($this->metaBundleSettings);
182
        }
183
        // Frontend templates
184
        if (is_array($this->frontendTemplatesContainer)) {
185
            $this->frontendTemplatesContainer = FrontendTemplateContainer::create($this->frontendTemplatesContainer);
186
        }
187
        // Create our variable so that meta containers can be parsed based on dynamic values
188
        // Make sure Twig is loaded and instantiated first by priming the pump
189
        if ($parse) {
190
            MetaValueHelper::parseString('{{ "prime" }}');
191
            $oldSeomaticVariable = Seomatic::$seomaticVariable;
192
            if (Seomatic::$seomaticVariable === null) {
193
                Seomatic::$seomaticVariable = new SeomaticVariable();
194
            }
195
            $oldMeta = Seomatic::$seomaticVariable->meta;
196
            $oldSite = Seomatic::$seomaticVariable->site;
197
            $oldLoadingContainers = Seomatic::$loadingMetaContainers;
198
            $oldPreviewingMetaContainers = Seomatic::$previewingMetaContainers;
199
            Seomatic::$loadingMetaContainers = false;
200
            Seomatic::$previewingMetaContainers = false;
201
            // Merge these global vars with the MetaContainers global vars
202
            $globalVars = [];
203
            if (Seomatic::$plugin->metaContainers->metaGlobalVars !== null) {
204
                $globalVars = Seomatic::$plugin->metaContainers->metaGlobalVars->getAttributes();
205
            }
206
            $thisGlobalVars = $this->metaGlobalVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

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

206
            /** @scrutinizer ignore-call */ 
207
            $thisGlobalVars = $this->metaGlobalVars->getAttributes();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
207
            $thisGlobals = MetaGlobalVars::create(ArrayHelper::merge($globalVars, $thisGlobalVars));
208
            // Merge these site vars with the MetaContainers site vars
209
            $siteVars = [];
210
            if (Seomatic::$plugin->metaContainers->metaSiteVars !== null) {
211
                $siteVars = Seomatic::$plugin->metaContainers->metaSiteVars->getAttributes();
212
            }
213
            $thisSiteVars = $this->metaSiteVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

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

213
            /** @scrutinizer ignore-call */ 
214
            $thisSiteVars = $this->metaSiteVars->getAttributes();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
214
            $thisSite = MetaSiteVars::create(ArrayHelper::merge($siteVars, $thisSiteVars));
215
            Seomatic::$seomaticVariable->meta = $thisGlobals;
216
            Seomatic::$seomaticVariable->site = $thisSite;
217
            MetaValueHelper::cache();
218
            Seomatic::$previewingMetaContainers = $oldPreviewingMetaContainers;
219
220
            // Meta containers
221
            if (!empty($this->metaContainers)) {
222
                $metaContainers = $this->metaContainers;
223
                $this->metaContainers = [];
224
                foreach ($metaContainers as $key => $metaContainer) {
225
                    /** @var MetaContainer $containerClass */
226
                    $containerClass = $metaContainer['class'];
227
                    /**  @var array $metaContainer */
228
                    $this->metaContainers[$key] = $containerClass::create($metaContainer);
229
                }
230
            }
231
            // Restore the $seomaticVariable
232
            Seomatic::$loadingMetaContainers = $oldLoadingContainers;
233
            Seomatic::$seomaticVariable->meta = $oldMeta;
234
            Seomatic::$seomaticVariable->site = $oldSite;
235
            Seomatic::$seomaticVariable = $oldSeomaticVariable;
236
            MetaValueHelper::cache();
237
        }
238
    }
239
240
    /**
241
     * @inheritdoc
242
     */
243
    public function datetimeAttributes(): array
244
    {
245
        $names = parent::datetimeAttributes();
246
        $names[] = 'sourceDateUpdated';
247
248
        return $names;
249
    }
250
251
    /**
252
     * Validation rules
253
     * @return array the validation rules
254
     */
255
    public function rules(): array
256
    {
257
        $rules = [
258
            [
259
                [
260
                    'bundleVersion',
261
                    'sourceType',
262
                    'sourceName',
263
                    'sourceHandle',
264
                    'sourceTemplate',
265
                    'sourceType',
266
                ],
267
                'string',
268
            ],
269
            [
270
                [
271
                    'sourceId',
272
                    'sourceSiteId',
273
                    'typeId',
274
                ],
275
                'number',
276
                'skipOnEmpty' => true,
277
            ],
278
            [
279
                [
280
                    'sourceDateUpdated',
281
                ],
282
                DateTimeValidator::class,
283
            ],
284
            [
285
                [
286
                    'sourceAltSiteSettings',
287
                ],
288
                'safe',
289
            ],
290
            [
291
                [
292
                    'metaContainers',
293
                    'redirectsContainer',
294
                ],
295
                ArrayValidator::class,
296
            ],
297
            [
298
                [
299
                    'metaGlobalVars',
300
                    'metaSiteVars',
301
                    'metaSitemapVars',
302
                    'metaBundleSettings',
303
                    'frontendTemplatesContainer',
304
                ],
305
                'safe',
306
            ],
307
        ];
308
309
        return $rules;
310
    }
311
312
    /**
313
     * @return array
314
     */
315
    public function behaviors()
316
    {
317
        $craft31Behaviors = [];
318
        if (Seomatic::$craft31) {
319
            $craft31Behaviors = [
320
                'parser' => [
321
                    'class' => EnvAttributeParserBehavior::class,
322
                    'attributes' => [
323
                    ],
324
                ],
325
            ];
326
        }
327
328
        return array_merge($craft31Behaviors, [
329
            'typecast' => [
330
                'class' => AttributeTypecastBehavior::class,
331
                // 'attributeTypes' will be composed automatically according to `rules()`
332
            ],
333
        ]);
334
    }
335
}
336