Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize foundation collections #1193

Merged
merged 108 commits into from
Mar 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
8c46f44
Update foundation collection class documentation
caendesilva Mar 3, 2023
78f9154
Add more class documentation
caendesilva Mar 3, 2023
d969f12
Link to #1194
caendesilva Mar 3, 2023
6690cf7
Catch and rethrow discovery exceptions in BaseFoundationCollection class
caendesilva Mar 3, 2023
caff5e2
Split out multiple assertions to separate tests
caendesilva Mar 3, 2023
7a7035a
Test that the original (previous) exception is accessible
caendesilva Mar 3, 2023
d4c46ca
Remove resolved todo
caendesilva Mar 4, 2023
44b7d5e
Add FileCollection::getFiles method to match getPages and getRoutes
caendesilva Mar 4, 2023
26535c4
Add static getFile to the facade
caendesilva Mar 4, 2023
eea28b4
Move method logic to the facade
caendesilva Mar 4, 2023
1392016
Use accessor instead of protected property
caendesilva Mar 4, 2023
b4e7b8b
Inline FileCollection:getFile method
caendesilva Mar 4, 2023
fa15ffe
Test covers file facade
caendesilva Mar 4, 2023
ee0ce71
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
cab7924
Copy public methods to facade as static stubs
caendesilva Mar 4, 2023
bfc987b
Implement method stubs as forwarders
caendesilva Mar 4, 2023
40a4151
Move method logic to the facade
caendesilva Mar 4, 2023
f5f930f
Update methods to forward to the facade
caendesilva Mar 4, 2023
0166137
Inline FileCollection methods moved to the Files facade
caendesilva Mar 4, 2023
64faf32
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
42b2457
Remove unused local test variables
caendesilva Mar 4, 2023
1e3cb3b
Clean up inlined methods
caendesilva Mar 4, 2023
c9573bb
Copy public methods to facade as static stubs
caendesilva Mar 4, 2023
690ac4c
Implement method stubs as forwarders
caendesilva Mar 4, 2023
d189ae1
Copy PHPDoc annotation
caendesilva Mar 4, 2023
e2d25f2
Move method logic to the facade
caendesilva Mar 4, 2023
83c75e2
Update methods to forward to the facade
caendesilva Mar 4, 2023
e38bc1e
Make methods static
caendesilva Mar 4, 2023
530aa42
Use accessor method
caendesilva Mar 4, 2023
8e0061b
Revert move of adder method from the facade as it's not pure
caendesilva Mar 4, 2023
4f116b1
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
a2b4d5f
Inline PageCollection methods moved to the Pages facade
caendesilva Mar 4, 2023
cf8ffe1
Merge branch 'finalize-foundation-collections' of github.com:hydephp/…
caendesilva Mar 4, 2023
f1fe330
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
48782ff
Set tested instance
caendesilva Mar 4, 2023
9f1aed1
Calling boot logic is no longer needed
caendesilva Mar 4, 2023
7e87a7b
Get instance directly as it's already fresh
caendesilva Mar 4, 2023
20ce1fb
Clean up code made messy by automated refactor
caendesilva Mar 4, 2023
7bd37ca
Test covers facade
caendesilva Mar 4, 2023
0b770b2
Copy public getter methods to facade as static stubs
caendesilva Mar 4, 2023
0bbb554
Implement method stubs as forwarders
caendesilva Mar 4, 2023
26814f8
Move method logic to the facade
caendesilva Mar 4, 2023
f0d91bc
Update methods to forward to the facade
caendesilva Mar 4, 2023
6bb0dfc
Use accessor instead of protected property
caendesilva Mar 4, 2023
2171866
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
e595fc9
Inline RouteCollection methods moved to the Routes facade
caendesilva Mar 4, 2023
99fbef3
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
e483889
Test covers facade
caendesilva Mar 4, 2023
577d3ba
Merge branch 'finalize-foundation-collections' of github.com:hydephp/…
caendesilva Mar 4, 2023
8092a39
Remove redundant arguments
caendesilva Mar 4, 2023
5708738
Remove unnecessary assertions for same object on both sides
caendesilva Mar 4, 2023
7b90c00
Remove unnecessary method calls
caendesilva Mar 4, 2023
f59d06d
Remove unused import
caendesilva Mar 4, 2023
495ee40
Extend UnitTestCase
caendesilva Mar 4, 2023
da73acd
Setup kernel and mock config at setup
caendesilva Mar 4, 2023
4e36627
Join comma-separated values into single lines
caendesilva Mar 4, 2023
01025d0
Use camelCase
caendesilva Mar 4, 2023
e86d041
Setup only needs to be done once
caendesilva Mar 4, 2023
0c9fc01
Specify test method names
caendesilva Mar 4, 2023
d653989
Remove redundant qualifier from test names
caendesilva Mar 4, 2023
f5e4767
Shorten test names to use name of the facades
caendesilva Mar 4, 2023
3c652f3
Split out multiple assertions to multiple tests
caendesilva Mar 4, 2023
d5c49f1
Implement getFacadeAccessor methods
caendesilva Mar 4, 2023
fdd0932
Replace final marker with final annotations in foundation collections…
caendesilva Mar 4, 2023
d1c2e0a
Annotate final annotation
caendesilva Mar 4, 2023
911a790
Test the facades are mockable
caendesilva Mar 4, 2023
60f306b
Revert "Test the facades are mockable"
caendesilva Mar 4, 2023
d550f34
Revert "Replace final marker with final annotations in foundation col…
caendesilva Mar 4, 2023
a4d8a33
Revert "Implement getFacadeAccessor methods"
caendesilva Mar 4, 2023
83765ab
Add baseline tests
caendesilva Mar 4, 2023
d44fe7e
Add generic collection template annotations
caendesilva Mar 4, 2023
6b85fd7
Use template-extends
caendesilva Mar 4, 2023
92956a7
Add return type generics
caendesilva Mar 4, 2023
c9f9d64
Add facade return type generics
caendesilva Mar 4, 2023
378a51c
Convert concatenation to string interpolation
caendesilva Mar 4, 2023
9ffb5d1
Fix string passed to invalid argument
caendesilva Mar 4, 2023
7e661d6
Update and test the exception message
caendesilva Mar 4, 2023
212f73c
Test and fix exception message
caendesilva Mar 4, 2023
e968a4d
Update developer documentation
caendesilva Mar 4, 2023
ce7aee7
Merge branch 'master' into finalize-foundation-collections
caendesilva Mar 4, 2023
4ad598c
Swap order of documentation words
caendesilva Mar 4, 2023
5185580
Update and test exception message
caendesilva Mar 4, 2023
86c247e
Flip '?:'
caendesilva Mar 4, 2023
55b7337
Flip '?:'
caendesilva Mar 4, 2023
9b4a9e2
Move down the getFacadeRoot methods
caendesilva Mar 4, 2023
80a5dbf
Remove developer annotation as contract forces route to lead to a page
caendesilva Mar 4, 2023
2eb7dc6
Remove unnecessary developer annotation
caendesilva Mar 4, 2023
d5099ac
Clean up developer documentation
caendesilva Mar 4, 2023
eef6e59
Inline simple helper method
caendesilva Mar 4, 2023
732553a
Break out return value from try block
caendesilva Mar 4, 2023
5dc43af
Unwrap finally block
caendesilva Mar 4, 2023
70d2be0
Make the BaseFoundationCollection::boot method final
caendesilva Mar 4, 2023
0b34f66
Make the protected BaseFoundationCollection constructor final
caendesilva Mar 4, 2023
8ed1025
Remove the BaseFoundationCollection::getInstance as it adds no value
caendesilva Mar 4, 2023
dfb025a
Extract public FileCollection::addFile method
caendesilva Mar 4, 2023
357f64c
Call runExtensionCallbacks from the base class boot method
caendesilva Mar 4, 2023
3ff68ea
Change BaseFoundationCollection::runDiscovery to return void instead …
caendesilva Mar 4, 2023
a6ca86b
Change BaseFoundationCollection::runExtensionCallbacks to return void…
caendesilva Mar 4, 2023
caf5b16
Shift and merge internal control flow to make code more understandable
caendesilva Mar 4, 2023
17d80df
Fix collect call
caendesilva Mar 4, 2023
c34f959
Annotate class-string parameter
caendesilva Mar 4, 2023
a1bb2b9
Use the temporary file helpers
caendesilva Mar 4, 2023
0a7b88c
Apply fixes from StyleCI
StyleCIBot Mar 4, 2023
af5c82f
Refactor to get files directly from the kernel
caendesilva Mar 4, 2023
8ae9144
Merge branch 'finalize-foundation-collections' of github.com:hydephp/…
caendesilva Mar 4, 2023
1eedf5b
Make FileCollection::addFile method return void
caendesilva Mar 4, 2023
8993dd9
Make PageCollection::addPage method return void
caendesilva Mar 4, 2023
5062f4b
Make RouteCollection::addRoute method return void
caendesilva Mar 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,57 @@
use Hyde\Foundation\HydeKernel;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection;
use RuntimeException;
use Throwable;

