Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
PublicationsExtension
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
13 / 13
18
100.00% covered (success)
100.00%
1 / 1
 getTypes
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getPageClasses
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 discoverFiles
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 discoverPages
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 discoverPublicationPages
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 generatePublicationListingPageForType
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 generatePublicationPaginatedListingPagesForType
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 generatePublicationTagPages
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 parsePublicationTypes
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getSchemaFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPublicationFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPublicationFilesForType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shouldGeneratePublicationTagPages
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\Publications;
6
7use Hyde\Foundation\Concerns\HydeExtension;
8use Hyde\Foundation\Facades\Files;
9use Hyde\Foundation\Kernel\FileCollection;
10use Hyde\Foundation\Kernel\PageCollection;
11use Hyde\Hyde;
12use Hyde\Pages\InMemoryPage;
13use Hyde\Publications\Actions\GeneratesPublicationTagPages;
14use Hyde\Publications\Models\PublicationType;
15use Hyde\Publications\Pages\PublicationListPage;
16use Hyde\Publications\Pages\PublicationPage;
17use Hyde\Support\Filesystem\SourceFile;
18use Illuminate\Support\Collection;
19use Illuminate\Support\Str;
20
21use function glob;
22use function range;
23use function str_ends_with;
24
25/**
26 * @see \Hyde\Publications\Testing\Feature\PublicationsExtensionTest
27 */
28class PublicationsExtension extends HydeExtension
29{
30    /** @var \Illuminate\Support\Collection<string, \Hyde\Publications\Models\PublicationType> */
31    protected Collection $types;
32
33    /** @return \Illuminate\Support\Collection<string, \Hyde\Publications\Models\PublicationType> */
34    public function getTypes(): Collection
35    {
36        if (! isset($this->types)) {
37            $this->types = $this->parsePublicationTypes();
38        }
39
40        return $this->types;
41    }
42
43    /** @return array<class-string<\Hyde\Pages\Concerns\HydePage>> */
44    public static function getPageClasses(): array
45    {
46        return [
47            // Since our page classes are not auto-discoverable by Hyde due to the dynamic source directories,
48            // we run our own discovery logic in the callbacks below.
49        ];
50    }
51
52    public function discoverFiles(FileCollection $collection): void
53    {
54        $this->types = $this->parsePublicationTypes();
55
56        $this->types->each(function (PublicationType $type) use ($collection): void {
57            Collection::make($this->getPublicationFilesForType($type))->map(function (string $filepath) use ($collection): void {
58                $collection->put(Hyde::pathToRelative($filepath), SourceFile::make($filepath, PublicationPage::class));
59            });
60        });
61    }
62
63    public function discoverPages(PageCollection $collection): void
64    {
65        $this->discoverPublicationPages($collection);
66
67        if (self::shouldGeneratePublicationTagPages()) {
68            $this->generatePublicationTagPages($collection);
69        }
70    }
71
72    protected function discoverPublicationPages(PageCollection $instance): void
73    {
74        Files::getFiles(PublicationPage::class)->each(function (SourceFile $file) use ($instance): void {
75            $instance->addPage(PublicationPage::parse(Str::before($file->getPath(), PublicationPage::fileExtension())));
76        });
77
78        $this->types->each(function (PublicationType $type) use ($instance): void {
79            $this->generatePublicationListingPageForType($type, $instance);
80        });
81    }
82
83    protected function generatePublicationListingPageForType(PublicationType $type, PageCollection $instance): void
84    {
85        $page = new PublicationListPage($type);
86        $instance->put($page->getSourcePath(), $page);
87
88        if ($type->usesPagination()) {
89            $this->generatePublicationPaginatedListingPagesForType($type, $instance);
90        }
91    }
92
93    protected function generatePublicationPaginatedListingPagesForType(PublicationType $type, PageCollection $instance): void
94    {
95        $paginator = $type->getPaginator();
96
97        foreach (range(1, $paginator->totalPages()) as $page) {
98            $paginator->setCurrentPage($page);
99            $listTemplate = $type->listTemplate;
100            if (str_ends_with($listTemplate, '.blade.php')) {
101                $listTemplate = "{$type->getDirectory()}/$listTemplate";
102            }
103            $listingPage = new InMemoryPage("{$type->getDirectory()}/page-$page", [
104                'publicationType' => $type, 'paginatorPage' => $page,
105                'title' => $type->name.' - Page '.$page,
106            ], view: $listTemplate);
107            $instance->put($listingPage->getSourcePath(), $listingPage);
108        }
109    }
110
111    protected function generatePublicationTagPages(PageCollection $collection): void
112    {
113        (new GeneratesPublicationTagPages($collection))->__invoke();
114    }
115
116    /** @return Collection<string, \Hyde\Publications\Pages\PublicationPage> */
117    protected function parsePublicationTypes(): Collection
118    {
119        return Collection::make($this->getSchemaFiles())->mapWithKeys(function (string $schemaFile): array {
120            $type = PublicationType::fromFile(Hyde::pathToRelative($schemaFile));
121
122            return [$type->getDirectory() => $type];
123        });
124    }
125
126    protected function getSchemaFiles(): array
127    {
128        return glob(Hyde::path(Hyde::getSourceRoot()).'/*/schema.json');
129    }
130
131    protected function getPublicationFiles(string $directory): array
132    {
133        return glob(Hyde::path("$directory/*.md"));
134    }
135
136    protected function getPublicationFilesForType(PublicationType $type): array
137    {
138        return $this->getPublicationFiles($type->getDirectory());
139    }
140
141    protected static function shouldGeneratePublicationTagPages(): bool
142    {
143        return count(Publications::getPublicationTags()) > 0;
144    }
145}