Skip to content

Commit c5c2aef

Browse files
committed
Merge branch 'master' into publications-feature
2 parents 8a55834 + 1ed5791 commit c5c2aef

File tree

6 files changed

+162
-4
lines changed

6 files changed

+162
-4
lines changed

packages/framework/src/Foundation/Concerns/ManagesHydeKernel.php

+46-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55
namespace Hyde\Foundation\Concerns;
66

7+
use BadMethodCallException;
78
use Hyde\Foundation\FileCollection;
89
use Hyde\Foundation\HydeKernel;
910
use Hyde\Foundation\PageCollection;
1011
use Hyde\Foundation\RouteCollection;
1112
use Hyde\Pages\Concerns\HydePage;
13+
use function in_array;
14+
use InvalidArgumentException;
15+
use function is_subclass_of;
1216

1317
/**
1418
* @internal Single-use trait for the HydeKernel class.
@@ -56,11 +60,52 @@ public function getSourceRoot(): string
5660
return $this->sourceRoot;
5761
}
5862

59-
/** @return array<class-string<\Hyde\Pages\Concerns\HydePage>> */
63+
/**
64+
* @deprecated This method may be removed in favour of {@see self::getRegisteredPageClasses()}
65+
*
66+
* @return array<class-string<\Hyde\Pages\Concerns\HydePage>>
67+
*/
6068
public function getDiscoveredPageTypes(): array
6169
{
6270
return $this->pages()->map(function (HydePage $page): string {
6371
return $page::class;
6472
})->unique()->values()->toArray();
6573
}
74+
75+
/**
76+
* Developer Information.
77+
*
78+
* @experimental This feature is experimental and may change substantially before the 1.0.0 release.
79+
*
80+
* If you are a package developer, and want a custom page class to be discovered,
81+
* you'll need to register it sometime before the boot process, before discovery is run.
82+
* Typically, you would do this by calling this method in the register method of a service provider.
83+
* Hyde will then automatically discover source files for the new page class, and compile them during the build process.
84+
*
85+
* @param class-string<\Hyde\Pages\Concerns\HydePage> $pageClass
86+
*/
87+
public function registerPageClass(string $pageClass): void
88+
{
89+
if ($this->booted) {
90+
// We throw an exception here to prevent the developer from registering a page class after the Kernel has been booted.
91+
// The reason we do this is because at this point all the source files have already been discovered and parsed.
92+
// If we allowed new classes after this point, we would have to reboot everything which adds complexity.
93+
94+
throw new BadMethodCallException('Cannot register a page class after the Kernel has been booted.');
95+
}
96+
97+
if (! is_subclass_of($pageClass, HydePage::class)) {
98+
throw new InvalidArgumentException('The specified class must be a subclass of HydePage.');
99+
}
100+
101+
if (! in_array($pageClass, $this->pageClasses, true)) {
102+
$this->pageClasses[] = $pageClass;
103+
}
104+
}
105+
106+
/** @return array<class-string<\Hyde\Pages\Concerns\HydePage>> */
107+
public function getRegisteredPageClasses(): array
108+
{
109+
return $this->pageClasses;
110+
}
66111
}

packages/framework/src/Foundation/FileCollection.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
use Hyde\Support\Filesystem\SourceFile;
1919

