diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e436cda298e..3a7b036b7cc 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -7,6 +7,8 @@ This update contains **breaking changes** to the internal API regarding page mod
### Added
- Added `compile()` method to `Facades\Markdown`, replacing the `parse()` method of the same class
- Adds a new action, PageModelConstructor, to dynamically construct page model data
+- Adds new actions to handle complex dynamic constructors
+- Adds new front matter schema traits
### Changed
- Breaking: Rename AbstractMarkdownPage constructor parameter `slug` to `identifier`
@@ -14,19 +16,20 @@ This update contains **breaking changes** to the internal API regarding page mod
- Breaking: Change `AbstractMarkdownPage` constructor argument positions, putting `identifier` first
- Breaking: Splits Markdown data from MarkdownDocument into new Markdown model class
- Breaking: The default `config/hyde.php` file now uses `Models\Author` instead of `Helpers\Author`
+- Major: Restructure internal page data to use new front matter schema traits
- Begin changing references to slugs to identifiers, see motivation below
- Makes some helpers in SourceFileParser public static allowing them to be used outside the class
### Deprecated
- Deprecated `Facades\Markdown::parse()`, use `Facades\Markdown::render()` instead
- Deprecated `Facades\Markdown.php`, will be merged into `Models\Markdown.php`
-- Deprecate `$title` property in AbstractMarkdownPage, (access through front matter instead)
### Removed
- Removed `Facades\Markdown.php`, merged into `Models\Markdown.php`
- Removed `body()` method from `MarkdownDocumentContract` interface and all its implementations. Use `markdown()->body()` (or cast to string) instead
- Removed `body` property from Markdown pages. Use `markdown()->body()` (or cast to string) instead
- Removed deprecated `Helpers\Author` (fully merged into `Models\Author`, simply swap namespace to upgrade)
+- Several internal single-use helper traits have been merged into their respective classes
### Fixed
- for any bug fixes.
diff --git a/packages/framework/src/Actions/Constructors/ConfiguresFeaturedImageForPost.php b/packages/framework/src/Actions/Constructors/ConfiguresFeaturedImageForPost.php
new file mode 100644
index 00000000000..582a52ef68c
--- /dev/null
+++ b/packages/framework/src/Actions/Constructors/ConfiguresFeaturedImageForPost.php
@@ -0,0 +1,44 @@
+constructImage();
+ }
+
+ protected function __construct(protected MarkdownPost $page)
+ {
+ }
+
+ private function constructImage(): Image|null
+ {
+ if ($this->page->matter('image') !== null) {
+ if (is_string($this->page->matter('image'))) {
+ return $this->constructBaseImage($this->page->matter('image'));
+ }
+ if (is_array($this->page->matter('image'))) {
+ return new Image($this->page->matter('image'));
+ }
+ }
+
+ return null;
+ }
+
+ private function constructBaseImage(string $image): Image
+ {
+ return str_starts_with($image, 'http')
+ ? new Image(['uri' => $image])
+ : new Image(['path' => $image]);
+ }
+}
diff --git a/packages/framework/src/Actions/Constructors/FindsAuthorForPost.php b/packages/framework/src/Actions/Constructors/FindsAuthorForPost.php
new file mode 100644
index 00000000000..e6c420dc1c2
--- /dev/null
+++ b/packages/framework/src/Actions/Constructors/FindsAuthorForPost.php
@@ -0,0 +1,45 @@
+findAuthorForPost();
+ }
+
+ protected function __construct(protected MarkdownPost $page)
+ {
+ }
+
+ protected function findAuthorForPost(): Author|null
+ {
+ if ($this->page->matter('author') !== null) {
+ if (is_string($this->page->matter('author'))) {
+ // If the author is a string, we assume it's a username,
+ // so we'll try to find the author in the config
+ return Author::get($this->page->matter('author'));
+ }
+ if (is_array($this->page->matter('author'))) {
+ // If the author is an array, we'll assume it's a user
+ // with one-off custom data, so we create a new author.
+ // In the future we may want to merge config data with custom data
+ return new Author($this->getUsername(), $this->page->matter('author'));
+ }
+ }
+
+ return null;
+ }
+
+ protected function getUsername(): string
+ {
+ return $this->page->matter('author')['username'] ?? $this->page->matter('author')['name'] ?? 'Guest';
+ }
+}
diff --git a/packages/framework/src/Actions/Constructors/FindsTitleForPage.php b/packages/framework/src/Actions/Constructors/FindsTitleForPage.php
new file mode 100644
index 00000000000..dd4db75644d
--- /dev/null
+++ b/packages/framework/src/Actions/Constructors/FindsTitleForPage.php
@@ -0,0 +1,51 @@
+findTitleForPage();
+ }
+
+ protected function __construct(protected AbstractPage $page)
+ {
+ }
+
+ protected function findTitleForPage(): string
+ {
+ return $this->page instanceof AbstractMarkdownPage
+ ? $this->findTitleForMarkdownPage()
+ : Hyde::makeTitle($this->page->identifier);
+ }
+
+ protected function findTitleForMarkdownPage(): string
+ {
+ return $this->page->matter('title')
+ ?? $this->findTitleFromMarkdownHeadings()
+ ?? Hyde::makeTitle($this->page->identifier);
+ }
+
+ protected function findTitleFromMarkdownHeadings(): ?string
+ {
+ if ($this->page instanceof AbstractMarkdownPage) {
+ foreach ($this->page->markdown()->toArray() as $line) {
+ if (str_starts_with($line, '# ')) {
+ return trim(substr($line, 2), ' ');
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/packages/framework/src/Actions/PageModelConstructor.php b/packages/framework/src/Actions/PageModelConstructor.php
index fc2cbe9e6bd..8612ca75b09 100644
--- a/packages/framework/src/Actions/PageModelConstructor.php
+++ b/packages/framework/src/Actions/PageModelConstructor.php
@@ -4,7 +4,6 @@
use Hyde\Framework\Contracts\AbstractMarkdownPage;
use Hyde\Framework\Contracts\AbstractPage;
-use Hyde\Framework\Hyde;
use Hyde\Framework\Models\Pages\BladePage;
use Hyde\Framework\Models\Pages\DocumentationPage;
use Illuminate\Support\Str;
@@ -34,10 +33,7 @@ protected function __construct(AbstractPage $page)
protected function constructDynamicData(): void
{
- if (optional($this->page)->title === null) {
- $this->page->title = static::findTitleForPage();
- }
-
+ // @deprecated v0.58.x-beta (will be added to docpage schema)
if ($this->page instanceof DocumentationPage) {
$this->page->category = static::getDocumentationPageCategory();
}
@@ -58,29 +54,4 @@ protected function getDocumentationPageCategory(): ?string
? Str::before($this->page->identifier, '/')
: $this->page->matter('category');
}
-
- protected function findTitleForPage(): string
- {
- return $this->page instanceof AbstractMarkdownPage
- ? $this->findTitleForMarkdownPage()
- : Hyde::makeTitle($this->page->identifier);
- }
-
- protected function findTitleForMarkdownPage(): string
- {
- return $this->page->matter('title')
- ?? static::findTitleFromMarkdownHeadings()
- ?? Hyde::makeTitle($this->page->identifier);
- }
-
- protected function findTitleFromMarkdownHeadings(): ?string
- {
- foreach ($this->page->markdown()->toArray() as $line) {
- if (str_starts_with($line, '# ')) {
- return trim(substr($line, 2), ' ');
- }
- }
-
- return null;
- }
}
diff --git a/packages/framework/src/Concerns/FrontMatter/Schemas/BlogPostSchema.php b/packages/framework/src/Concerns/FrontMatter/Schemas/BlogPostSchema.php
new file mode 100644
index 00000000000..3d50ebf7132
--- /dev/null
+++ b/packages/framework/src/Concerns/FrontMatter/Schemas/BlogPostSchema.php
@@ -0,0 +1,50 @@
+category = $this->matter('category');
+ $this->description = $this->matter('description', substr($this->markdown, 0, 125).'...');
+ $this->date = $this->matter('date') !== null ? new DateString($this->matter('date')) : null;
+ $this->author = FindsAuthorForPost::run($this);
+ $this->image = ConfiguresFeaturedImageForPost::run($this);
+ }
+}
diff --git a/packages/framework/src/Concerns/FrontMatter/Schemas/PageSchema.php b/packages/framework/src/Concerns/FrontMatter/Schemas/PageSchema.php
new file mode 100644
index 00000000000..c8fd88dfa84
--- /dev/null
+++ b/packages/framework/src/Concerns/FrontMatter/Schemas/PageSchema.php
@@ -0,0 +1,16 @@
+title = FindsTitleForPage::run($this);
+ }
+}
diff --git a/packages/framework/src/Concerns/HasArticleMetadata.php b/packages/framework/src/Concerns/HasArticleMetadata.php
deleted file mode 100644
index 79da2f0cb8b..00000000000
--- a/packages/framework/src/Concerns/HasArticleMetadata.php
+++ /dev/null
@@ -1,108 +0,0 @@
-parseFrontMatterMetadata();
-
- $this->makeOpenGraphPropertiesForArticle();
- }
-
- public function getMetadata(): array
- {
- return $this->metadata;
- }
-
- public function getMetaProperties(): array
- {
- return $this->properties;
- }
-
- /**
- * Generate metadata from the front matter that can be used in standard tags.
- * This helper is page type agnostic and works with any kind of model having front matter.
- */
- protected function parseFrontMatterMetadata(): void
- {
- if ($this->matter('description') !== null) {
- $this->metadata['description'] = $this->matter('description');
- }
-
- if ($this->matter('author') !== null) {
- $this->metadata['author'] = $this->getAuthorName($this->matter('author'));
- }
-
- if ($this->matter('category') !== null) {
- $this->metadata['keywords'] = $this->matter('category');
- }
- }
-
- /**
- * Generate opengraph metadata from front matter for an og:article such as a blog post.
- */
- protected function makeOpenGraphPropertiesForArticle(): void
- {
- $this->properties['og:type'] = 'article';
- if (Hyde::hasSiteUrl()) {
- $this->properties['og:url'] = $this->getRoute()->getQualifiedUrl();
- }
-
- if ($this->matter('title') !== null) {
- $this->properties['og:title'] = $this->matter('title');
- }
-
- if ($this->matter('date') !== null) {
- $this->properties['og:article:published_time'] = date('c', strtotime($this->matter('date')));
- }
-
- if ($this->matter('image') !== null) {
- $this->setImageMetadata();
- }
- }
-
- /**
- * Parse the author name string from front matter with support for both flat and array notation.
- *
- * @param string|array $author
- * @return string
- */
- protected function getAuthorName(string|array $author): string
- {
- if (is_string($author)) {
- return $author;
- }
-
- return $author['name'] ?? $author['username'] ?? 'Guest';
- }
-
- protected function setImageMetadata(): void
- {
- if (is_string($this->matter('image'))) {
- $this->properties['og:image'] = $this->matter('image');
- } else {
- if (isset($this->matter('image')['path'])) {
- $this->properties['og:image'] = $this->matter('image')['path'];
- }
- if (isset($this->matter('image')['uri'])) {
- $this->properties['og:image'] = $this->matter('image')['uri'];
- }
- }
- }
-}
diff --git a/packages/framework/src/Concerns/HasAuthor.php b/packages/framework/src/Concerns/HasAuthor.php
deleted file mode 100644
index 739b8f9f57c..00000000000
--- a/packages/framework/src/Concerns/HasAuthor.php
+++ /dev/null
@@ -1,45 +0,0 @@
-matter('author') !== null) {
- if (is_string($this->matter('author'))) {
- // If the author is a string, we assume it's a username,
- // so we'll try to find the author in the config
- $this->author = $this->findAuthor($this->matter('author'));
- }
- if (is_array($this->matter('author'))) {
- // If the author is an array, we'll assume it's a user
- // with one-off custom data, so we create a new author.
- // In the future we may want to merge config data with custom data
- $this->author = $this->createAuthor($this->matter('author'));
- }
- }
- }
-
- protected function findAuthor(string $author): Author
- {
- return Author::get($author);
- }
-
- protected function createAuthor(array $data): Author
- {
- $username = $data['username'] ?? $data['name'] ?? 'Guest';
-
- return new Author($username, $data);
- }
-}
diff --git a/packages/framework/src/Concerns/HasDateString.php b/packages/framework/src/Concerns/HasDateString.php
deleted file mode 100644
index 4062b295496..00000000000
--- a/packages/framework/src/Concerns/HasDateString.php
+++ /dev/null
@@ -1,22 +0,0 @@
-matter('date') !== null) {
- $this->date = new DateString($this->matter('date'));
- }
- }
-}
diff --git a/packages/framework/src/Concerns/HasDynamicTitle.php b/packages/framework/src/Concerns/HasDynamicTitle.php
deleted file mode 100644
index 0914d9870ab..00000000000
--- a/packages/framework/src/Concerns/HasDynamicTitle.php
+++ /dev/null
@@ -1,3 +0,0 @@
-matter('image') !== null) {
- if (is_string($this->matter('image'))) {
- $this->image = $this->constructBaseImage($this->matter('image'));
- }
- if (is_array($this->matter('image'))) {
- $this->image = $this->constructFullImage($this->matter('image'));
- }
- }
- }
-
- public function constructBaseImage(string $image): Image
- {
- if (str_starts_with($image, 'http')) {
- return new Image([
- 'uri' => $image,
- ]);
- }
-
- return new Image([
- 'path' => $image,
- ]);
- }
-
- public function constructFullImage(array $image): Image
- {
- return new Image($image);
- }
-}
diff --git a/packages/framework/src/Contracts/AbstractPage.php b/packages/framework/src/Contracts/AbstractPage.php
index dcd01397ed5..247394be320 100644
--- a/packages/framework/src/Contracts/AbstractPage.php
+++ b/packages/framework/src/Contracts/AbstractPage.php
@@ -3,6 +3,7 @@
namespace Hyde\Framework\Contracts;
use Hyde\Framework\Actions\SourceFileParser;
+use Hyde\Framework\Concerns\FrontMatter\Schemas\PageSchema;
use Hyde\Framework\Helpers\Features;
use Hyde\Framework\Helpers\Meta;
use Hyde\Framework\Hyde;
@@ -23,10 +24,12 @@
*
* @see \Hyde\Framework\Contracts\PageContract
* @see \Hyde\Framework\Contracts\AbstractMarkdownPage
- * @test \Hyde\Framework\Testing\Feature\AbstractPageTest
+ * @see \Hyde\Framework\Testing\Feature\AbstractPageTest
*/
abstract class AbstractPage implements PageContract, CompilableContract
{
+ use PageSchema;
+
public static string $sourceDirectory;
public static string $outputDirectory;
public static string $fileExtension;
@@ -97,6 +100,7 @@ public function __construct(string $identifier = '', FrontMatter|array $matter =
{
$this->identifier = $identifier;
$this->matter = $matter instanceof FrontMatter ? $matter : new FrontMatter($matter);
+ $this->constructPageSchema();
}
/** @interitDoc */
diff --git a/packages/framework/src/Models/Author.php b/packages/framework/src/Models/Author.php
index 20e2558030e..1d2fcb1eda8 100644
--- a/packages/framework/src/Models/Author.php
+++ b/packages/framework/src/Models/Author.php
@@ -7,7 +7,7 @@
/**
* The Post Author Object Model.
*/
-class Author
+class Author implements \Stringable
{
/**
* The username of the author.
@@ -54,6 +54,11 @@ public function __construct(string $username, ?array $data = [])
}
}
+ public function __toString(): string
+ {
+ return $this->getName();
+ }
+
/**
* Get the author's preferred name.
*
diff --git a/packages/framework/src/Models/DateString.php b/packages/framework/src/Models/DateString.php
index 5e9d6e43233..ed564841879 100644
--- a/packages/framework/src/Models/DateString.php
+++ b/packages/framework/src/Models/DateString.php
@@ -9,7 +9,7 @@
*
* @see \Hyde\Framework\Testing\Unit\DateStringTest
*/
-class DateString
+class DateString implements \Stringable
{
/** The original date string. */
public string $string;
@@ -35,4 +35,9 @@ public function __construct(string $string)
$this->sentence = $this->dateTimeObject->format('l M jS, Y, \a\t g:ia');
$this->short = $this->dateTimeObject->format('M jS, Y');
}
+
+ public function __toString(): string
+ {
+ return $this->short;
+ }
}
diff --git a/packages/framework/src/Models/FrontMatter.php b/packages/framework/src/Models/FrontMatter.php
index 28bc4d96f35..df94c9a10e6 100644
--- a/packages/framework/src/Models/FrontMatter.php
+++ b/packages/framework/src/Models/FrontMatter.php
@@ -13,16 +13,16 @@
*/
class FrontMatter implements Arrayable, \Stringable
{
- public array $matter;
+ public array $data;
public function __construct(array $matter = [])
{
- $this->matter = $matter;
+ $this->data = $matter;
}
public function __toString(): string
{
- return (new ConvertsArrayToFrontMatter())->execute($this->matter);
+ return (new ConvertsArrayToFrontMatter())->execute($this->data);
}
public function __get(string $key): mixed
@@ -33,22 +33,22 @@ public function __get(string $key): mixed
public function get(string $key = null, mixed $default = null): mixed
{
if ($key) {
- return Arr::get($this->matter, $key, $default);
+ return Arr::get($this->data, $key, $default);
}
- return $this->matter;
+ return $this->data;
}
public function set(string $key, mixed $value): static
{
- $this->matter[$key] = $value;
+ $this->data[$key] = $value;
return $this;
}
public function toArray(): array
{
- return $this->matter;
+ return $this->data;
}
public static function fromArray(array $matter): static
diff --git a/packages/framework/src/Models/Pages/MarkdownPost.php b/packages/framework/src/Models/Pages/MarkdownPost.php
index ae8740002d1..7f5253903d0 100644
--- a/packages/framework/src/Models/Pages/MarkdownPost.php
+++ b/packages/framework/src/Models/Pages/MarkdownPost.php
@@ -2,24 +2,19 @@
namespace Hyde\Framework\Models\Pages;
-use Hyde\Framework\Concerns\HasArticleMetadata;
-use Hyde\Framework\Concerns\HasAuthor;
-use Hyde\Framework\Concerns\HasDateString;
-use Hyde\Framework\Concerns\HasFeaturedImage;
+use Hyde\Framework\Concerns\FrontMatter\Schemas\BlogPostSchema;
use Hyde\Framework\Contracts\AbstractMarkdownPage;
use Hyde\Framework\Hyde;
use Hyde\Framework\Models\FrontMatter;
use Hyde\Framework\Models\Markdown;
use Illuminate\Support\Collection;
+/**
+ * @see \Hyde\Framework\Testing\Feature\MarkdownPostTest
+ */
class MarkdownPost extends AbstractMarkdownPage
{
- use HasAuthor;
- use HasArticleMetadata;
- use HasDateString;
- use HasFeaturedImage;
-
- public ?string $category;
+ use BlogPostSchema;
public static string $sourceDirectory = '_posts';
public static string $outputDirectory = 'posts';
@@ -29,26 +24,119 @@ public function __construct(string $identifier = '', ?FrontMatter $matter = null
{
parent::__construct($identifier, $matter, $markdown);
- $this->constructAuthor();
+ $this->constructBlogPostSchema();
$this->constructMetadata();
- $this->constructDateString();
- $this->constructFeaturedImage();
-
- $this->category = $this->matter('category');
}
+ /** @deprecated v0.58.x-beta (may be moved to BlogPostSchema) */
public function getCanonicalLink(): string
{
return Hyde::url($this->getCurrentPagePath().'.html');
}
+ /** @deprecated v0.58.x-beta (pull description instead) */
public function getPostDescription(): string
{
- return $this->matter('description') ?? substr($this->markdown, 0, 125).'...';
+ return $this->description;
}
public static function getLatestPosts(): Collection
{
return static::all()->sortByDesc('matter.date');
}
+
+ // HasArticleMetadata (Generates article metadata for a MarkdownPost)
+
+ public array $metadata = [];
+ public array $properties = [];
+
+ protected function constructMetadata(): void
+ {
+ $this->parseFrontMatterMetadata();
+
+ $this->makeOpenGraphPropertiesForArticle();
+ }
+
+ public function getMetadata(): array
+ {
+ return $this->metadata;
+ }
+
+ public function getMetaProperties(): array
+ {
+ return $this->properties;
+ }
+
+ /**
+ * Generate metadata from the front matter that can be used in standard tags.
+ * This helper is page type agnostic and works with any kind of model having front matter.
+ */
+ protected function parseFrontMatterMetadata(): void
+ {
+ if ($this->matter('description') !== null) {
+ $this->metadata['description'] = $this->matter('description');
+ }
+
+ if ($this->matter('author') !== null) {
+ $this->metadata['author'] = $this->getAuthorName($this->matter('author'));
+ }
+
+ if ($this->matter('category') !== null) {
+ $this->metadata['keywords'] = $this->matter('category');
+ }
+ }
+
+ /**
+ * Generate opengraph metadata from front matter for an og:article such as a blog post.
+ */
+ protected function makeOpenGraphPropertiesForArticle(): void
+ {
+ $this->properties['og:type'] = 'article';
+ if (Hyde::hasSiteUrl()) {
+ $this->properties['og:url'] = $this->getRoute()->getQualifiedUrl();
+ }
+
+ if ($this->matter('title') !== null) {
+ $this->properties['og:title'] = $this->matter('title');
+ }
+
+ if ($this->matter('date') !== null) {
+ $this->properties['og:article:published_time'] = date('c', strtotime($this->matter('date')));
+ }
+
+ if ($this->matter('image') !== null) {
+ $this->setImageMetadata();
+ }
+ }
+
+ /**
+ * Parse the author name string from front matter with support for both flat and array notation.
+ *
+ * @param string|array $author
+ * @return string
+ *
+ * @deprecated v0.58.x-beta (Use author model instead)
+ */
+ protected function getAuthorName(string|array $author): string
+ {
+ if (is_string($author)) {
+ return $author;
+ }
+
+ return $author['name'] ?? $author['username'] ?? 'Guest';
+ }
+
+ protected function setImageMetadata(): void
+ {
+ if (is_string($this->matter('image'))) {
+ $this->properties['og:image'] = $this->matter('image');
+ } else {
+ if (isset($this->matter('image')['path'])) {
+ $this->properties['og:image'] = $this->matter('image')['path'];
+ }
+ if (isset($this->matter('image')['uri'])) {
+ $this->properties['og:image'] = $this->matter('image')['uri'];
+ }
+ }
+ }
}
diff --git a/packages/framework/tests/Feature/AuthorHelperTest.php b/packages/framework/tests/Feature/AuthorHelperTest.php
index e01967adb20..79d5c5d69a0 100644
--- a/packages/framework/tests/Feature/AuthorHelperTest.php
+++ b/packages/framework/tests/Feature/AuthorHelperTest.php
@@ -85,4 +85,27 @@ public function test_get_method_returns_new_author_if_username_not_found_in_conf
$this->assertInstanceOf(Author::class, $author);
$this->assertEquals('foo', $author->username);
}
+
+ public function test_get_name_helper_returns_name_if_set()
+ {
+ $author = new Author('username');
+ $author->name = 'John Doe';
+
+ $this->assertEquals('John Doe', $author->getName());
+ }
+
+ public function test_get_name_helper_returns_username_if_name_is_not_set()
+ {
+ $author = new Author('username');
+
+ $this->assertEquals('username', $author->getName());
+ }
+
+ public function test_to_string_helper_returns_the_name()
+ {
+ $author = new Author('username');
+ $author->name = 'John Doe';
+
+ $this->assertEquals('John Doe', (string) $author);
+ }
}
diff --git a/packages/framework/tests/Feature/MarkdownPostTest.php b/packages/framework/tests/Feature/MarkdownPostTest.php
new file mode 100644
index 00000000000..c0f8ce4bb8a
--- /dev/null
+++ b/packages/framework/tests/Feature/MarkdownPostTest.php
@@ -0,0 +1,77 @@
+ 'John Doe',
+ ]));
+
+ $this->assertInstanceOf(Author::class, $post->author);
+ $this->assertEquals('John Doe', $post->author->username);
+ $this->assertNull($post->author->name);
+ $this->assertNull($post->author->website);
+ }
+
+ public function test_constructor_can_create_a_new_author_instance_from_user_array()
+ {
+ $post = new MarkdownPost(matter: FrontMatter::fromArray([
+ 'author' => [
+ 'username' => 'john_doe',
+ 'name' => 'John Doe',
+ 'website' => 'https://example.com',
+ ],
+ ]));
+
+ $this->assertInstanceOf(Author::class, $post->author);
+ $this->assertEquals('john_doe', $post->author->username);
+ $this->assertEquals('John Doe', $post->author->name);
+ $this->assertEquals('https://example.com', $post->author->website);
+ }
+
+ public function test_constructor_can_create_a_new_image_instance_from_a_string()
+ {
+ $post = new MarkdownPost(matter: FrontMatter::fromArray([
+ 'image' => 'https://example.com/image.jpg',
+ ]));
+
+ $this->assertInstanceOf(Image::class, $post->image);
+ $this->assertEquals('https://example.com/image.jpg', $post->image->uri);
+ }
+
+ public function test_constructor_can_create_a_new_image_instance_from_an_array()
+ {
+ $post = new MarkdownPost(matter: FrontMatter::fromArray([
+ 'image' => [
+ 'uri' => 'https://example.com/image.jpg',
+ ],
+ ]));
+
+ $this->assertInstanceOf(Image::class, $post->image);
+ $this->assertEquals('https://example.com/image.jpg', $post->image->uri);
+ }
+
+ public function test_constructor_can_create_a_new_date_string_instance_from_matter()
+ {
+ $post = new MarkdownPost(matter: FrontMatter::fromArray([
+ 'date' => '2022-01-01',
+ ]));
+
+ $this->assertInstanceOf(DateString::class, $post->date);
+ $this->assertEquals('Jan 1st, 2022', $post->date->short);
+ }
+}
diff --git a/packages/framework/tests/Feature/PageModelConstructorTest.php b/packages/framework/tests/Feature/PageModelConstructorTest.php
index 94966ed3c71..b3f0528b3f3 100644
--- a/packages/framework/tests/Feature/PageModelConstructorTest.php
+++ b/packages/framework/tests/Feature/PageModelConstructorTest.php
@@ -9,6 +9,7 @@
/**
* @covers \Hyde\Framework\Actions\PageModelConstructor
+ * @covers \Hyde\Framework\Actions\Constructors\FindsTitleForPage
*/
class PageModelConstructorTest extends TestCase
{
diff --git a/packages/framework/tests/Feature/Concerns/HasArticleMetadataTest.php b/packages/framework/tests/Unit/ArticleMetadataTest.php
similarity index 95%
rename from packages/framework/tests/Feature/Concerns/HasArticleMetadataTest.php
rename to packages/framework/tests/Unit/ArticleMetadataTest.php
index 1f4ead599d4..dd297ab6e4e 100644
--- a/packages/framework/tests/Feature/Concerns/HasArticleMetadataTest.php
+++ b/packages/framework/tests/Unit/ArticleMetadataTest.php
@@ -1,17 +1,15 @@
name = 'John Doe';
-
- $this->assertEquals('John Doe', $author->getName());
- }
-
- public function test_get_name_helper_returns_username_if_name_is_not_set()
- {
- $author = new Author('username');
-
- $this->assertEquals('username', $author->getName());
- }
-}
diff --git a/packages/framework/tests/Unit/ConfiguresFeaturedImageForPostTest.php b/packages/framework/tests/Unit/ConfiguresFeaturedImageForPostTest.php
new file mode 100644
index 00000000000..56551c71289
--- /dev/null
+++ b/packages/framework/tests/Unit/ConfiguresFeaturedImageForPostTest.php
@@ -0,0 +1,63 @@
+assertNull(ConfiguresFeaturedImageForPost::run($page));
+ }
+
+ // test returns null when image is set in the page matter but is not a string or array
+ public function test_action_returns_null_when_image_is_set_in_the_page_matter_but_is_not_a_string_or_array()
+ {
+ $page = MarkdownPost::make(matter: ['image' => 123]);
+ $this->assertNull(ConfiguresFeaturedImageForPost::run($page));
+ }
+
+ // test returns image object with local path when matter is string
+ public function test_action_returns_image_object_with_local_path_when_matter_is_string()
+ {
+ $page = MarkdownPost::make(matter: ['image' => 'foo.png']);
+ $image = ConfiguresFeaturedImageForPost::run($page);
+ $this->assertInstanceOf(Image::class, $image);
+ $this->assertEquals('foo.png', $image->path);
+ }
+
+ // test returns image object with remote path when matter is string
+ public function test_action_returns_image_object_with_remote_path_when_matter_is_string()
+ {
+ $page = MarkdownPost::make(matter: ['image' => 'https://example.com/foo.png']);
+ $image = ConfiguresFeaturedImageForPost::run($page);
+ $this->assertInstanceOf(Image::class, $image);
+ $this->assertEquals('https://example.com/foo.png', $image->uri);
+ }
+
+ // test returns image object with supplied data when matter is array
+ public function test_action_returns_image_object_with_supplied_data_when_matter_is_array()
+ {
+ $page = MarkdownPost::make(matter: ['image' => ['path' => 'foo.png', 'title' => 'bar']]);
+ $image = ConfiguresFeaturedImageForPost::run($page);
+ $this->assertInstanceOf(Image::class, $image);
+ $this->assertEquals('foo.png', $image->path);
+ $this->assertEquals('bar', $image->title);
+ }
+
+ public function test_action_requires_markdown_post_object_as_argument()
+ {
+ $this->expectException(\TypeError::class);
+ ConfiguresFeaturedImageForPost::run(new MarkdownPage());
+ }
+}
diff --git a/packages/framework/tests/Unit/DateStringTest.php b/packages/framework/tests/Unit/DateStringTest.php
index 35dca0ee08b..5cecc9cf672 100644
--- a/packages/framework/tests/Unit/DateStringTest.php
+++ b/packages/framework/tests/Unit/DateStringTest.php
@@ -40,4 +40,10 @@ public function test_it_can_format_date_string_into_short_human_readable_string(
$dateString = new DateString('2020-01-01 UTC');
$this->assertEquals('Jan 1st, 2020', $dateString->short);
}
+
+ public function test_it_can_format_date_string_into_short_human_readable_string_using_magic_method()
+ {
+ $dateString = new DateString('2022-01-01 UTC');
+ $this->assertEquals('Jan 1st, 2022', (string) $dateString);
+ }
}
diff --git a/packages/framework/tests/Unit/FrontMatterModelTest.php b/packages/framework/tests/Unit/FrontMatterModelTest.php
index 9f87387038b..2a326f0e482 100644
--- a/packages/framework/tests/Unit/FrontMatterModelTest.php
+++ b/packages/framework/tests/Unit/FrontMatterModelTest.php
@@ -25,14 +25,14 @@ public function test_constructor_arguments_are_optional()
public function test_constructor_arguments_are_assigned()
{
$matter = new FrontMatter(['foo' => 'bar']);
- $this->assertEquals(['foo' => 'bar'], $matter->matter);
+ $this->assertEquals(['foo' => 'bar'], $matter->data);
}
public function test_static_from_array_method_creates_new_front_matter_model()
{
$matter = FrontMatter::fromArray(['foo' => 'bar']);
$this->assertInstanceOf(FrontMatter::class, $matter);
- $this->assertEquals(['foo' => 'bar'], $matter->matter);
+ $this->assertEquals(['foo' => 'bar'], $matter->data);
}
public function test_to_string_magic_method_converts_model_array_into_yaml_front_matter()
diff --git a/packages/framework/tests/Unit/HasAuthorTest.php b/packages/framework/tests/Unit/HasAuthorTest.php
deleted file mode 100644
index 093e656cc69..00000000000
--- a/packages/framework/tests/Unit/HasAuthorTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-matter->get(...$args);
- }
-
- public function test_it_can_create_a_new_author_instance_from_username_string()
- {
- $this->matter = FrontMatter::fromArray([
- 'author' => 'John Doe',
- ]);
-
- $this->constructAuthor();
- $this->assertInstanceOf(Author::class, $this->author);
- $this->assertEquals('John Doe', $this->author->username);
- $this->assertNull($this->author->name);
- $this->assertNull($this->author->website);
- }
-
- public function test_it_can_create_a_new_author_instance_from_user_array()
- {
- $this->matter = FrontMatter::fromArray(['author' => [
- 'username' => 'john_doe',
- 'name' => 'John Doe',
- 'website' => 'https://example.com',
- ]]);
- $this->constructAuthor();
- $this->assertInstanceOf(Author::class, $this->author);
- $this->assertEquals('john_doe', $this->author->username);
- $this->assertEquals('John Doe', $this->author->name);
- $this->assertEquals('https://example.com', $this->author->website);
- }
-}
diff --git a/packages/framework/tests/Unit/HasFeaturedImageTest.php b/packages/framework/tests/Unit/HasFeaturedImageTest.php
deleted file mode 100644
index 9a78a3755d3..00000000000
--- a/packages/framework/tests/Unit/HasFeaturedImageTest.php
+++ /dev/null
@@ -1,71 +0,0 @@
-matter->get(...$args);
- }
-
- public function test_it_can_create_a_new_image_instance_from_a_string()
- {
- $this->matter = FrontMatter::fromArray([
- 'image' => 'https://example.com/image.jpg',
- ]);
-
- $this->constructFeaturedImage();
- $this->assertInstanceOf(Image::class, $this->image);
- $this->assertEquals('https://example.com/image.jpg', $this->image->uri);
- }
-
- public function test_it_can_create_a_new_image_instance_from_an_array()
- {
- $this->matter = FrontMatter::fromArray([
- 'image' => [
- 'uri' => 'https://example.com/image.jpg',
- ],
- ]);
-
- $this->constructFeaturedImage();
- $this->assertInstanceOf(Image::class, $this->image);
- $this->assertEquals('https://example.com/image.jpg', $this->image->uri);
- }
-
- public function test_construct_base_image_sets_the_source_to_the_image_uri_when_supplied_path_is_an_uri()
- {
- $image = $this->constructBaseImage('https://example.com/image.jpg');
- $this->assertEquals('https://example.com/image.jpg', $image->getSource());
- }
-
- public function test_construct_base_image_sets_the_source_to_the_image_path_when_supplied_path_is_a_local_path()
- {
- $image = $this->constructBaseImage('/path/to/image.jpg');
- $this->assertEquals('/path/to/image.jpg', $image->getSource());
- }
-
- public function test_construct_base_image_returns_an_image_instance_created_from_a_string()
- {
- $this->assertInstanceOf(Image::class, $this->constructBaseImage(''));
- }
-
- public function test_construct_full_image_returns_an_image_instance_created_from_an_array()
- {
- $this->assertInstanceOf(Image::class, $this->constructFullImage([]));
- }
-}