Passed
Push — develop ( 421797...7f10a1 )
by Andrew
09:07
created

SitemapTemplate::render()   C

Complexity

Conditions 11
Paths 37

Size

Total Lines 100
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 68
c 1
b 0
f 0
nc 37
nop 1
dl 0
loc 100
ccs 0
cts 68
cp 0
crap 132
rs 6.5515

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
111
        $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle($type, $handle, $siteId);
112
        // If it doesn't exist, throw a 404
113
        if ($metaBundle === null ) {
114
            throw new NotFoundHttpException(Craft::t('seomatic', 'Page not found.'));
115
        }
116
        // Check to see if robots is `none` or `no index`
117
        $robotsEnabled = true;
118
        if (!empty($metaBundle->metaGlobalVars->robots)) {
119
            $robotsEnabled = $metaBundle->metaGlobalVars->robots !== 'none' &&
120
                $metaBundle->metaGlobalVars->robots !== 'noindex';
121
        }
122
        $sitemapUrls = $metaBundle->metaSitemapVars->sitemapUrls;
123
        if (Seomatic::$plugin->sitemaps->anyEntryTypeHasSitemapUrls($metaBundle)) {
124
            $robotsEnabled = true;
125
            $sitemapUrls = true;
126
        }
127
        // If it's disabled, just throw a 404
128
        if (!$sitemapUrls || !$robotsEnabled) {
129
            throw new NotFoundHttpException(Craft::t('seomatic', 'Page not found.'));
130
        }
131
132
        $cache = Craft::$app->getCache();
133
        $uniqueKey = $groupId.$type.$handle.$siteId;
134
        $cacheKey = self::CACHE_KEY.$uniqueKey;
135
        $queueJobCacheKey = self::QUEUE_JOB_CACHE_KEY.$uniqueKey;
136
        $result = $cache->get($cacheKey);
137
        // If the sitemap isn't cached, start a job to create it
138
        if ($result === false) {
139
            $queue = Craft::$app->getQueue();
140
            // If there's an existing queue job, release it so queue jobs don't stack
141
            $existingJobId = $cache->get($queueJobCacheKey);
142
            // Make sure the queue uses the Craft web interface
143
            if ($existingJobId && $queue instanceof QueueInterface) {
144
                $queue = Craft::$app->getQueue();
145
                $queue->release($existingJobId);
146
                $cache->delete($queueJobCacheKey);
147
            }
148
            // Push a new queue job
149
            $jobId = $queue->push(new GenerateSitemap([
150
                'groupId' => $groupId,
151
                'type' => $type,
152
                'handle' => $handle,
153
                'siteId' => $siteId,
154
                'queueJobCacheKey' => $queueJobCacheKey,
155
            ]));
156
            // Stash the queue job id in the cache for future reference
157
            $cacheDuration = 3600;
158
            $dependency = new TagDependency([
159
                'tags' => [
160
                    self::GLOBAL_SITEMAP_CACHE_TAG,
161
                    self::CACHE_KEY.$uniqueKey,
162
                ],
163
            ]);
164
            $cache->set($queueJobCacheKey, $jobId, $cacheDuration, $dependency);
165
            Craft::debug(
166
                Craft::t(
167
                    'seomatic',
168
                    'Started GenerateSitemap queue job id: {jobId} with cache key {cacheKey}',
169
                    [
170
                        'jobId' => $jobId,
171
                        'cacheKey' => $cacheKey,
172
                    ]
173
                ),
174
                __METHOD__
175
            );
176
            // Try to run the queue immediately
177
            QueueHelper::run();
178
            // Try it again now
179
            $result = $cache->get($cacheKey);
180
            if ($result !== false) {
181
                return $result;
182
            }
183
            // Return a 503 Service Unavailable an a Retry-After so bots will try back later
184
            $response = Craft::$app->getResponse();
185
            $response->setStatusCode(503);
186
            $response->headers->add('Retry-After', 60);
187
            $response->headers->add('Cache-Control', 'no-cache, no-store');
188
            // Return an empty XML document
189
            $lines[] = '<?xml version="1.0" encoding="UTF-8"?>';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$lines was never initialized. Although not strictly required by PHP, it is generally a good practice to add $lines = array(); before regardless.
Loading history...
190
            $lines[] = '<?xml-stylesheet type="text/xsl" href="sitemap-empty.xsl"?>';
191
            $lines[] = '<!-- ' . Craft::t('seomatic', 'This sitemap has not been generated yet.') . ' -->';
192
            $lines[] = '<!-- ' . Craft::t('seomatic', 'If you are seeing this in local dev or an') . ' -->';
193
            $lines[] = '<!-- ' . Craft::t('seomatic', 'environment with `devMode` on, caches only') . ' -->';
194
            $lines[] = '<!-- ' . Craft::t('seomatic', 'last for 30 seconds in local dev, so it is') . ' -->';
195
            $lines[] = '<!-- ' . Craft::t('seomatic', 'normal for the sitemap to not be cached.') . ' -->';
196
            $lines[] = '<urlset>';
197
            $lines[] = '</urlset>';
198
            $lines = implode("\r\n", $lines);
199
200
            return $lines;
201
        }
202
203
        return $result;
204
    }
205
206
    /**
207
     * Invalidate a sitemap cache
208
     *
209
     * @param string $handle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
210
     * @param int    $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
211
     */
212
    public function invalidateCache(string $handle, int $siteId)
213
    {
214
        $cache = Craft::$app->getCache();
215
        TagDependency::invalidate($cache, self::SITEMAP_CACHE_TAG.$handle.$siteId);
216
        Craft::info(
217
            'Sitemap cache cleared: '.$handle,
218
            __METHOD__
219
        );
220
    }
221
222
}
223