Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c15c827
Create FeaturedImageFactory.php
emmadesilva Oct 29, 2022
aeafe3e
Extends PageDataFactory, implements FeaturedImageSchema
emmadesilva Oct 29, 2022
93aa458
Add schema constant
emmadesilva Oct 29, 2022
f130141
Add required method stub
emmadesilva Oct 29, 2022
3b651f7
Add class properties
emmadesilva Oct 29, 2022
77a463d
Implement toArray() method.
emmadesilva Oct 29, 2022
b164daf
Add constructor
emmadesilva Oct 29, 2022
33afc45
Add method stubs
emmadesilva Oct 29, 2022
d2a5856
Create FeaturedImageFactoryTest.php
emmadesilva Oct 29, 2022
e2ad465
Factory needs to know front matter
emmadesilva Oct 29, 2022
1efd469
Implement the factory
emmadesilva Oct 29, 2022
b043824
Sketch out make method
emmadesilva Oct 29, 2022
ca4d1dc
Fix whoopsie: front matter keys must obviously be prefixed with image
emmadesilva Oct 29, 2022
a196c0a
Add source property
emmadesilva Oct 29, 2022
968a34e
Dynamically set the source
emmadesilva Oct 29, 2022
799589b
Throw RuntimeException if no source is set
emmadesilva Oct 29, 2022
8b73fa0
Return the proper image type
emmadesilva Oct 29, 2022
2998006
Source needs to be added to array
emmadesilva Oct 29, 2022
b612fdd
Normalize the local source path
emmadesilva Oct 29, 2022
555455e
Update FeaturedImageFactoryTest.php
emmadesilva Oct 29, 2022
907fa06
Inline variables
emmadesilva Oct 29, 2022
015d22c
Revert "Inline variables"
emmadesilva Oct 29, 2022
b6925b7
Inline only single variable
emmadesilva Oct 29, 2022
d5b6037
Invert logic to check on normalized data
emmadesilva Oct 29, 2022
0f08b61
No longer validate if remote image starts with http
emmadesilva Oct 29, 2022
4b843c6
Implement the test stubs
emmadesilva Oct 29, 2022
74585ae
Add content assertions
emmadesilva Oct 29, 2022
b90be86
Fix local variable name
emmadesilva Oct 29, 2022
c6af53e
Apply fixes from StyleCI
StyleCIBot Oct 29, 2022
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
138 changes: 138 additions & 0 deletions packages/framework/src/Framework/Factories/FeaturedImageFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Factories;

use Hyde\Framework\Concerns\InteractsWithFrontMatter;
use Hyde\Framework\Features\Blogging\Models\FeaturedImage;
use Hyde\Framework\Features\Blogging\Models\LocalFeaturedImage;
use Hyde\Framework\Features\Blogging\Models\RemoteFeaturedImage;
use Hyde\Hyde;
use Hyde\Markdown\Contracts\FrontMatter\SubSchemas\FeaturedImageSchema;
use Hyde\Markdown\Models\FrontMatter;
use function is_string;
use RuntimeException;
use function str_starts_with;

