Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
35 / 35 |
|
100.00% |
8 / 8 |
CRAP | |
100.00% |
1 / 1 |
SitemapGenerator | |
100.00% |
35 / 35 |
|
100.00% |
8 / 8 |
17 | |
100.00% |
1 / 1 |
generate | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getXml | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
constructBaseElement | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
addRoute | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
getLastModDate | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getPriority | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
6 | |||
getFormattedProcessingTime | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
resolveRouteLink | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | /** @noinspection PhpComposerExtensionStubsInspection */ |
4 | |
5 | declare(strict_types=1); |
6 | |
7 | namespace Hyde\Framework\Features\XmlGenerators; |
8 | |
9 | use Hyde\Hyde; |
10 | use SimpleXMLElement; |
11 | use Hyde\Facades\Config; |
12 | use Hyde\Pages\BladePage; |
13 | use Hyde\Pages\MarkdownPage; |
14 | use Hyde\Pages\MarkdownPost; |
15 | use Hyde\Support\Models\Route; |
16 | use Hyde\Pages\DocumentationPage; |
17 | use Hyde\Foundation\Facades\Routes; |
18 | use Hyde\Framework\Concerns\TracksExecutionTime; |
19 | |
20 | use function blank; |
21 | use function filemtime; |
22 | use function in_array; |
23 | use function date; |
24 | use function time; |
25 | use function str_starts_with; |
26 | |
27 | /** |
28 | * @see https://www.sitemaps.org/protocol.html |
29 | */ |
30 | class SitemapGenerator extends BaseXmlGenerator |
31 | { |
32 | use TracksExecutionTime; |
33 | |
34 | public function generate(): static |
35 | { |
36 | Routes::all()->each(function (Route $route): void { |
37 | $this->addRoute($route); |
38 | }); |
39 | |
40 | return $this; |
41 | } |
42 | |
43 | public function getXml(): string |
44 | { |
45 | $this->xmlElement->addAttribute('processing_time_ms', $this->getFormattedProcessingTime()); |
46 | |
47 | return parent::getXml(); |
48 | } |
49 | |
50 | protected function constructBaseElement(): void |
51 | { |
52 | $this->startClock(); |
53 | |
54 | $this->xmlElement = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"></urlset>'); |
55 | $this->xmlElement->addAttribute('generator', 'HydePHP v'.Hyde::version()); |
56 | } |
57 | |
58 | protected function addRoute(Route $route): void |
59 | { |
60 | $urlItem = $this->xmlElement->addChild('url'); |
61 | |
62 | $this->addChild($urlItem, 'loc', $this->resolveRouteLink($route)); |
63 | $this->addChild($urlItem, 'lastmod', $this->getLastModDate($route->getSourcePath())); |
64 | $this->addChild($urlItem, 'changefreq', 'daily'); |
65 | |
66 | if (Config::getBool('hyde.sitemap.dynamic_priority', true)) { |
67 | $this->addChild($urlItem, 'priority', $this->getPriority( |
68 | $route->getPageClass(), $route->getPage()->getIdentifier() |
69 | )); |
70 | } |
71 | } |
72 | |
73 | protected function getLastModDate(string $file): string |
74 | { |
75 | return date('c', @filemtime($file) ?: time()); |
76 | } |
77 | |
78 | protected function getPriority(string $pageClass, string $slug): string |
79 | { |
80 | $priority = 0.5; |
81 | |
82 | if (in_array($pageClass, [BladePage::class, MarkdownPage::class])) { |
83 | $priority = 0.9; |
84 | if ($slug === 'index') { |
85 | $priority = 1; |
86 | } |
87 | if ($slug === '404') { |
88 | $priority = 0.5; |
89 | } |
90 | } |
91 | |
92 | if ($pageClass === DocumentationPage::class) { |
93 | $priority = 0.9; |
94 | } |
95 | |
96 | if ($pageClass === MarkdownPost::class) { |
97 | $priority = 0.75; |
98 | } |
99 | |
100 | return (string) $priority; |
101 | } |
102 | |
103 | /** @return numeric-string */ |
104 | protected function getFormattedProcessingTime(): string |
105 | { |
106 | return (string) $this->getExecutionTimeInMs(); |
107 | } |
108 | |
109 | protected function resolveRouteLink(Route $route): string |
110 | { |
111 | $baseUrl = Config::getNullableString('hyde.url'); |
112 | |
113 | if (blank($baseUrl) || str_starts_with($baseUrl, 'http://localhost')) { |
114 | // While the sitemap spec requires a full URL, we rather fall back |
115 | // to using relative links instead of using localhost links. |
116 | |
117 | return $route->getLink(); |
118 | } else { |
119 | return Hyde::url($route->getOutputPath()); |
120 | } |
121 | } |
122 | } |