2020
/**
21-
* The FileCollection contains all the discovered source and media files.
21+
* The FileCollection contains all the discovered source and media files,
22+
* and thus has an integral role in the Hyde Auto Discovery process.
2223
*
2324
* This class is stored as a singleton in the HydeKernel.
2425
* You would commonly access it via one of the facades:
@@ -80,7 +81,9 @@ protected function runDiscovery(): self
8081
$this->discoverFilesFor(DocumentationPage::class);
8182
}
8283

83-
// TODO: Add hook to support custom page types
84+
foreach ($this->kernel->getRegisteredPageClasses() as $pageClass) {
85+
$this->discoverFilesFor($pageClass);
86+
}
8487

8588
$this->discoverMediaAssetFiles();
8689

packages/framework/src/Foundation/HydeKernel.php

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class HydeKernel implements SerializableContract
5555
protected RouteCollection $routes;
5656

5757
protected bool $booted = false;
58+
protected array $pageClasses = [];
5859

5960
final public const VERSION = '1.0.0-dev';
6061

packages/framework/src/Foundation/PageCollection.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ protected function runDiscovery(): self
7070
$this->discoverPublicationPages();
7171
}
7272

73-
// TODO: #781 Add package developer hook to discover custom page types
73+
foreach ($this->kernel->getRegisteredPageClasses() as $pageClass) {
74+
$this->discoverPagesFor($pageClass);
75+
}
7476

7577
return $this;
7678
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hyde\Framework\Testing\Feature;
6+
7+
use function app;
8+
use BadMethodCallException;
9+
use Hyde\Foundation\Facades;
10+
use Hyde\Foundation\HydeKernel;
11+
use Hyde\Pages\Concerns\HydePage;
12+
use Hyde\Support\Filesystem\SourceFile;
13+
use Hyde\Support\Models\Route;
14+
use Hyde\Testing\TestCase;
15+
use InvalidArgumentException;
16+
use stdClass;
17+
18+
/**
19+
* @covers \Hyde\Foundation\HydeKernel
20+
* @covers \Hyde\Foundation\Concerns\ManagesHydeKernel
21+
* @covers \Hyde\Foundation\FileCollection
22+
* @covers \Hyde\Foundation\PageCollection
23+
*/
24+
class HydeKernelDynamicPageClassesTest extends TestCase
25+
{
26+
public function test_get_registered_page_classes_method()
27+
{
28+
$this->assertSame([], app(HydeKernel::class)->getRegisteredPageClasses());
29+
}
30+
31+
public function test_register_page_class_method_adds_specified_class_name_to_index()
32+
{
33+
app(HydeKernel::class)->registerPageClass(TestPageClass::class);
34+
$this->assertSame([TestPageClass::class], app(HydeKernel::class)->getRegisteredPageClasses());
35+
}
36+
37+
public function test_register_page_class_method_does_not_add_already_added_class_names()
38+
{
39+
app(HydeKernel::class)->registerPageClass(TestPageClass::class);
40+
app(HydeKernel::class)->registerPageClass(TestPageClass::class);
41+
$this->assertSame([TestPageClass::class], app(HydeKernel::class)->getRegisteredPageClasses());
42+
}
43+
44+
public function test_register_page_class_method_only_accepts_instances_of_hyde_page_class()
45+
{
46+
$this->expectException(InvalidArgumentException::class);
47+
$this->expectExceptionMessage('The specified class must be a subclass of HydePage.');
48+
app(HydeKernel::class)->registerPageClass(stdClass::class);
49+
}
50+
51+
public function test_register_page_class_method_throws_exception_when_collection_is_already_booted()
52+
{
53+
$this->expectException(BadMethodCallException::class);
54+
$this->expectExceptionMessage('Cannot register a page class after the Kernel has been booted.');
55+
56+
app(HydeKernel::class)->boot();
57+
app(HydeKernel::class)->registerPageClass(TestPageClass::class);
58+
}
59+
60+
// Test custom registered pages can be further processed and parsed
61+
62+
public function test_custom_registered_pages_are_discovered_by_the_file_collection_class()
63+
{
64+
$this->directory('foo');
65+
$this->file('foo/bar.txt');
66+
app(HydeKernel::class)->registerPageClass(TestPageClassWithSourceInformation::class);
67+
68+
$this->assertArrayHasKey('foo/bar.txt', Facades\FileCollection::all());
69+
$this->assertEquals(new SourceFile('foo/bar.txt', TestPageClassWithSourceInformation::class), Facades\FileCollection::get('foo/bar.txt'));
70+
}
71+
72+
public function test_custom_registered_pages_are_discovered_by_the_page_collection_class()
73+
{
74+
$this->directory('foo');
75+
$this->file('foo/bar.txt');
76+
app(HydeKernel::class)->registerPageClass(TestPageClassWithSourceInformation::class);
77+
$this->assertArrayHasKey('foo/bar.txt', Facades\PageCollection::all());
78+
$this->assertEquals(new TestPageClassWithSourceInformation('bar'), Facades\PageCollection::get('foo/bar.txt'));
79+
}
80+
81+
public function test_custom_registered_pages_are_discovered_by_the_route_collection_class()
82+
{
83+
$this->directory('foo');
84+
$this->file('foo/bar.txt');
85+
app(HydeKernel::class)->registerPageClass(TestPageClassWithSourceInformation::class);
86+
$this->assertArrayHasKey('foo/bar', Facades\Router::all());
87+
$this->assertEquals(new Route(new TestPageClassWithSourceInformation('bar')), Facades\Router::get('foo/bar'));
88+
}
89+
}
90+
91+
abstract class TestPageClass extends HydePage
92+
{
93+
//
94+
}
95+
96+
class TestPageClassWithSourceInformation extends HydePage
97+
{
98+
public static string $sourceDirectory = 'foo';
99+
public static string $outputDirectory = 'foo';
100+
public static string $fileExtension = '.txt';
101+
102+
public function compile(): string
103+
{
104+
return '';
105+
}
106+
}

packages/framework/tests/Feature/HydeKernelTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @covers \Hyde\Hyde
3030
*
3131
* @see \Hyde\Framework\Testing\Unit\HydeHelperFacadeMakeTitleTest
32+
* @see \Hyde\Framework\Testing\Feature\HydeKernelDynamicPageClassesTest
3233
*/
3334
class HydeKernelTest extends TestCase
3435
{

0 commit comments

Comments
 (0)