From ee9709925754290047d3632269d02f7d92c16ec1 Mon Sep 17 00:00:00 2001 From: OStefan2001 Date: Wed, 30 Sep 2026 12:32:09 +0300 Subject: [PATCH 1/3] Update post slug to Autologin using Cookie post and and posibility to update/add post_slug using fixtures --- src/App/src/Fixture/PostLoader.php | 25 ++++++++++++++++------- src/App/src/Fixture/articles_cleaned.json | 1 + 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/App/src/Fixture/PostLoader.php b/src/App/src/Fixture/PostLoader.php index 96474a4..6c08dd9 100644 --- a/src/App/src/Fixture/PostLoader.php +++ b/src/App/src/Fixture/PostLoader.php @@ -55,17 +55,20 @@ public function load(ObjectManager $manager): void } /** @var Author $author */ - $author = $this->getReference('author_' . $authorSlug, Author::class); - $title = html_entity_decode($articleData['post_title'], ENT_QUOTES, 'UTF-8'); - $slug = $this->slugify($title); + $author = $this->getReference('author_' . $authorSlug, Author::class); + $title = html_entity_decode($articleData['post_title'], ENT_QUOTES, 'UTF-8'); + $autoSlug = $this->slugify($title); - if (isset($usedSlugs[$slug])) { - $usedSlugs[$slug]++; - $slug .= '-' . $usedSlugs[$slug]; + if (isset($usedSlugs[$autoSlug])) { + $usedSlugs[$autoSlug]++; + $autoSlug .= '-' . $usedSlugs[$autoSlug]; } else { - $usedSlugs[$slug] = 1; + $usedSlugs[$autoSlug] = 1; } + $customSlug = trim((string) ($articleData['post_slug'] ?? '')); + $slug = $customSlug !== '' ? $customSlug : $autoSlug; + $status = match ($articleData['post_status']) { 'published' => PostStatusEnum::Published, 'private' => PostStatusEnum::Private, @@ -85,6 +88,10 @@ public function load(ObjectManager $manager): void $openGraphImg = $articleData['opengraph_img'] ?? null; $article = $repository->findOneBy(['slug' => $slug]); + if ($article === null && $slug !== $autoSlug) { + // post was imported before post_slug was set: find it by the title-based slug + $article = $repository->findOneBy(['slug' => $autoSlug]); + } if ($article === null) { $article = new Post(); @@ -105,6 +112,10 @@ public function load(ObjectManager $manager): void } else { $changed = false; + if ($article->getSlug() !== $slug) { + $article->setSlug($slug); + $changed = true; + } if ($article->getTitle() !== $title) { $article->setTitle($title); $changed = true; diff --git a/src/App/src/Fixture/articles_cleaned.json b/src/App/src/Fixture/articles_cleaned.json index ff1fb05..a98c152 100644 --- a/src/App/src/Fixture/articles_cleaned.json +++ b/src/App/src/Fixture/articles_cleaned.json @@ -936,6 +936,7 @@ }, { "post_title": "Autologin using Cookie / Remember Me in Dotkernel", + "post_slug": "autologin-cookie-remember-me-feature", "post_date": "2022-07-18 09:12:59", "post_status": "published", "author": { From 21db1e42536f4359703972c0f603f0c1823d703b Mon Sep 17 00:00:00 2001 From: OStefan2001 Date: Wed, 30 Sep 2026 12:38:40 +0300 Subject: [PATCH 2/3] add test --- test/Unit/App/Fixture/PostLoaderTest.php | 372 +++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 test/Unit/App/Fixture/PostLoaderTest.php diff --git a/test/Unit/App/Fixture/PostLoaderTest.php b/test/Unit/App/Fixture/PostLoaderTest.php new file mode 100644 index 0000000..a680058 --- /dev/null +++ b/test/Unit/App/Fixture/PostLoaderTest.php @@ -0,0 +1,372 @@ +jsonFile = sprintf( + '%s%slight-post-loader-%s%sarticles_cleaned.json', + sys_get_temp_dir(), + DIRECTORY_SEPARATOR, + bin2hex(random_bytes(8)), + DIRECTORY_SEPARATOR + ); + + mkdir(dirname($this->jsonFile), 0775, true); + + $this->author = new Author(); + $this->category = new Category(); + } + + protected function tearDown(): void + { + if (is_file($this->jsonFile)) { + unlink($this->jsonFile); + } + + $directory = dirname($this->jsonFile); + if (is_dir($directory)) { + rmdir($directory); + } + + parent::tearDown(); + } + + /** + * @throws Exception + */ + public function testLoadCreatesPostWithCustomSlugWhenNothingMatchesInDb(): void + { + $this->writeArticles([ + $this->article('A post', ['post_slug' => ' custom-slug ']), + ]); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository([], $lookups)); + + $persisted = null; + $manager->expects($this->once())->method('persist') + ->willReturnCallback(function (Post $post) use (&$persisted): void { + $persisted = $post; + }); + $manager->expects($this->once())->method('flush'); + + $this->expectOutputString("CREATE: A post\n"); + $this->runLoader($manager); + + $this->assertInstanceOf(Post::class, $persisted); + $this->assertSame('custom-slug', $persisted->getSlug()); + $this->assertSame(['custom-slug', 'a-post'], $lookups); + } + + /** + * @throws Exception + */ + public function testLoadUpdatesExistingPostFoundByCustomSlug(): void + { + $this->writeArticles([ + $this->article('A post', ['post_slug' => 'custom-slug']), + ]); + + $existing = $this->existingPost('custom-slug', 'A post'); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository(['custom-slug' => $existing], $lookups)); + $manager->expects($this->never())->method('persist'); + + $this->expectOutputString("UNCHANGED: A post\n"); + $this->runLoader($manager); + + $this->assertSame('custom-slug', $existing->getSlug()); + $this->assertSame(['custom-slug'], $lookups); + } + + /** + * @throws Exception + */ + public function testLoadRenamesExistingPostFoundByTitleSlugToCustomSlug(): void + { + $this->writeArticles([ + $this->article('A post', ['post_slug' => 'custom-slug']), + ]); + + // Imported before post_slug was added to the JSON. + $existing = $this->existingPost('a-post', 'A post'); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository(['a-post' => $existing], $lookups)); + $manager->expects($this->never())->method('persist'); + + $this->expectOutputString("UPDATE: A post\n"); + $this->runLoader($manager); + + $this->assertSame('custom-slug', $existing->getSlug()); + $this->assertSame(['custom-slug', 'a-post'], $lookups); + } + + /** + * @throws Exception + */ + public function testLoadFallsBackToTitleSlugWhenPostSlugIsMissingOrEmpty(): void + { + $this->writeArticles([ + $this->article('A post'), + $this->article('A post', ['post_slug' => '']), + ]); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository([], $lookups)); + $manager->expects($this->exactly(2))->method('persist'); + + $this->expectOutputString("CREATE: A post\nCREATE: A post\n"); + $this->runLoader($manager); + + $this->assertSame(['a-post', 'a-post-2'], $lookups); + } + + /** + * @throws Exception + */ + public function testLoadUpdatesEveryChangedFieldOnExistingPost(): void + { + $this->writeArticles([ + $this->article('A post', [ + 'post_status' => 'archived', + 'post_date' => '0000-00-00 00:00:00', + 'excerpt' => 'New excerpt', + 'tl_dr' => 'New TL;DR', + 'isObsolete' => true, + 'isTwig' => true, + 'opengraph_img' => 'og.png', + ]), + ]); + + $existing = $this->existingPost('a-post', 'Old title'); + $existing->setCategory(new Category()); + $existing->setAuthor(new Author()); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository(['a-post' => $existing], $lookups)); + $manager->expects($this->never())->method('persist'); + + $this->expectOutputString("UPDATE: A post\n"); + $this->runLoader($manager); + + $this->assertSame('A post', $existing->getTitle()); + $this->assertSame(PostStatusEnum::Archived, $existing->getStatus()); + $this->assertNotSame('2022-07-18 09:12:59', $existing->getPostDate()->format('Y-m-d H:i:s')); + $this->assertSame($this->category, $existing->getCategory()); + $this->assertSame($this->author, $existing->getAuthor()); + $this->assertSame('New excerpt', $existing->getExcerpt()); + $this->assertSame('New TL;DR', $existing->getTlDr()); + $this->assertTrue($existing->isObsolete()); + $this->assertTrue($existing->isTwig()); + $this->assertSame('og.png', $existing->getOpenGraphImage()); + } + + /** + * @throws Exception + */ + public function testLoadMapsPostStatuses(): void + { + $this->writeArticles([ + $this->article('Private post', ['post_status' => 'private']), + $this->article('Draft post', ['post_status' => 'unknown']), + ]); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository([], $lookups)); + + $statuses = []; + $manager->expects($this->exactly(2))->method('persist') + ->willReturnCallback(function (Post $post) use (&$statuses): void { + $statuses[] = $post->getStatus(); + }); + + $this->expectOutputString("CREATE: Private post\nCREATE: Draft post\n"); + $this->runLoader($manager); + + $this->assertSame([PostStatusEnum::Private, PostStatusEnum::Draft], $statuses); + } + + /** + * @throws Exception + */ + public function testLoadSkipsArticleWithUnknownAuthor(): void + { + $this->writeArticles([ + $this->article('A post', ['author' => ['display_name' => 'nobody']]), + ]); + + $lookups = []; + $manager = $this->createEntityManager($this->createRepository([], $lookups)); + $manager->expects($this->never())->method('persist'); + + $this->expectOutputString("SKIP (no author): A post\n"); + $this->runLoader($manager); + + $this->assertSame([], $lookups); + } + + /** + * @throws Exception + */ + public function testLoadThrowsWhenJsonFileCannotBeRead(): void + { + $manager = $this->createStub(EntityManagerInterface::class); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Unable to read file'); + + @$this->runLoader($manager); + } + + public function testDependenciesAndOrder(): void + { + $loader = new PostLoader($this->jsonFile); + + $this->assertSame([AuthorLoader::class, CategoryLoader::class], $loader->getDependencies()); + $this->assertSame(3, $loader->getOrder()); + } + + /** + * @param array $extra + * @return array + */ + private function article(string $title, array $extra = []): array + { + return $extra + [ + 'post_title' => $title, + 'post_date' => '2022-07-18 09:12:59', + 'post_status' => 'published', + 'author' => ['display_name' => 'arhimede'], + 'excerpt' => 'Excerpt', + 'tl_dr' => 'TL;DR', + 'tags' => [], + ]; + } + + private function existingPost(string $slug, string $title): Post + { + $post = new Post(); + $post->setSlug($slug); + $post->setTitle($title); + $post->setPostDate(new DateTimeImmutable('2022-07-18 09:12:59')); + $post->setStatus(PostStatusEnum::Published); + $post->setCategory($this->category); + $post->setAuthor($this->author); + $post->setExcerpt('Excerpt'); + $post->setTldr('TL;DR'); + $post->setObsolete(false); + $post->setTwig(false); + $post->setOpenGraphImage(null); + + return $post; + } + + /** + * @param list> $articles + */ + private function writeArticles(array $articles): void + { + file_put_contents($this->jsonFile, json_encode([ + ['slug' => 'category', 'articles' => $articles], + ])); + } + + /** + * @param array $postsBySlug + * @param list $lookups + * @return EntityRepository + * @throws Exception + */ + private function createRepository(array $postsBySlug, array &$lookups): EntityRepository + { + $repository = $this->createStub(EntityRepository::class); + $repository->method('findOneBy')->willReturnCallback( + function (array $criteria) use ($postsBySlug, &$lookups): ?Post { + $lookups[] = $criteria['slug']; + return $postsBySlug[$criteria['slug']] ?? null; + } + ); + + return $repository; + } + + private function runLoader(EntityManagerInterface $manager): void + { + $referenceRepository = new ReferenceRepository($manager); + $referenceRepository->addReference('category_category', $this->category); + $referenceRepository->addReference('author_arhimede', $this->author); + + $loader = new PostLoader($this->jsonFile); + $loader->setReferenceRepository($referenceRepository); + $loader->load($manager); + } + + /** + * @param EntityRepository $repository + * @throws Exception + */ + private function createEntityManager(EntityRepository $repository): EntityManagerInterface&MockObject + { + $manager = $this->createMock(EntityManagerInterface::class); + $manager->method('getRepository')->willReturn($repository); + $manager->method('contains')->willReturn(true); + + $unitOfWork = $this->createStub(UnitOfWork::class); + $unitOfWork->method('isInIdentityMap')->willReturn(false); + $manager->method('getUnitOfWork')->willReturn($unitOfWork); + + $manager->method('getClassMetadata')->willReturnCallback(function (string $class) { + $metadata = $this->createStub(ClassMetadata::class); + $metadata->method('getName')->willReturn($class); + return $metadata; + }); + + return $manager; + } +} From dc1c07c15df0d7e1cf9223fa8b0e9513d2b6625c Mon Sep 17 00:00:00 2001 From: OStefan2001 Date: Wed, 30 Sep 2026 12:40:15 +0300 Subject: [PATCH 3/3] update test --- test/Unit/App/Fixture/PostLoaderTest.php | 316 ++++++----------------- 1 file changed, 73 insertions(+), 243 deletions(-) diff --git a/test/Unit/App/Fixture/PostLoaderTest.php b/test/Unit/App/Fixture/PostLoaderTest.php index a680058..f5bf88d 100644 --- a/test/Unit/App/Fixture/PostLoaderTest.php +++ b/test/Unit/App/Fixture/PostLoaderTest.php @@ -16,307 +16,113 @@ use Light\Blog\Entity\Author; use Light\Blog\Entity\Category; use Light\Blog\Entity\Post; -use Light\Blog\Enum\PostStatusEnum; use LightTest\Unit\UnitTest; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\MockObject\MockObject; -use RuntimeException; -use function bin2hex; +use function array_count_values; use function dirname; -use function file_put_contents; -use function is_dir; -use function is_file; -use function json_encode; -use function mkdir; -use function random_bytes; -use function rmdir; -use function sprintf; -use function sys_get_temp_dir; -use function unlink; - -use const DIRECTORY_SEPARATOR; - +use function file_get_contents; +use function json_decode; +use function preg_quote; +use function preg_replace; +use function strtolower; +use function trim; + +/** + * Runs PostLoader against the real articles_cleaned.json, using the + * "Autologin using Cookie / Remember Me in Dotkernel" article that sets post_slug. + */ class PostLoaderTest extends UnitTest { - private string $jsonFile; - private Author $author; - private Category $category; - - protected function setUp(): void - { - parent::setUp(); - - $this->jsonFile = sprintf( - '%s%slight-post-loader-%s%sarticles_cleaned.json', - sys_get_temp_dir(), - DIRECTORY_SEPARATOR, - bin2hex(random_bytes(8)), - DIRECTORY_SEPARATOR - ); - - mkdir(dirname($this->jsonFile), 0775, true); - - $this->author = new Author(); - $this->category = new Category(); - } - - protected function tearDown(): void - { - if (is_file($this->jsonFile)) { - unlink($this->jsonFile); - } - - $directory = dirname($this->jsonFile); - if (is_dir($directory)) { - rmdir($directory); - } - - parent::tearDown(); - } + private const string TITLE = 'Autologin using Cookie / Remember Me in Dotkernel'; + private const string CUSTOM_SLUG = 'autologin-cookie-remember-me-feature'; + private const string TITLE_SLUG = 'autologin-using-cookie-remember-me-in-dotkernel'; /** * @throws Exception */ public function testLoadCreatesPostWithCustomSlugWhenNothingMatchesInDb(): void { - $this->writeArticles([ - $this->article('A post', ['post_slug' => ' custom-slug ']), - ]); - $lookups = []; $manager = $this->createEntityManager($this->createRepository([], $lookups)); - $persisted = null; - $manager->expects($this->once())->method('persist') - ->willReturnCallback(function (Post $post) use (&$persisted): void { - $persisted = $post; + $persistedSlugs = []; + $manager->expects($this->atLeastOnce())->method('persist') + ->willReturnCallback(function (Post $post) use (&$persistedSlugs): void { + $persistedSlugs[$post->getTitle()] = $post->getSlug(); }); - $manager->expects($this->once())->method('flush'); - - $this->expectOutputString("CREATE: A post\n"); - $this->runLoader($manager); - - $this->assertInstanceOf(Post::class, $persisted); - $this->assertSame('custom-slug', $persisted->getSlug()); - $this->assertSame(['custom-slug', 'a-post'], $lookups); - } - - /** - * @throws Exception - */ - public function testLoadUpdatesExistingPostFoundByCustomSlug(): void - { - $this->writeArticles([ - $this->article('A post', ['post_slug' => 'custom-slug']), - ]); - - $existing = $this->existingPost('custom-slug', 'A post'); - - $lookups = []; - $manager = $this->createEntityManager($this->createRepository(['custom-slug' => $existing], $lookups)); - $manager->expects($this->never())->method('persist'); - - $this->expectOutputString("UNCHANGED: A post\n"); - $this->runLoader($manager); - - $this->assertSame('custom-slug', $existing->getSlug()); - $this->assertSame(['custom-slug'], $lookups); - } - - /** - * @throws Exception - */ - public function testLoadRenamesExistingPostFoundByTitleSlugToCustomSlug(): void - { - $this->writeArticles([ - $this->article('A post', ['post_slug' => 'custom-slug']), - ]); - - // Imported before post_slug was added to the JSON. - $existing = $this->existingPost('a-post', 'A post'); - - $lookups = []; - $manager = $this->createEntityManager($this->createRepository(['a-post' => $existing], $lookups)); - $manager->expects($this->never())->method('persist'); - - $this->expectOutputString("UPDATE: A post\n"); - $this->runLoader($manager); - - $this->assertSame('custom-slug', $existing->getSlug()); - $this->assertSame(['custom-slug', 'a-post'], $lookups); - } - - /** - * @throws Exception - */ - public function testLoadFallsBackToTitleSlugWhenPostSlugIsMissingOrEmpty(): void - { - $this->writeArticles([ - $this->article('A post'), - $this->article('A post', ['post_slug' => '']), - ]); - - $lookups = []; - $manager = $this->createEntityManager($this->createRepository([], $lookups)); - $manager->expects($this->exactly(2))->method('persist'); - $this->expectOutputString("CREATE: A post\nCREATE: A post\n"); + $this->expectOutputRegex('/CREATE: ' . preg_quote(self::TITLE, '/') . '\n/'); $this->runLoader($manager); - $this->assertSame(['a-post', 'a-post-2'], $lookups); - } - - /** - * @throws Exception - */ - public function testLoadUpdatesEveryChangedFieldOnExistingPost(): void - { - $this->writeArticles([ - $this->article('A post', [ - 'post_status' => 'archived', - 'post_date' => '0000-00-00 00:00:00', - 'excerpt' => 'New excerpt', - 'tl_dr' => 'New TL;DR', - 'isObsolete' => true, - 'isTwig' => true, - 'opengraph_img' => 'og.png', - ]), - ]); - - $existing = $this->existingPost('a-post', 'Old title'); - $existing->setCategory(new Category()); - $existing->setAuthor(new Author()); - - $lookups = []; - $manager = $this->createEntityManager($this->createRepository(['a-post' => $existing], $lookups)); - $manager->expects($this->never())->method('persist'); - - $this->expectOutputString("UPDATE: A post\n"); - $this->runLoader($manager); + $this->assertSame(self::CUSTOM_SLUG, $persistedSlugs[self::TITLE]); + $this->assertNotContains(self::TITLE_SLUG, $persistedSlugs); - $this->assertSame('A post', $existing->getTitle()); - $this->assertSame(PostStatusEnum::Archived, $existing->getStatus()); - $this->assertNotSame('2022-07-18 09:12:59', $existing->getPostDate()->format('Y-m-d H:i:s')); - $this->assertSame($this->category, $existing->getCategory()); - $this->assertSame($this->author, $existing->getAuthor()); - $this->assertSame('New excerpt', $existing->getExcerpt()); - $this->assertSame('New TL;DR', $existing->getTlDr()); - $this->assertTrue($existing->isObsolete()); - $this->assertTrue($existing->isTwig()); - $this->assertSame('og.png', $existing->getOpenGraphImage()); + // Not found by post_slug, so the title-based slug is tried before creating. + $counts = array_count_values($lookups); + $this->assertSame(1, $counts[self::CUSTOM_SLUG]); + $this->assertSame(1, $counts[self::TITLE_SLUG]); } /** * @throws Exception */ - public function testLoadMapsPostStatuses(): void + public function testLoadUpdatesPostFoundByCustomSlug(): void { - $this->writeArticles([ - $this->article('Private post', ['post_status' => 'private']), - $this->article('Draft post', ['post_status' => 'unknown']), - ]); + $existing = $this->existingPost(self::CUSTOM_SLUG, 'Old title'); $lookups = []; - $manager = $this->createEntityManager($this->createRepository([], $lookups)); - - $statuses = []; - $manager->expects($this->exactly(2))->method('persist') - ->willReturnCallback(function (Post $post) use (&$statuses): void { - $statuses[] = $post->getStatus(); - }); + $manager = $this->createEntityManager($this->createRepository([self::CUSTOM_SLUG => $existing], $lookups)); + $manager->expects($this->atLeastOnce())->method('flush'); - $this->expectOutputString("CREATE: Private post\nCREATE: Draft post\n"); + $this->expectOutputRegex('/UPDATE: ' . preg_quote(self::TITLE, '/') . '\n/'); $this->runLoader($manager); - $this->assertSame([PostStatusEnum::Private, PostStatusEnum::Draft], $statuses); + $this->assertSame(self::CUSTOM_SLUG, $existing->getSlug()); + $this->assertSame(self::TITLE, $existing->getTitle()); + $this->assertNotContains(self::TITLE_SLUG, $lookups); } /** * @throws Exception */ - public function testLoadSkipsArticleWithUnknownAuthor(): void + public function testLoadRenamesPostImportedUnderTitleSlugToCustomSlug(): void { - $this->writeArticles([ - $this->article('A post', ['author' => ['display_name' => 'nobody']]), - ]); + // Imported before post_slug was added to the JSON. + $existing = $this->existingPost(self::TITLE_SLUG, self::TITLE); $lookups = []; - $manager = $this->createEntityManager($this->createRepository([], $lookups)); - $manager->expects($this->never())->method('persist'); + $manager = $this->createEntityManager($this->createRepository([self::TITLE_SLUG => $existing], $lookups)); + $manager->expects($this->atLeastOnce())->method('flush'); - $this->expectOutputString("SKIP (no author): A post\n"); + $this->expectOutputRegex('/UPDATE: ' . preg_quote(self::TITLE, '/') . '\n/'); $this->runLoader($manager); - $this->assertSame([], $lookups); - } - - /** - * @throws Exception - */ - public function testLoadThrowsWhenJsonFileCannotBeRead(): void - { - $manager = $this->createStub(EntityManagerInterface::class); - - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Unable to read file'); - - @$this->runLoader($manager); + $this->assertSame(self::CUSTOM_SLUG, $existing->getSlug()); } public function testDependenciesAndOrder(): void { - $loader = new PostLoader($this->jsonFile); + $loader = new PostLoader(); $this->assertSame([AuthorLoader::class, CategoryLoader::class], $loader->getDependencies()); $this->assertSame(3, $loader->getOrder()); } - /** - * @param array $extra - * @return array - */ - private function article(string $title, array $extra = []): array - { - return $extra + [ - 'post_title' => $title, - 'post_date' => '2022-07-18 09:12:59', - 'post_status' => 'published', - 'author' => ['display_name' => 'arhimede'], - 'excerpt' => 'Excerpt', - 'tl_dr' => 'TL;DR', - 'tags' => [], - ]; - } - private function existingPost(string $slug, string $title): Post { $post = new Post(); $post->setSlug($slug); $post->setTitle($title); - $post->setPostDate(new DateTimeImmutable('2022-07-18 09:12:59')); - $post->setStatus(PostStatusEnum::Published); - $post->setCategory($this->category); - $post->setAuthor($this->author); - $post->setExcerpt('Excerpt'); - $post->setTldr('TL;DR'); - $post->setObsolete(false); - $post->setTwig(false); - $post->setOpenGraphImage(null); + $post->setPostDate(new DateTimeImmutable()); + $post->setCategory(new Category()); + $post->setAuthor(new Author()); + $post->setExcerpt(''); return $post; } - /** - * @param list> $articles - */ - private function writeArticles(array $articles): void - { - file_put_contents($this->jsonFile, json_encode([ - ['slug' => 'category', 'articles' => $articles], - ])); - } - /** * @param array $postsBySlug * @param list $lookups @@ -336,17 +142,41 @@ function (array $criteria) use ($postsBySlug, &$lookups): ?Post { return $repository; } + /** + * Registers the category and author references the real articles_cleaned.json needs. + */ private function runLoader(EntityManagerInterface $manager): void { + $contents = file_get_contents(dirname(__DIR__, 4) . '/src/App/src/Fixture/articles_cleaned.json'); + $this->assertIsString($contents); + + /** @var list}> $categories */ + $categories = json_decode($contents, true); + $referenceRepository = new ReferenceRepository($manager); - $referenceRepository->addReference('category_category', $this->category); - $referenceRepository->addReference('author_arhimede', $this->author); + foreach ($categories as $category) { + $referenceRepository->setReference('category_' . $category['slug'], new Category()); + + foreach ($category['articles'] as $article) { + $authorName = $article['author']['display_name'] ?? null; + if ($authorName !== null) { + $referenceRepository->setReference('author_' . $this->slugify($authorName), new Author()); + } + } + } - $loader = new PostLoader($this->jsonFile); + $loader = new PostLoader(); $loader->setReferenceRepository($referenceRepository); $loader->load($manager); } + private function slugify(string $text): string + { + $text = strtolower(trim($text)); + $text = preg_replace('/[^a-z0-9]+/', '-', $text) ?? ''; + return trim($text, '-'); + } + /** * @param EntityRepository $repository * @throws Exception