Passed
Push — v3 ( 5141f6...ef9227 )
by Andrew
31:01 queued 18:03
created

MetaItemAttributeParserBehavior::events()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 5
ccs 0
cts 5
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
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\behaviors;
13
14
use nystudio107\seomatic\helpers\MetaValue as MetaValueHelper;
15
use yii\base\Behavior;
16
use yii\base\Model;
17
use yii\validators\UrlValidator;
18
19
/**
20
 * MetaItemAttributeParserBehavior can be applied to models with attributes that can be
21
 * parsed as twig expressions
22
 *
23
 * ---
24
 *
25
 * ```php
26
 * public function behaviors(): array
27
 * {
28
 *     return [
29
 *         'parser' => [
30
 *             'class' => MetaItemAttributeParserBehavior::class,
31
 *             'attributes' => ['attr1', 'attr2', '...'],
32
 *         ],
33
 *     ];
34
 * }
35
 * ```
36
 */
37
class MetaItemAttributeParserBehavior extends Behavior
38
{
39
    /**
40
     * @var Model
41
     */
42
    public $owner;
43
44
    /**
45
     * @var string[]|callable[] The attributes names that can be parsed as Twig expressions
46
     *
47
     * If the raw (unparsed) attribute value can’t be obtained from the attribute directly (`$model->foo`),
48
     * then the attribute name should be specified as an array key instead, and the value should be set to the
49
     * raw value, or a callable that returns the raw value. For example:
50
     *
51
     * ```php
52
     * 'attributes' => [
53
     *     'foo' => '$FOO',
54
     *     'bar' => function() {
55
     *         return $this->_bar;
56
     *     },
57
     * ],
58
     * ```
59
     */
60
    public array $attributes = [];
61
62
    /**
63
     * @var array Keeps track of the original attribute values
64
     */
65
    private array $originalAttributes;
66
67
    /**
68
     * @inheritdoc
69
     */
70
    public function events(): array
71
    {
72
        return [
73
            Model::EVENT_BEFORE_VALIDATE => 'beforeValidate',
74
            Model::EVENT_AFTER_VALIDATE => 'afterValidate',
75
        ];
76
    }
77
78
    /**
79
     * Replaces attribute values before validation occurs.
80
     */
81
    public function beforeValidate(): void
82
    {
83
        $this->originalAttributes = [];
84
85
        // Default the attributes to the available fields in the `render` scenario if empty
86
        if (empty($this->attributes)) {
87
            $oldScenario = $this->owner->getScenario();
88
            $this->owner->setScenario('render');
89
            $this->attributes = $this->owner->fields();
90
            $this->owner->setScenario($oldScenario);
91
        }
92
        // Swap in parsed versions of the attributes before validation
93
        foreach ($this->attributes as $i => $attribute) {
94
            if ($i === 'dateCreated') {
95
                continue;
96
            }
97
            $value = $this->owner->$attribute;
98
99
            if (($parsed = MetaValueHelper::parseString($value)) !== $value) {
100
                $this->originalAttributes[$attribute] = $value;
101
                $this->owner->$attribute = $parsed;
102
103
                foreach ($this->owner->getActiveValidators($attribute) as $validator) {
104
                    if ($validator instanceof UrlValidator) {
105
                        $validator->defaultScheme = null;
106
                    }
107
                }
108
            }
109
        }
110
    }
111
112
    /**
113
     * Restores the original attribute values after validation occurs.
114
     */
115
    public function afterValidate(): void
116
    {
117
        foreach ($this->originalAttributes as $attribute => $value) {
118
            $this->owner->$attribute = $value;
119
        }
120
    }
121
122
    /**
123
     * Returns the original value of an attribute, or `null` if it wasn’t set to an environment variable or alias.
124
     *
125
     * @param string $attribute
126
     * @return string|null
127
     */
128
    public function getUnparsedAttribute(string $attribute): ?string
129
    {
130
        return $this->originalAttributes[$attribute] ?? null;
131
    }
132
}
133