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

Add featured image factory #620

Merged
merged 29 commits into from
Oct 29, 2022
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
caendesilva Oct 29, 2022
aeafe3e
Extends PageDataFactory, implements FeaturedImageSchema
caendesilva Oct 29, 2022
93aa458
Add schema constant
caendesilva Oct 29, 2022
f130141
Add required method stub
caendesilva Oct 29, 2022
3b651f7
Add class properties
caendesilva Oct 29, 2022
77a463d
Implement toArray() method.
caendesilva Oct 29, 2022
b164daf
Add constructor
caendesilva Oct 29, 2022
33afc45
Add method stubs
caendesilva Oct 29, 2022
d2a5856
Create FeaturedImageFactoryTest.php
caendesilva Oct 29, 2022
e2ad465
Factory needs to know front matter
caendesilva Oct 29, 2022
1efd469
Implement the factory
caendesilva Oct 29, 2022
b043824
Sketch out make method
caendesilva Oct 29, 2022
ca4d1dc
Fix whoopsie: front matter keys must obviously be prefixed with image
caendesilva Oct 29, 2022
a196c0a
Add source property
caendesilva Oct 29, 2022
968a34e
Dynamically set the source
caendesilva Oct 29, 2022
799589b
Throw RuntimeException if no source is set
caendesilva Oct 29, 2022
8b73fa0
Return the proper image type
caendesilva Oct 29, 2022
2998006
Source needs to be added to array
caendesilva Oct 29, 2022
b612fdd
Normalize the local source path
caendesilva Oct 29, 2022
555455e
Update FeaturedImageFactoryTest.php
caendesilva Oct 29, 2022
907fa06
Inline variables
caendesilva Oct 29, 2022
015d22c
Revert "Inline variables"
caendesilva Oct 29, 2022
b6925b7
Inline only single variable
caendesilva Oct 29, 2022
d5b6037
Invert logic to check on normalized data
caendesilva Oct 29, 2022
0f08b61
No longer validate if remote image starts with http
caendesilva Oct 29, 2022
4b843c6
Implement the test stubs
caendesilva Oct 29, 2022
74585ae
Add content assertions
caendesilva Oct 29, 2022
b90be86
Fix local variable name
caendesilva 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