class FeaturedImageFactory extends Concerns\PageDataFactory implements FeaturedImageSchema
{
use InteractsWithFrontMatter;

public const SCHEMA = FeaturedImageSchema::FEATURED_IMAGE_SCHEMA;

protected readonly string $source;
protected readonly ?string $altText;
protected readonly ?string $titleText;
protected readonly ?string $authorName;
protected readonly ?string $authorUrl;
protected readonly ?string $copyrightText;
protected readonly ?string $licenseName;
protected readonly ?string $licenseUrl;

public function __construct(
private readonly FrontMatter $matter,
) {
$this->source = $this->makeSource();
$this->altText = $this->makeAltText();
$this->titleText = $this->makeTitleText();
$this->authorName = $this->makeAuthorName();
$this->authorUrl = $this->makeAuthorUrl();
$this->copyrightText = $this->makeCopyrightText();
$this->licenseName = $this->makeLicenseName();
$this->licenseUrl = $this->makeLicenseUrl();
}

public function toArray(): array
{
return [
'source' => $this->source,
'altText' => $this->altText,
'titleText' => $this->titleText,
'authorName' => $this->authorName,
'authorUrl' => $this->authorUrl,
'copyrightText' => $this->copyrightText,
'licenseName' => $this->licenseName,
'licenseUrl' => $this->licenseUrl,
];
}

public static function make(FrontMatter $matter): FeaturedImage
{
$data = (new static($matter))->toArray();

if (str_starts_with($data['source'], '_media')) {
return new LocalFeaturedImage(...$data);
}

return new RemoteFeaturedImage(...$data);
}

protected function makeSource(): string
{
if (is_string($this->matter('image'))) {
return $this->matter('image');
}

if ($this->matter('image.url') !== null) {
return $this->matter('image.url');
}

if ($this->matter('image.path') !== null) {
return $this->normalizeLocalImagePath($this->matter('image.path'));
}

// Todo, we might want to add a note about which file caused the error
throw new RuntimeException('No featured image source was found');
}

protected function makeAltText(): ?string
{
return $this->matter('image.description');
}

protected function makeTitleText(): ?string
{
return $this->matter('image.title');
}

protected function makeAuthorName(): ?string
{
return $this->matter('image.author');
}

protected function makeAuthorUrl(): ?string
{
return $this->matter('image.attributionUrl');
}

protected function makeCopyrightText(): ?string
{
return $this->matter('image.copyright');
}

protected function makeLicenseName(): ?string
{
return $this->matter('image.license');
}

protected function makeLicenseUrl(): ?string
{
return $this->matter('image.licenseUrl');
}

protected static function normalizeLocalImagePath(string $path): string
{
$path = Hyde::pathToRelative($path);

if (str_starts_with($path, '_media/')) {
return $path;
}

if (str_starts_with($path, 'media/')) {
return '_'.$path;
}

return '_media/'.$path;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use function array_key_exists;
use function config;
use Illuminate\Support\Facades\Http;
use InvalidArgumentException;
use function key;

class RemoteFeaturedImage extends FeaturedImage
Expand All @@ -17,10 +16,7 @@ class RemoteFeaturedImage extends FeaturedImage

protected function setSource(string $source): void
{
if (! str_starts_with($source, 'http')) {
// Throwing an exception here ensures we have a super predictable state.
throw new InvalidArgumentException('RemoteFeaturedImage source must be a valid URL');
}
// Here we can validate the source URL if we want.

$this->source = $source;
}
Expand Down
96 changes: 96 additions & 0 deletions packages/framework/tests/Feature/FeaturedImageFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Feature;

use Hyde\Framework\Factories\FeaturedImageFactory;
use Hyde\Framework\Features\Blogging\Models\LocalFeaturedImage;
use Hyde\Framework\Features\Blogging\Models\RemoteFeaturedImage;
use Hyde\Markdown\Models\FrontMatter;
use Hyde\Testing\TestCase;
use RuntimeException;

/**
* @covers \Hyde\Framework\Factories\FeaturedImageFactory
*/
class FeaturedImageFactoryTest extends TestCase
{
public function testWithDataFromSchema()
{
$array = [
'image.path' => 'path',
'image.url' => 'url',
'image.description' => 'description',
'image.title' => 'title',
'image.copyright' => 'copyright',
'image.license' => 'license',
'image.licenseUrl' => 'licenseUrl',
'image.author' => 'author',
'image.attributionUrl' => 'attributionUrl',
];

$expected = [
'source' => 'url',
'altText' => 'description',
'titleText' => 'title',
'authorName' => 'author',
'authorUrl' => 'attributionUrl',
'copyrightText' => 'copyright',
'licenseName' => 'license',
'licenseUrl' => 'licenseUrl',
];

$factory = new FeaturedImageFactory(new FrontMatter($array));

$this->assertSame($expected, $factory->toArray());
}

public function testMakeMethodCreatesLocalImageWhenPathIsSet()
{
$image = FeaturedImageFactory::make(new FrontMatter([
'image.path' => 'path',
]));

$this->assertInstanceOf(LocalFeaturedImage::class, $image);
$this->assertSame('_media/path', $image->getSource());
}

public function testMakeMethodCreatesRemoteImageWhenUrlIsSet()
{
$image = FeaturedImageFactory::make(new FrontMatter([
'image.url' => 'url',
]));

$this->assertInstanceOf(RemoteFeaturedImage::class, $image);
$this->assertSame('url', $image->getSource());
}

public function testMakeMethodCreatesRemoteImageWhenBothUrlAndPathIsSet()
{
$image = FeaturedImageFactory::make(new FrontMatter([
'image.url' => 'url',
'image.path' => 'path',
]));

$this->assertInstanceOf(RemoteFeaturedImage::class, $image);
$this->assertSame('url', $image->getSource());
}

public function testMakeMethodThrowsExceptionIfNoPathInformationIsSet()
{
$this->expectException(RuntimeException::class);

FeaturedImageFactory::make(new FrontMatter([]));
}

public function testMakeMethodCanCreateImageFromJustString()
{
$image = FeaturedImageFactory::make(new FrontMatter([
'image' => 'foo',
]));

$this->assertInstanceOf(RemoteFeaturedImage::class, $image);
$this->assertSame('foo', $image->getSource());
}
}
8 changes: 3 additions & 5 deletions packages/framework/tests/Feature/FeaturedImageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,10 @@ public function testCanConstructRemoteFeaturedImageWithHttps()
$this->assertEquals('https/foo', $image->getSource());
}

public function testCannotConstructRemoteFeaturedImageWithInvalidSource()
public function testCanConstructRemoteFeaturedImageWithInvalidSource()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('RemoteFeaturedImage source must be a valid URL');

new RemoteFeaturedImage('foo', ...$this->defaultArguments());
$image = new RemoteFeaturedImage('foo', ...$this->defaultArguments());
$this->assertEquals('foo', $image->getSource());
}

public function testFeaturedImageGetContentLengthWithRemoteSource()
Expand Down