Total Complexity | 40 |
Total Lines | 313 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like SitemapIndexTemplate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SitemapIndexTemplate, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
35 | class SitemapIndexTemplate extends FrontendTemplate implements SitemapInterface |
||
36 | { |
||
37 | // Constants |
||
38 | // ========================================================================= |
||
39 | |||
40 | /** |
||
41 | * @event RegisterSitemapsEvent The event that is triggered when registering |
||
42 | * additional sitemaps for the sitemap index. |
||
43 | * |
||
44 | * --- |
||
45 | * ```php |
||
46 | * use nystudio107\seomatic\events\RegisterSitemapsEvent; |
||
47 | * use nystudio107\seomatic\models\SitemapIndexTemplate; |
||
48 | * use yii\base\Event; |
||
49 | * Event::on(SitemapIndexTemplate::class, SitemapIndexTemplate::EVENT_REGISTER_SITEMAPS, function(RegisterSitemapsEvent $e) { |
||
50 | * $e->sitemaps[] = [ |
||
51 | * 'loc' => $url, |
||
52 | * 'lastmod' => $lastMod, |
||
53 | * ]; |
||
54 | * }); |
||
55 | * ``` |
||
56 | */ |
||
57 | public const EVENT_REGISTER_SITEMAPS = 'registerSitemaps'; |
||
58 | |||
59 | public const TEMPLATE_TYPE = 'SitemapIndexTemplate'; |
||
60 | |||
61 | public const CACHE_KEY = 'seomatic_sitemap_index'; |
||
62 | |||
63 | public const SITEMAP_INDEX_CACHE_TAG = 'seomatic_sitemap_index'; |
||
64 | |||
65 | // Static Methods |
||
66 | // ========================================================================= |
||
67 | |||
68 | /** |
||
69 | * @param array $config |
||
70 | * |
||
71 | * @return null|SitemapIndexTemplate |
||
72 | */ |
||
73 | public static function create(array $config = []) |
||
74 | { |
||
75 | $defaults = [ |
||
76 | 'path' => 'sitemaps-<groupId:\d+>-sitemap.xml', |
||
77 | 'template' => '', |
||
78 | 'controller' => 'sitemap', |
||
79 | 'action' => 'sitemap-index', |
||
80 | ]; |
||
81 | $config = array_merge($config, $defaults); |
||
82 | |||
83 | return new SitemapIndexTemplate($config); |
||
84 | } |
||
85 | |||
86 | // Public Properties |
||
87 | // ========================================================================= |
||
88 | |||
89 | // Public Methods |
||
90 | // ========================================================================= |
||
91 | |||
92 | /** |
||
93 | * @inheritdoc |
||
94 | */ |
||
95 | public function rules(): array |
||
96 | { |
||
97 | $rules = parent::rules(); |
||
98 | $rules = array_merge($rules, [ |
||
99 | ]); |
||
100 | |||
101 | return $rules; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @inheritdoc |
||
106 | */ |
||
107 | public function fields(): array |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Get the filename of the sitemap index. |
||
114 | * |
||
115 | * @param int $groupId |
||
116 | * @return string |
||
117 | */ |
||
118 | public function getFilename(int $groupId): string |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * @inheritdoc |
||
125 | * |
||
126 | * @throws NotFoundHttpException if the sitemap.xml doesn't exist |
||
127 | */ |
||
128 | public function render(array $params = []): string |
||
129 | { |
||
130 | $cache = Craft::$app->getCache(); |
||
131 | $groupId = $params['groupId']; |
||
132 | $siteId = $params['siteId']; |
||
133 | if (Seomatic::$settings->siteGroupsSeparate) { |
||
134 | /** @var SiteGroup|null $siteGroup */ |
||
135 | $siteGroup = Craft::$app->getSites()->getGroupById($groupId); |
||
136 | if ($siteGroup === null) { |
||
137 | throw new NotFoundHttpException(Craft::t('seomatic', 'Sitemap.xml not found for groupId {groupId}', [ |
||
138 | 'groupId' => $groupId, |
||
139 | ])); |
||
140 | } |
||
141 | $groupSiteIds = $siteGroup->getSiteIds(); |
||
142 | } else { |
||
143 | $groupSiteIds = Craft::$app->getSites()->allSiteIds; |
||
144 | } |
||
145 | |||
146 | $dependency = new TagDependency([ |
||
147 | 'tags' => [ |
||
148 | self::GLOBAL_SITEMAP_CACHE_TAG, |
||
149 | self::SITEMAP_INDEX_CACHE_TAG, |
||
150 | ], |
||
151 | ]); |
||
152 | |||
153 | return $cache->getOrSet(self::CACHE_KEY . $groupId . '.' . $siteId, function() use ($groupSiteIds, $siteId) { |
||
154 | Craft::info( |
||
155 | 'Sitemap index cache miss', |
||
156 | __METHOD__ |
||
157 | ); |
||
158 | $lines = []; |
||
159 | // Sitemap index XML header and opening tag |
||
160 | $lines[] = '<?xml version="1.0" encoding="UTF-8"?>'; |
||
161 | $lines[] = '<?xml-stylesheet type="text/xsl" href="sitemap.xsl"?>'; |
||
162 | $lines[] = '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'; |
||
163 | // One sitemap entry for each MeteBundle |
||
164 | $metaBundles = Seomatic::$plugin->metaBundles->getContentMetaBundlesForSiteId($siteId); |
||
165 | Seomatic::$plugin->metaBundles->pruneVestigialMetaBundles($metaBundles); |
||
166 | /** @var MetaBundle $metaBundle */ |
||
167 | foreach ($metaBundles as $metaBundle) { |
||
168 | $sitemapUrls = $metaBundle->metaSitemapVars->sitemapUrls; |
||
169 | // Check to see if robots is `none` or `no index` |
||
170 | $robotsEnabled = true; |
||
171 | if (!empty($metaBundle->metaGlobalVars->robots)) { |
||
172 | $robotsEnabled = $metaBundle->metaGlobalVars->robots !== 'none' && |
||
173 | $metaBundle->metaGlobalVars->robots !== 'noindex'; |
||
174 | } |
||
175 | if (Seomatic::$plugin->sitemaps->anyEntryTypeHasSitemapUrls($metaBundle)) { |
||
176 | $robotsEnabled = true; |
||
177 | $sitemapUrls = true; |
||
178 | } |
||
179 | // Only add in a sitemap entry if it meets our criteria |
||
180 | if (in_array($metaBundle->sourceSiteId, $groupSiteIds, false) |
||
181 | && $sitemapUrls |
||
182 | && $robotsEnabled) { |
||
183 | // Get all of the elements for this meta bundle type |
||
184 | $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($metaBundle->sourceBundleType); |
||
185 | $totalElements = 0; |
||
186 | $pageCount = 0; |
||
187 | |||
188 | if ($seoElement !== null) { |
||
189 | // Ensure `null` so that the resulting element query is correct |
||
190 | if (empty($metaBundle->metaSitemapVars->sitemapLimit)) { |
||
191 | $metaBundle->metaSitemapVars->sitemapLimit = null; |
||
192 | } |
||
193 | |||
194 | $totalElements = $seoElement::sitemapElementsQuery($metaBundle)->count(); |
||
195 | |||
196 | if ($metaBundle->metaSitemapVars->sitemapLimit && ($totalElements > $metaBundle->metaSitemapVars->sitemapLimit)) { |
||
197 | $totalElements = $metaBundle->metaSitemapVars->sitemapLimit; |
||
198 | } |
||
199 | |||
200 | $pageSize = $metaBundle->metaSitemapVars->sitemapPageSize; |
||
201 | $pageCount = (!empty($pageSize) && $pageSize > 0) ? ceil($totalElements / $pageSize) : 1; |
||
202 | } |
||
203 | |||
204 | // Only add a sitemap to the sitemap index if there's at least 1 element in the resulting sitemap |
||
205 | if ($totalElements > 0 && $pageCount > 0) { |
||
206 | for ($page = 1; $page <= $pageCount; $page++) { |
||
207 | $sitemapUrl = Seomatic::$plugin->sitemaps->sitemapUrlForBundle( |
||
208 | $metaBundle->sourceBundleType, |
||
209 | $metaBundle->sourceHandle, |
||
210 | $metaBundle->sourceSiteId, |
||
211 | $pageCount > 1 ? $page : 0 // No paging, if only one page |
||
212 | ); |
||
213 | |||
214 | $lines[] = '<sitemap>'; |
||
215 | $lines[] = '<loc>'; |
||
216 | $lines[] = Html::encode($sitemapUrl); |
||
217 | $lines[] = '</loc>'; |
||
218 | |||
219 | if ($metaBundle->sourceDateUpdated !== null) { |
||
220 | $lines[] = '<lastmod>'; |
||
221 | $lines[] = $metaBundle->sourceDateUpdated->format(DateTime::W3C); |
||
222 | $lines[] = '</lastmod>'; |
||
223 | } |
||
224 | |||
225 | $lines[] = '</sitemap>'; |
||
226 | } |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | // Custom sitemap entries |
||
231 | $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteId, false); |
||
232 | if ($metaBundle !== null) { |
||
233 | $this->addAdditionalSitemapUrls($metaBundle, $siteId, $lines); |
||
234 | $this->addAdditionalSitemaps($metaBundle, $siteId, $lines); |
||
235 | } |
||
236 | // Sitemap index closing tag |
||
237 | $lines[] = '</sitemapindex>'; |
||
238 | |||
239 | return implode('', $lines); |
||
240 | }, Seomatic::$cacheDuration, $dependency); |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Invalidate the sitemap index cache |
||
245 | */ |
||
246 | public function invalidateCache() |
||
253 | ); |
||
254 | } |
||
255 | |||
256 | // Protected Methods |
||
257 | // ========================================================================= |
||
258 | |||
259 | /** |
||
260 | * Add an additional sitemap to the sitemap index, coming from the global |
||
261 | * meta bundle metaSiteVars->additionalSitemaps |
||
262 | * |
||
263 | * @param MetaBundle $metaBundle |
||
264 | * @param int $groupSiteId |
||
265 | * @param array $lines |
||
266 | * |
||
267 | * @throws Exception |
||
268 | */ |
||
269 | protected function addAdditionalSitemaps(MetaBundle $metaBundle, int $groupSiteId, array &$lines) |
||
297 | } |
||
298 | } |
||
299 | } |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Add an additional "custom" sitemap to the sitemap index, with URLs coming from |
||
304 | * the global meta bundle metaSiteVars->additionalSitemapUrls |
||
305 | * |
||
306 | * @param MetaBundle $metaBundle |
||
307 | * @param int $groupSiteId |
||
308 | * @param array $lines |
||
309 | * |
||
310 | * @throws Exception |
||
311 | */ |
||
312 | protected function addAdditionalSitemapUrls(MetaBundle $metaBundle, int $groupSiteId, array &$lines) |
||
348 | } |
||
349 | } |
||
351 |