/**
* Base class for the kernel auto-discovery collections.
*
* @see \Hyde\Foundation\Kernel\FileCollection
* @see \Hyde\Foundation\Kernel\PageCollection
* @see \Hyde\Foundation\Kernel\RouteCollection
* @see \Hyde\Framework\Testing\Unit\BaseFoundationCollectionTest
* These collections are the heart of the discovery process.
*
* They are responsible for discovering the files, pages, and routes,
* for the project, and also act as containers for the discovered data.
*
* The collections are stored as singletons in the kernel, and can be
* accessed via the kernel's `getFiles()`, `getPages()`, and `getRoutes()`
* methods respectively, or through the corresponding facade helper classes.
*
* Each collection depends on the earlier one, thus they are booted in sequence.
*
* @see \Hyde\Foundation\Kernel\FileCollection Discovers the source files in the project.
* @see \Hyde\Foundation\Kernel\PageCollection Parses the source files into page objects.
* @see \Hyde\Foundation\Kernel\RouteCollection Creates route objects from the page objects.
*
* The collections are constructed and booted in the kernel through the `BootsHydeKernel` trait.
* Between the construction and booting is a time-frame where the extensions can hook into
* the discovery process and add their data through the `runExtensionCallbacks` API.
*/
abstract class BaseFoundationCollection extends Collection
{
protected HydeKernel $kernel;

abstract protected function runDiscovery(): self;
abstract protected function runDiscovery(): void;

abstract protected function runExtensionCallbacks(): self;
abstract protected function runExtensionCallbacks(): void;

public static function init(HydeKernel $kernel): static
{
return (new static())->setKernel($kernel);
}

public function boot(): static
final public function boot(): static
{
return $this->runDiscovery();
try {
$this->runDiscovery();
$this->runExtensionCallbacks();
} catch (Throwable $exception) {
throw new RuntimeException('An error occurred during the discovery process.', previous: $exception);
}

return $this;
}

protected function __construct(array|Arrayable|null $items = [])
final protected function __construct(array|Arrayable|null $items = [])
{
parent::__construct($items);
}
Expand All @@ -46,10 +69,4 @@ protected function setKernel(HydeKernel $kernel): static

return $this;
}

