Passed
Push — develop ( 35fad9...992d49 )
by Andrew
13:42
created

SitemapTemplate::render()   D

Complexity

Conditions 19
Paths 99

Size

Total Lines 115
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 380

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 19
eloc 79
nc 99
nop 1
dl 0
loc 115
ccs 0
cts 79
cp 0
crap 380
rs 4.5166
c 2
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 nystudio107\seomatic\Seomatic;
15
use nystudio107\seomatic\base\FrontendTemplate;
16
use nystudio107\seomatic\base\SitemapInterface;
17
use nystudio107\seomatic\helpers\Queue as QueueHelper;
18
use nystudio107\seomatic\jobs\GenerateSitemap;
19
20
use Craft;
21
use craft\queue\QueueInterface;
22
23
use yii\caching\TagDependency;
24
use yii\web\NotFoundHttpException;
25
26
/**
27
 * @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...
28
 * @package   Seomatic
29
 * @since     3.0.0
30
 */
31
class SitemapTemplate extends FrontendTemplate implements SitemapInterface
32
{
33
    // Constants
34
    // =========================================================================
35
36
    const TEMPLATE_TYPE = 'SitemapTemplate';
37
38
    const CACHE_KEY = 'seomatic_sitemap_';
39
40
    const QUEUE_JOB_CACHE_KEY = 'seomatic_sitemap_queue_job_';
41
42
    const SITEMAP_CACHE_TAG = 'seomatic_sitemap_';
43
44
    const FILE_TYPES = [
45
        'excel',
46
        'pdf',
47
        'illustrator',
48
        'powerpoint',
49
        'text',
50
        'word',
51
        'xml',
52
    ];
53
54
    // Static Methods
55
    // =========================================================================
56
57
    /**
58
     * @param array $config
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
59
     *
60
     * @return null|SitemapTemplate
61
     */
62
    public static function create(array $config = [])
63
    {
64
        $defaults = [
65
            'path' => 'sitemaps-<groupId:\d+>-<type:[\w\.*]+>-<handle:[\w\.*]+>-<siteId:\d+>-<file:[-\w\.*]+>',
66
            'template' => '',
67
            'controller' => 'sitemap',
68
            'action' => 'sitemap',
69
        ];
70
        $config = array_merge($config, $defaults);
71
72
        return new SitemapTemplate($config);
73
    }
74
75
    // Public Properties
76
    // =========================================================================
77
78
    // Public Methods
79
    // =========================================================================
80
81
    /**
82
     * @inheritdoc
83
     */
84
    public function rules(): array
85
    {
86
        $rules = parent::rules();
87
        $rules = array_merge($rules, [
88
        ]);
89
90
        return $rules;
91
    }
92
93
    /**
94
     * @inheritdoc
95
     */
96
    public function fields(): array
97
    {
98
        return parent::fields();
99
    }
100
101
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $params should have a doc-comment as per coding-style.
Loading history...
102
     * @inheritdoc
103
     */
104
    public function render(array $params = []): string
105
    {
106
        $groupId = $params['groupId'];
107
        $type = $params['type'];
108
        $handle = $params['handle'];
109
        $siteId = $params['siteId'];
110
        $throwException = $params['throwException'] ?? true;
111
        $request = Craft::$app->getRequest();
112
        $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle($type, $handle, $siteId);
113
        // If it doesn't exist, throw a 404
114
        if ($metaBundle === null ) {
115
            if ($request->isCpRequest || $request->isConsoleRequest) {
116
                return '';
117
            }
118
            if ($throwException) {
119
                throw new NotFoundHttpException(Craft::t('seomatic', 'Page not found.'));
120
            }
121
            return '';
122
        }
123
        // Check to see if robots is `none` or `no index`
124
        $robotsEnabled = true;
125
        if (!empty($metaBundle->metaGlobalVars->robots)) {
126
            $robotsEnabled = $metaBundle->metaGlobalVars->robots !== 'none' &&
127
                $metaBundle->metaGlobalVars->robots !== 'noindex';
128
        }
129
        $sitemapUrls = $metaBundle->metaSitemapVars->sitemapUrls;
130
        if (Seomatic::$plugin->sitemaps->anyEntryTypeHasSitemapUrls($metaBundle)) {
131
            $robotsEnabled = true;
132
            $sitemapUrls = true;
133
        }
134
        // If it's disabled, just throw a 404
135
        if (!$sitemapUrls || !$robotsEnabled) {
136
            if ($request->isCpRequest || $request->isConsoleRequest) {
137
                return '';
138
            }
139
            if ($throwException) {
140
                throw new NotFoundHttpException(Craft::t('seomatic', 'Page not found.'));
141
            }
142
        }
143
144
        $cache = Craft::$app->getCache();
145
        $uniqueKey = $groupId.$type.$handle.$siteId;
146
        $cacheKey = self::CACHE_KEY.$uniqueKey;
147
        $queueJobCacheKey = self::QUEUE_JOB_CACHE_KEY.$uniqueKey;
148
        $result = $cache->get($cacheKey);
149
        // If the sitemap isn't cached, start a job to create it
150
        if ($result === false) {
151
            $queue = Craft::$app->getQueue();
152
            // If there's an existing queue job, release it so queue jobs don't stack
153
            $existingJobId = $cache->get($queueJobCacheKey);
154
            // Make sure the queue uses the Craft web interface
155
            if ($existingJobId && $queue instanceof QueueInterface) {
156
                $queue = Craft::$app->getQueue();
157
                $queue->release($existingJobId);
158
                $cache->delete($queueJobCacheKey);
159
            }
160
            // Push a new queue job
161
            $jobId = $queue->push(new GenerateSitemap([
162
                'groupId' => $groupId,
163
                'type' => $type,
164
                'handle' => $handle,
165
                'siteId' => $siteId,
166
                'queueJobCacheKey' => $queueJobCacheKey,
167
            ]));
168
            // Stash the queue job id in the cache for future reference
169
            $cacheDuration = 3600;
170
            $dependency = new TagDependency([
171
                'tags' => [
172
                    self::GLOBAL_SITEMAP_CACHE_TAG,
173
                    self::CACHE_KEY.$uniqueKey,
174
                ],
175
            ]);
176
            $cache->set($queueJobCacheKey, $jobId, $cacheDuration, $dependency);
177
            Craft::debug(
178
                Craft::t(
179
                    'seomatic',
180
                    'Started GenerateSitemap queue job id: {jobId} with cache key {cacheKey}',
181
                    [
182
                        'jobId' => $jobId,
183
                        'cacheKey' => $cacheKey,
184
                    ]
185
                ),
186
                __METHOD__
187
            );
188
            // Try to run the queue immediately
189
            QueueHelper::run();
190
            // Try it again now
191
            $result = $cache->get($cacheKey);
192
            if ($result !== false) {
193
                return $result;
194
            }
195
            // Return a 503 Service Unavailable an a Retry-After so bots will try back later
196
            $lines = [];
197
            $response = Craft::$app->getResponse();
198
            if (!$request->isConsoleRequest && $throwException) {
199
                $response->setStatusCode(503);
200
                $response->headers->add('Retry-After', 60);
201
                $response->headers->add('Cache-Control', 'no-cache, no-store');
202
                // Return an empty XML document
203
                $lines[] = '<?xml version="1.0" encoding="UTF-8"?>';
204
                $lines[] = '<?xml-stylesheet type="text/xsl" href="sitemap-empty.xsl"?>';
205
                $lines[] = '<!-- ' . Craft::t('seomatic', 'This sitemap has not been generated yet.') . ' -->';
206
                $lines[] = '<!-- ' . Craft::t('seomatic', 'If you are seeing this in local dev or an') . ' -->';
207
                $lines[] = '<!-- ' . Craft::t('seomatic', 'environment with `devMode` on, caches only') . ' -->';
208
                $lines[] = '<!-- ' . Craft::t('seomatic', 'last for 30 seconds in local dev, so it is') . ' -->';
209
                $lines[] = '<!-- ' . Craft::t('seomatic', 'normal for the sitemap to not be cached.') . ' -->';
210
                $lines[] = '<urlset>';
211
                $lines[] = '</urlset>';
212
            }
213
            $lines = implode("\r\n", $lines);
214
215
            return $lines;
216
        }
217
218
        return $result;
219
    }
220
221
    /**
222
     * Invalidate a sitemap cache
223
     *
224
     * @param string $handle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
225
     * @param int    $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
226
     */
227
    public function invalidateCache(string $handle, int $siteId)
228
    {
229
        $cache = Craft::$app->getCache();
230
        TagDependency::invalidate($cache, self::SITEMAP_CACHE_TAG.$handle.$siteId);
231
        Craft::info(
232
            'Sitemap cache cleared: '.$handle,
233
            __METHOD__
234
        );
235
    }
236
237
}
238