Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
PageMetadataBag
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
7 / 7
16
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 generate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addDynamicPageMetadata
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 addMetadataForMarkdownPost
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 addPostMetadataIfExists
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 resolveImageLink
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 calculatePathTraversal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Framework\Features\Metadata;
6
7use Hyde\Facades\Meta;
8use Hyde\Pages\Concerns\HydePage;
9use Hyde\Pages\MarkdownPost;
10use Hyde\Foundation\Kernel\Hyperlinks;
11
12use function substr_count;
13use function str_repeat;
14
15class PageMetadataBag extends MetadataBag
16{
17    protected HydePage $page;
18
19    public function __construct(HydePage $page)
20    {
21        $this->page = $page;
22
23        $this->generate();
24    }
25
26    protected function generate(): void
27    {
28        $this->addDynamicPageMetadata($this->page);
29    }
30
31    protected function addDynamicPageMetadata(HydePage $page): void
32    {
33        if ($page->getCanonicalUrl()) {
34            $this->add(Meta::link('canonical', $page->getCanonicalUrl()));
35        }
36
37        if ($page->has('description')) {
38            $this->add(Meta::name('description', $page->data('description')));
39            $this->add(Meta::property('description', $page->data('description')));
40        }
41
42        if ($page->has('title')) {
43            $this->add(Meta::name('twitter:title', $page->title()));
44            $this->add(Meta::property('title', $page->title()));
45        }
46
47        if ($page instanceof MarkdownPost) {
48            $this->addMetadataForMarkdownPost($page);
49        }
50    }
51
52    protected function addMetadataForMarkdownPost(MarkdownPost $page): void
53    {
54        $this->addPostMetadataIfExists($page, 'author');
55        $this->addPostMetadataIfExists($page, 'category', 'keywords');
56
57        if ($page->getCanonicalUrl()) {
58            $this->add(Meta::name('url', $page->getCanonicalUrl()));
59            $this->add(Meta::property('url', $page->getCanonicalUrl()));
60        }
61
62        if ($page->has('date')) {
63            $this->add(Meta::property('og:article:published_time', $page->date->datetime));
64        }
65
66        if ($page->has('image')) {
67            $this->add(Meta::property('image', $this->resolveImageLink((string) $page->data('image'))));
68        }
69
70        $this->add(Meta::property('type', 'article'));
71    }
72
73    protected function addPostMetadataIfExists(MarkdownPost $page, string $property, ?string $name = null): void
74    {
75        if ($page->has($property)) {
76            $this->add(Meta::name($name ?? $property, (string) $page->data($property)));
77        }
78    }
79
80    protected function resolveImageLink(string $image): string
81    {
82        // Since this is run before the page is rendered, we don't have the currentPage property.
83        // So we need to run some of the same calculations here to resolve the image path link.
84        return Hyperlinks::isRemote($image) ? $image : $this->calculatePathTraversal().$image;
85    }
86
87    private function calculatePathTraversal(): string
88    {
89        return str_repeat('../', substr_count(MarkdownPost::outputDirectory().'/'.$this->page->identifier, '/'));
90    }
91}