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([])); - } -}