Code Coverage  | 
      ||||||||||
Lines  | 
       Functions and Methods  | 
       Classes and Traits  | 
      ||||||||
| Total |         | 
       100.00%  | 
       41 / 41  | 
               | 
       100.00%  | 
       8 / 8  | 
       CRAP |         | 
       100.00%  | 
       1 / 1  | 
      
| SitemapService |         | 
       100.00%  | 
       41 / 41  | 
               | 
       100.00%  | 
       8 / 8  | 
       21 |         | 
       100.00%  | 
       1 / 1  | 
      
| __construct |         | 
       100.00%  | 
       3 / 3  | 
               | 
       100.00%  | 
       1 / 1  | 
       1 | |||
| generate |         | 
       100.00%  | 
       10 / 10  | 
               | 
       100.00%  | 
       1 / 1  | 
       5 | |||
| getXML |         | 
       100.00%  | 
       2 / 2  | 
               | 
       100.00%  | 
       1 / 1  | 
       1 | |||
| addPageModelUrls |         | 
       100.00%  | 
       8 / 8  | 
               | 
       100.00%  | 
       1 / 1  | 
       3 | |||
| getLastModDate |         | 
       100.00%  | 
       2 / 2  | 
               | 
       100.00%  | 
       1 / 1  | 
       1 | |||
| getPriority |         | 
       100.00%  | 
       12 / 12  | 
               | 
       100.00%  | 
       1 / 1  | 
       6 | |||
| generateSitemap |         | 
       100.00%  | 
       1 / 1  | 
               | 
       100.00%  | 
       1 / 1  | 
       1 | |||
| canGenerateSitemap |         | 
       100.00%  | 
       3 / 3  | 
               | 
       100.00%  | 
       1 / 1  | 
       3 | |||
| 1 | <?php | 
| 2 | |
| 3 | namespace Hyde\Framework\Services; | 
| 4 | |
| 5 | use Hyde\Framework\Helpers\Features; | 
| 6 | use Hyde\Framework\Hyde; | 
| 7 | use Hyde\Framework\Models\BladePage; | 
| 8 | use Hyde\Framework\Models\DocumentationPage; | 
| 9 | use Hyde\Framework\Models\MarkdownPage; | 
| 10 | use Hyde\Framework\Models\MarkdownPost; | 
| 11 | use SimpleXMLElement; | 
| 12 | |
| 13 | /** | 
| 14 | * @see \Tests\Feature\Services\SitemapServiceTest | 
| 15 | * @see https://www.sitemaps.org/protocol.html | 
| 16 | */ | 
| 17 | class SitemapService | 
| 18 | { | 
| 19 | public SimpleXMLElement $xmlElement; | 
| 20 | protected float $time_start; | 
| 21 | |
| 22 | public function __construct() | 
| 23 | { | 
| 24 | $this->time_start = microtime(true); | 
| 25 | |
| 26 | $this->xmlElement = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"></urlset>'); | 
| 27 | $this->xmlElement->addAttribute('generator', 'HydePHP '.Hyde::version()); | 
| 28 | } | 
| 29 | |
| 30 | public function generate(): self | 
| 31 | { | 
| 32 | if (Features::hasBladePages()) { | 
| 33 | $this->addPageModelUrls( | 
| 34 | BladePage::class | 
| 35 | ); | 
| 36 | } | 
| 37 | |
| 38 | if (Features::hasMarkdownPages()) { | 
| 39 | $this->addPageModelUrls( | 
| 40 | MarkdownPage::class | 
| 41 | ); | 
| 42 | } | 
| 43 | |
| 44 | if (Features::hasBlogPosts()) { | 
| 45 | $this->addPageModelUrls( | 
| 46 | MarkdownPost::class, | 
| 47 | 'posts/' | 
| 48 | ); | 
| 49 | } | 
| 50 | |
| 51 | if (Features::hasDocumentationPages()) { | 
| 52 | $this->addPageModelUrls( | 
| 53 | DocumentationPage::class, | 
| 54 | Hyde::docsDirectory().'/' | 
| 55 | ); | 
| 56 | } | 
| 57 | |
| 58 | return $this; | 
| 59 | } | 
| 60 | |
| 61 | public function getXML(): string | 
| 62 | { | 
| 63 | $this->xmlElement->addAttribute('processing_time_ms', (string) round((microtime(true) - $this->time_start) * 1000, 2)); | 
| 64 | |
| 65 | return $this->xmlElement->asXML(); | 
| 66 | } | 
| 67 | |
| 68 | public function addPageModelUrls(string $pageClass, string $routePrefix = ''): void | 
| 69 | { | 
| 70 | $collection = CollectionService::getSourceFileListForModel($pageClass); | 
| 71 | |
| 72 | foreach ($collection as $slug) { | 
| 73 | $urlItem = $this->xmlElement->addChild('url'); | 
| 74 | $urlItem->addChild('loc', htmlentities(Hyde::uriPath(Hyde::pageLink($routePrefix.$slug.'.html')))); | 
| 75 | $urlItem->addChild('lastmod', htmlentities($this->getLastModDate($pageClass, $slug))); | 
| 76 | $urlItem->addChild('changefreq', 'daily'); | 
| 77 | if (config('hyde.sitemap.dynamic_priority', true)) { | 
| 78 | $urlItem->addChild('priority', $this->getPriority($pageClass, $slug)); | 
| 79 | } | 
| 80 | } | 
| 81 | } | 
| 82 | |
| 83 | protected function getLastModDate(string $pageClass, string $slug): string | 
| 84 | { | 
| 85 | return date('c', filemtime( | 
| 86 | /** @var \Hyde\Framework\Contracts\AbstractPage $pageClass */ | 
| 87 | Hyde::path($pageClass::$sourceDirectory.DIRECTORY_SEPARATOR.$slug.$pageClass::$fileExtension) | 
| 88 | )); | 
| 89 | } | 
| 90 | |
| 91 | protected function getPriority(string $pageClass, string $slug): string | 
| 92 | { | 
| 93 | $priority = 0.5; | 
| 94 | |
| 95 | if (in_array($pageClass, [BladePage::class, MarkdownPage::class])) { | 
| 96 | $priority = 0.9; | 
| 97 | if ($slug === 'index') { | 
| 98 | $priority = 1; | 
| 99 | } | 
| 100 | if ($slug === '404') { | 
| 101 | $priority = 0.5; | 
| 102 | } | 
| 103 | } | 
| 104 | |
| 105 | if ($pageClass === DocumentationPage::class) { | 
| 106 | $priority = 0.9; | 
| 107 | } | 
| 108 | |
| 109 | if ($pageClass === MarkdownPost::class) { | 
| 110 | $priority = 0.75; | 
| 111 | } | 
| 112 | |
| 113 | return (string) $priority; | 
| 114 | } | 
| 115 | |
| 116 | public static function generateSitemap(): string | 
| 117 | { | 
| 118 | return (new static)->generate()->getXML(); | 
| 119 | } | 
| 120 | |
| 121 | public static function canGenerateSitemap(): bool | 
| 122 | { | 
| 123 | return (Hyde::uriPath() !== false) | 
| 124 | && config('hyde.generate_sitemap', true) | 
| 125 | && extension_loaded('simplexml'); | 
| 126 | } | 
| 127 | } |