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

MetaJsonLdContainer::includeMetaData()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 21
c 1
b 1
f 0
dl 0
loc 31
ccs 0
cts 20
cp 0
rs 9.584
cc 3
nc 4
nop 1
crap 12
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;
15
use craft\helpers\Html;
16
use nystudio107\seomatic\base\NonceContainer;
17
use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper;
18
use nystudio107\seomatic\helpers\MetaValue as MetaValueHelper;
19
use nystudio107\seomatic\Seomatic;
20
use yii\caching\TagDependency;
21
use yii\web\View;
22
23
/**
24
 * @author    nystudio107
25
 * @package   Seomatic
26
 * @since     3.0.0
27
 */
28
class MetaJsonLdContainer extends NonceContainer
29
{
30
    // Constants
31
    // =========================================================================
32
33
    const CONTAINER_TYPE = 'MetaJsonLdContainer';
34
35
    // Public Properties
36
    // =========================================================================
37
38
    /**
39
     * The data in this container
40
     *
41
     * @var MetaJsonLd[] $data
42
     */
43
    public $data = [];
44
45
    // Public Methods
46
    // =========================================================================
47
48
    /**
49
     * @inheritdoc
50
     */
51
    public function includeMetaData($dependency)
52
    {
53
        Craft::beginProfile('MetaJsonLdContainer::includeMetaData', __METHOD__);
54
        $uniqueKey = $this->handle . $dependency->tags[3] . '-v2';
55
        $cache = Craft::$app->getCache();
56
        if ($this->clearCache) {
57
            TagDependency::invalidate($cache, $dependency->tags[3]);
58
        }
59
        [$jsonLd, $attrs] = $cache->getOrSet(
60
            self::CONTAINER_TYPE . $uniqueKey,
61
            function () use ($uniqueKey) {
62
                Craft::info(
63
                    self::CONTAINER_TYPE . ' cache miss: ' . $uniqueKey,
64
                    __METHOD__
65
                );
66
                
67
                return $this->renderInternal();
68
            },
69
            Seomatic::$cacheDuration,
70
            $dependency
71
        );
72
        // Invalidate the cache we just created if there were pending image transforms in it
73
        if (ImageTransformHelper::$pendingImageTransforms) {
74
            TagDependency::invalidate($cache, $dependency->tags[3]);
75
        }
76
        Seomatic::$view->registerScript(
77
            $jsonLd,
78
            View::POS_END,
79
            $attrs
80
        );
81
        Craft::endProfile('MetaJsonLdContainer::includeMetaData', __METHOD__);
82
    }
83
84
    /**
85
     * @inheritdoc
86
     */
87
    public function render(array $params = []): string
88
    {
89
        [$jsonLd, $attrs] = $this->renderInternal();
90
91
        return trim(Html::script($jsonLd, $attrs));
92
    }
93
94
    /**
95
     * @inheritdoc
96
     */
97
    public function normalizeContainerData()
98
    {
99
        parent::normalizeContainerData();
100
101
        foreach ($this->data as $key => $config) {
102
            $schemaType = $config['type'] ?? $config['@type'];
103
            $config['key'] = $key;
104
            $schemaType = MetaValueHelper::parseString($schemaType);
105
            $jsonLd = MetaJsonLd::create($schemaType, $config);
0 ignored issues
show
Bug introduced by
$config of type nystudio107\seomatic\models\MetaJsonLd is incompatible with the type array expected by parameter $config of nystudio107\seomatic\models\MetaJsonLd::create(). ( Ignorable by Annotation )

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

105
            $jsonLd = MetaJsonLd::create($schemaType, /** @scrutinizer ignore-type */ $config);
Loading history...
106
            // Retain the intended type
107
            $jsonLd->type = $config['type'] ?? $config['@type'];
108
            $this->data[$key] = $jsonLd;
109
        }
110
    }
111
112
    // Protected Methods
113
    // =========================================================================
114
115
    /**
116
     * Render the JSON-LD as a graph
117
     *
118
     * @return array
119
     */
120
    protected function renderInternal(): array
121
    {
122
        $tagData = [];
123
        if ($this->prepForInclusion()) {
124
            /** @var $metaJsonLdModel MetaJsonLd */
125
            foreach ($this->data as $metaJsonLdModel) {
126
                if ($metaJsonLdModel->include) {
127
                    $options = $metaJsonLdModel->tagAttributes();
128
                    if ($metaJsonLdModel->prepForRender($options)) {
129
                        $tagData[] = [
130
                            'jsonLd' => $metaJsonLdModel,
131
                            'position' => View::POS_END
132
                        ];
133
                        // If `devMode` is enabled, validate the JSON-LD and output any model errors
134
                        if (Seomatic::$devMode) {
135
                            $metaJsonLdModel->debugMetaItem(
136
                                'JSON-LD property: ',
137
                                [
138
                                    'default' => 'error',
139
                                    'google' => 'warning',
140
                                ]
141
                            );
142
                        }
143
                    }
144
                }
145
            }
146
        }
147
148
        // Create a root JSON-LD object
149
        $jsonLdGraph = MetaJsonLd::create('jsonLd', [
150
            'graph' => [],
151
        ]);
152
        $jsonLdGraph->type = null;
153
        // Add the JSON-LD objects to our root JSON-LD's graph
154
        $cspNonce = null;
155
        foreach ($tagData as $config) {
156
            $jsonLdGraph->graph[] = $config['jsonLd'];
157
            if (!empty($config['jsonLd']->nonce)) {
158
                $cspNonce = $config['jsonLd']->nonce;
159
            }
160
        }
161
        // Render the JSON-LD object
162
        $jsonLd = $jsonLdGraph->render([
163
            'renderRaw' => true,
164
            'renderScriptTags' => false,
165
            'array' => false,
166
        ]);
167
168
        // Register the tags
169
        $attrs = ['type' => 'application/ld+json'];
170
        if (!empty($cspNonce)) {
171
            $attrs = array_merge($attrs, [
172
                'nonce' => $cspNonce,
173
            ]);
174
        }
175
176
        return [$jsonLd, $attrs];
177
    }
178
}
179