/** @return $this */
public function getInstance(): static
{
return $this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@
*/
trait HandlesFoundationCollections
{
/** @return \Hyde\Foundation\Kernel\FileCollection<string, \Hyde\Support\Filesystem\ProjectFile> */
public function files(): FileCollection
{
$this->needsToBeBooted();

return $this->files;
}

/** @return \Hyde\Foundation\Kernel\PageCollection<string, \Hyde\Pages\Concerns\HydePage> */
public function pages(): PageCollection
{
$this->needsToBeBooted();

return $this->pages;
}

/** @return \Hyde\Foundation\Kernel\RouteCollection<string, \Hyde\Support\Models\Route> */
public function routes(): RouteCollection
{
$this->needsToBeBooted();
Expand Down
40 changes: 40 additions & 0 deletions packages/framework/src/Foundation/Facades/Files.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,53 @@

use Hyde\Foundation\HydeKernel;
use Hyde\Foundation\Kernel\FileCollection;
use Hyde\Framework\Exceptions\FileNotFoundException;
use Hyde\Support\Filesystem\MediaFile;
use Hyde\Support\Filesystem\ProjectFile;
use Hyde\Support\Filesystem\SourceFile;
use Illuminate\Support\Facades\Facade;

/**
* @mixin \Hyde\Foundation\Kernel\FileCollection
*/
class Files extends Facade
{
public static function getFile(string $filePath): ProjectFile
{
return static::getFacadeRoot()->get($filePath) ?? throw new FileNotFoundException(message: "File [$filePath] not found in file collection");
}

/**
* @param class-string<\Hyde\Pages\Concerns\HydePage>|null $pageClass
* @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile>
*/
public static function getSourceFiles(?string $pageClass = null): FileCollection
{
return $pageClass ? static::getSourceFilesFor($pageClass) : static::getAllSourceFiles();
}

/**
* @param class-string<\Hyde\Pages\Concerns\HydePage> $pageClass
* @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile>
*/
public static function getSourceFilesFor(string $pageClass): FileCollection
{
return static::getAllSourceFiles()->where(fn (SourceFile $file): bool => $file->model === $pageClass);
}

/** @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile> */
public static function getAllSourceFiles(): FileCollection
{
return static::getFacadeRoot()->where(fn (ProjectFile $file): bool => $file instanceof SourceFile);
}

/** @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\MediaFile> */
public static function getMediaFiles(): FileCollection
{
return static::getFacadeRoot()->where(fn (ProjectFile $file): bool => $file instanceof MediaFile);
}

/** @return \Hyde\Foundation\Kernel\FileCollection<string, \Hyde\Support\Filesystem\ProjectFile> */
public static function getFacadeRoot(): FileCollection
{
return HydeKernel::getInstance()->files();
Expand Down
15 changes: 15 additions & 0 deletions packages/framework/src/Foundation/Facades/Pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@

use Hyde\Foundation\HydeKernel;
use Hyde\Foundation\Kernel\PageCollection;
use Hyde\Framework\Exceptions\FileNotFoundException;
use Hyde\Pages\Concerns\HydePage;
use Illuminate\Support\Facades\Facade;

/**
* @mixin \Hyde\Foundation\Kernel\PageCollection
*/
class Pages extends Facade
{
public static function getPage(string $sourcePath): HydePage
{
return static::getFacadeRoot()->get($sourcePath) ?? throw new FileNotFoundException(message: "Page [$sourcePath] not found in page collection");
}

public static function getPages(?string $pageClass = null): PageCollection
{
return $pageClass ? static::getFacadeRoot()->filter(function (HydePage $page) use ($pageClass): bool {
return $page instanceof $pageClass;
}) : static::getFacadeRoot();
}

/** @return \Hyde\Foundation\Kernel\PageCollection<string, \Hyde\Pages\Concerns\HydePage> */
public static function getFacadeRoot(): PageCollection
{
return HydeKernel::getInstance()->pages();
Expand Down
15 changes: 15 additions & 0 deletions packages/framework/src/Foundation/Facades/Routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@

use Hyde\Foundation\HydeKernel;
use Hyde\Foundation\Kernel\RouteCollection;
use Hyde\Framework\Exceptions\RouteNotFoundException;
use Hyde\Support\Models\Route;
use Illuminate\Support\Facades\Facade;

/**
* @mixin \Hyde\Foundation\Kernel\RouteCollection
*/
class Routes extends Facade
{
public static function getRoute(string $routeKey): Route
{
return static::getFacadeRoot()->get($routeKey) ?? throw new RouteNotFoundException(message: "Route [$routeKey] not found in route collection");
}

public static function getRoutes(?string $pageClass = null): RouteCollection
{
return $pageClass ? static::getFacadeRoot()->filter(function (Route $route) use ($pageClass): bool {
return $route->getPage() instanceof $pageClass;
}) : static::getFacadeRoot();
}

/** @return \Hyde\Foundation\Kernel\RouteCollection<string, \Hyde\Support\Models\Route> */
public static function getFacadeRoot(): RouteCollection
{
return HydeKernel::getInstance()->routes();
Expand Down
49 changes: 14 additions & 35 deletions packages/framework/src/Foundation/Kernel/FileCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* The FileCollection contains all the discovered source and media files,
* and thus has an integral role in the Hyde Auto Discovery process.
*
* @template T of \Hyde\Support\Filesystem\ProjectFile
* @template-extends \Hyde\Foundation\Concerns\BaseFoundationCollection<string, T>
*
* @property array<string, ProjectFile> $items The files in the collection.
*
* This class is stored as a singleton in the HydeKernel.
Expand All @@ -26,36 +29,18 @@
final class FileCollection extends BaseFoundationCollection
{
/**
* @param class-string<\Hyde\Pages\Concerns\HydePage>|null $pageClass
* @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile>
*/
public function getSourceFiles(?string $pageClass = null): self
{
return ! $pageClass ? $this->getAllSourceFiles() : $this->getSourceFilesFor($pageClass);
}

/**
* @param class-string<\Hyde\Pages\Concerns\HydePage> $pageClass
* @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile>
* This method adds the specified file to the file collection.
* It can be used by package developers to add a file that can be discovered.
*
* In order for your file to be further processed you must call this method during the boot process,
* either using a Kernel bootingCallback, or by using a HydeExtension's discovery handler callback.
*/
public function getSourceFilesFor(string $pageClass): self
public function addFile(ProjectFile $file): void
{
return $this->getAllSourceFiles()->where(fn (SourceFile $file): bool => $file->model === $pageClass);
$this->put($file->getPath(), $file);
}

/** @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\SourceFile> */
public function getAllSourceFiles(): self
{
return $this->where(fn (ProjectFile $file): bool => $file instanceof SourceFile);
}

/** @return \Hyde\Foundation\Kernel\FileCollection<\Hyde\Support\Filesystem\MediaFile> */
public function getMediaFiles(): self
{
return $this->where(fn (ProjectFile $file): bool => $file instanceof MediaFile);
}

protected function runDiscovery(): self
protected function runDiscovery(): void
{
/** @var class-string<\Hyde\Pages\Concerns\HydePage> $pageClass */
foreach ($this->kernel->getRegisteredPageClasses() as $pageClass) {
Expand All @@ -64,21 +49,15 @@ protected function runDiscovery(): self
}
}

$this->runExtensionCallbacks();

$this->discoverMediaAssetFiles();

return $this;
}

protected function runExtensionCallbacks(): self
protected function runExtensionCallbacks(): void
{
/** @var class-string<\Hyde\Foundation\Concerns\HydeExtension> $extension */
foreach ($this->kernel->getExtensions() as $extension) {
$extension->discoverFiles($this);
}

return $this;
}

/** @param class-string<HydePage> $pageClass */
Expand All @@ -87,15 +66,15 @@ protected function discoverFilesFor(string $pageClass): void
// Scan the source directory, and directories therein, for files that match the model's file extension.
foreach (glob($this->kernel->path($pageClass::sourcePath('{*,**/*}')), GLOB_BRACE) as $filepath) {
if (! str_starts_with(basename((string) $filepath), '_')) {
$this->put($this->kernel->pathToRelative($filepath), SourceFile::make($filepath, $pageClass));
$this->addFile(SourceFile::make($filepath, $pageClass));
}
}
}

protected function discoverMediaAssetFiles(): void
{
foreach (DiscoveryService::getMediaAssetFiles() as $filepath) {
$this->put($this->kernel->pathToRelative($filepath), MediaFile::make($filepath));
$this->addFile(MediaFile::make($filepath));
}
}
}
Loading