From 235539e4a5a95e59f7452521e5cfe787ba6a2869 Mon Sep 17 00:00:00 2001 From: Thor Brink Date: Tue, 14 Jan 2025 13:58:32 +0100 Subject: [PATCH] feat: allow PostObject getIcon() to get icons from other blog if origin of post is other blog (#1243) --- library/Helper/Post.php | 10 +- .../BackwardsCompatiblePostObject.php | 63 ++++++++++++- .../Decorators/IconResolvingPostObject.php | 53 ++++++++++- .../IconResolvingPostObject.test.php | 6 +- .../Decorators/PostObjectFromOtherBlog.php | 93 +++++++++++++++++++ .../PostObjectFromOtherBlog.test.php | 39 ++++++++ .../Decorators/PostObjectFromWpPost.php | 22 ++++- .../Decorators/PostObjectFromWpPost.test.php | 8 +- ...bjectWithOtherBlogIdFromSwitchedState.php} | 29 +++++- ...tWithOtherBlogIdFromSwitchedState.test.php | 54 +++++++++++ .../Icon/Resolvers/CachedIconResolver.php | 2 +- library/PostObject/PostObject.php | 17 +++- library/PostObject/PostObject.test.php | 14 ++- library/PostObject/PostObjectInterface.php | 8 ++ 14 files changed, 392 insertions(+), 26 deletions(-) create mode 100644 library/PostObject/Decorators/PostObjectFromOtherBlog.php create mode 100644 library/PostObject/Decorators/PostObjectFromOtherBlog.test.php rename library/PostObject/Decorators/{AbstractPostObjectDecorator.php => PostObjectWithOtherBlogIdFromSwitchedState.php} (57%) create mode 100644 library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.test.php diff --git a/library/Helper/Post.php b/library/Helper/Post.php index faa812353..555b81583 100644 --- a/library/Helper/Post.php +++ b/library/Helper/Post.php @@ -10,7 +10,10 @@ use Municipio\Helper\Term\Term; use Municipio\PostObject\Decorators\BackwardsCompatiblePostObject; use Municipio\PostObject\Decorators\IconResolvingPostObject; +use Municipio\PostObject\Decorators\PostObjectFromOtherBlog; use Municipio\PostObject\Decorators\PostObjectFromWpPost; +use Municipio\PostObject\Decorators\PostObjectWithOtherBlogIdFromSwitchedState; +use Municipio\PostObject\Decorators\PostObjectWithOtherBlogIdTest; use Municipio\PostObject\Icon\Resolvers\CachedIconResolver; use Municipio\PostObject\Icon\Resolvers\NullIconResolver; use Municipio\PostObject\Icon\Resolvers\PostIconResolver; @@ -154,12 +157,15 @@ private static function convertWpPostToPostObject(WP_Post $post, string $cacheGr $wpService = \Municipio\Helper\WpService::get(); $acfService = \Municipio\Helper\AcfService::get(); - $postObject = new PostObjectFromWpPost(new PostObject(), $post, $wpService); + $postObject = new PostObjectFromWpPost(new PostObject($wpService), $post, $wpService); + $postObject = new PostObjectWithOtherBlogIdFromSwitchedState($postObject, $wpService); $iconResolver = new TermIconResolver($postObject, $wpService, new Term($wpService, AcfService::get()), new NullIconResolver()); $iconResolver = new PostIconResolver($postObject, $acfService, $iconResolver); $iconResolver = new CachedIconResolver($postObject, $iconResolver); - $postObject = new IconResolvingPostObject($postObject, $iconResolver); + + $postObject = new IconResolvingPostObject($postObject, $iconResolver); + $postObject = new PostObjectFromOtherBlog($postObject, $wpService); $postObject = new BackwardsCompatiblePostObject($postObject, $camelCasedPost); diff --git a/library/PostObject/Decorators/BackwardsCompatiblePostObject.php b/library/PostObject/Decorators/BackwardsCompatiblePostObject.php index f12f64d26..83f1ec7db 100644 --- a/library/PostObject/Decorators/BackwardsCompatiblePostObject.php +++ b/library/PostObject/Decorators/BackwardsCompatiblePostObject.php @@ -3,6 +3,7 @@ namespace Municipio\PostObject\Decorators; use AllowDynamicProperties; +use Municipio\PostObject\Icon\IconInterface; use Municipio\PostObject\PostObjectInterface; /** @@ -11,19 +12,73 @@ * This class is used to make sure that the PostObjectInterface is backwards compatible with the old PostObject class. */ #[AllowDynamicProperties] -class BackwardsCompatiblePostObject extends AbstractPostObjectDecorator implements PostObjectInterface +class BackwardsCompatiblePostObject implements PostObjectInterface { /** * Constructor. */ - public function __construct(PostObjectInterface $postObject, object $legacyPost) + public function __construct(private PostObjectInterface $postObject, object $legacyPost) { - $this->postObject = $postObject; - foreach ($legacyPost as $key => $value) { if (!isset($this->{$key})) { $this->{$key} = $value; } } } + + /** + * @inheritDoc + */ + public function getId(): int + { + return $this->postObject->getId(); + } + + /** + * @inheritDoc + */ + public function getTitle(): string + { + return $this->postObject->getTitle(); + } + + /** + * @inheritDoc + */ + public function getPermalink(): string + { + return $this->postObject->getPermalink(); + } + + /** + * @inheritDoc + */ + public function getCommentCount(): int + { + return $this->postObject->getCommentCount(); + } + + /** + * @inheritDoc + */ + public function getPostType(): string + { + return $this->postObject->getPostType(); + } + + /** + * @inheritDoc + */ + public function getIcon(): ?IconInterface + { + return $this->postObject->getIcon(); + } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->postObject->getBlogId(); + } } diff --git a/library/PostObject/Decorators/IconResolvingPostObject.php b/library/PostObject/Decorators/IconResolvingPostObject.php index 0703b6e5a..bb265519a 100644 --- a/library/PostObject/Decorators/IconResolvingPostObject.php +++ b/library/PostObject/Decorators/IconResolvingPostObject.php @@ -9,14 +9,61 @@ /** * IconResolvingPostObject */ -class IconResolvingPostObject extends AbstractPostObjectDecorator implements PostObjectInterface +class IconResolvingPostObject implements PostObjectInterface { /** * Constructor. */ - public function __construct(PostObjectInterface $inner, private IconResolverInterface $iconResolver) + public function __construct(private PostObjectInterface $postObject, private IconResolverInterface $iconResolver) { - $this->postObject = $inner; + } + + /** + * @inheritDoc + */ + public function getId(): int + { + return $this->postObject->getId(); + } + + /** + * @inheritDoc + */ + public function getTitle(): string + { + return $this->postObject->getTitle(); + } + + /** + * @inheritDoc + */ + public function getPermalink(): string + { + return $this->postObject->getPermalink(); + } + + /** + * @inheritDoc + */ + public function getCommentCount(): int + { + return $this->postObject->getCommentCount(); + } + + /** + * @inheritDoc + */ + public function getPostType(): string + { + return $this->postObject->getPostType(); + } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->postObject->getBlogId(); } /** diff --git a/library/PostObject/Decorators/IconResolvingPostObject.test.php b/library/PostObject/Decorators/IconResolvingPostObject.test.php index 086cd76db..49f0299c7 100644 --- a/library/PostObject/Decorators/IconResolvingPostObject.test.php +++ b/library/PostObject/Decorators/IconResolvingPostObject.test.php @@ -6,8 +6,8 @@ use Municipio\PostObject\Icon\Resolvers\IconResolverInterface; use Municipio\PostObject\Icon\Resolvers\NullIconResolver; use Municipio\PostObject\PostObject; -use Municipio\PostObject\PostObjectInterface; use PHPUnit\Framework\TestCase; +use WpService\Implementations\FakeWpService; class IconResolvingPostObjectTest extends TestCase { @@ -16,7 +16,7 @@ class IconResolvingPostObjectTest extends TestCase */ public function testClassCanBeInstantiated() { - $decorator = new IconResolvingPostObject(new PostObject(), new NullIconResolver()); + $decorator = new IconResolvingPostObject(new PostObject(new FakeWpService()), new NullIconResolver()); $this->assertInstanceOf(IconResolvingPostObject::class, $decorator); } @@ -31,7 +31,7 @@ public function testGetIconCallsProvidedIconResolver() $icon->method('getIcon')->willReturn('test-icon'); $iconResolver->method('resolve')->willReturn($icon); - $postObject = new IconResolvingPostObject(new PostObject(), $iconResolver); + $postObject = new IconResolvingPostObject(new PostObject(new FakeWpService()), $iconResolver); $this->assertEquals('test-icon', $postObject->getIcon()->getIcon()); } diff --git a/library/PostObject/Decorators/PostObjectFromOtherBlog.php b/library/PostObject/Decorators/PostObjectFromOtherBlog.php new file mode 100644 index 000000000..dc937dc33 --- /dev/null +++ b/library/PostObject/Decorators/PostObjectFromOtherBlog.php @@ -0,0 +1,93 @@ +postObject->getId(); + } + + /** + * @inheritDoc + */ + public function getTitle(): string + { + return $this->postObject->getTitle(); + } + + /** + * @inheritDoc + */ + public function getPermalink(): string + { + return $this->postObject->getPermalink(); + } + + /** + * @inheritDoc + */ + public function getCommentCount(): int + { + return $this->postObject->getCommentCount(); + } + + /** + * @inheritDoc + */ + public function getPostType(): string + { + return $this->postObject->getPostType(); + } + + /** + * @inheritDoc + */ + public function getIcon(): ?IconInterface + { + if (!$this->wpService->isMultisite()) { + return $this->postObject->getIcon(); + } + + if ($this->getBlogId() === $this->wpService->getCurrentBlogId()) { + return $this->postObject->getIcon(); + } + + $this->wpService->switchToBlog($this->getBlogId()); + $icon = $this->postObject->getIcon(); + $this->wpService->restoreCurrentBlog(); + return $icon; + } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->blogId ?? $this->postObject->getBlogId(); + } +} diff --git a/library/PostObject/Decorators/PostObjectFromOtherBlog.test.php b/library/PostObject/Decorators/PostObjectFromOtherBlog.test.php new file mode 100644 index 000000000..3933b53f3 --- /dev/null +++ b/library/PostObject/Decorators/PostObjectFromOtherBlog.test.php @@ -0,0 +1,39 @@ +createStub(PostObjectInterface::class); + + $this->assertInstanceOf( + PostObjectFromOtherBlog::class, + new PostObjectFromOtherBlog($postObject, $wpService) + ); + } + + /** + * @testdox getIcon() performs a switch to the correct blog if the post is from another blog + */ + public function testGetIconSwitchesToCorrectBlog() + { + $wpService = new FakeWpService(['isMultisite' => true, 'getCurrentBlogId' => 1, 'switchToBlog' => true, 'restoreCurrentBlog' => true]); + $postObject = $this->createStub(PostObjectInterface::class); + $postObject->method('getBlogId')->willReturn(2); + $decoratedPostObject = new PostObjectFromOtherBlog($postObject, $wpService); + + $decoratedPostObject->getIcon(); + + $this->assertEquals(2, $wpService->methodCalls['switchToBlog'][0][0]); + } +} diff --git a/library/PostObject/Decorators/PostObjectFromWpPost.php b/library/PostObject/Decorators/PostObjectFromWpPost.php index cc884237f..20748bc6c 100644 --- a/library/PostObject/Decorators/PostObjectFromWpPost.php +++ b/library/PostObject/Decorators/PostObjectFromWpPost.php @@ -2,6 +2,7 @@ namespace Municipio\PostObject\Decorators; +use Municipio\PostObject\Icon\IconInterface; use WP_Post; use Municipio\PostObject\PostObjectInterface; use WpService\Contracts\GetCommentCount; @@ -10,17 +11,16 @@ /** * PostObject from WP_Post. */ -class PostObjectFromWpPost extends AbstractPostObjectDecorator implements PostObjectInterface +class PostObjectFromWpPost implements PostObjectInterface { /** * Constructor. */ public function __construct( - PostObjectInterface $inner, + private PostObjectInterface $postObject, private WP_Post $wpPost, private GetPermalink&GetCommentCount $wpService ) { - $this->postObject = $inner; } /** @@ -62,4 +62,20 @@ public function getPostType(): string { return $this->wpPost->post_type; } + + /** + * @inheritDoc + */ + public function getIcon(): ?IconInterface + { + return $this->postObject->getIcon(); + } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->postObject->getBlogId(); + } } diff --git a/library/PostObject/Decorators/PostObjectFromWpPost.test.php b/library/PostObject/Decorators/PostObjectFromWpPost.test.php index c1fe96614..de81118ef 100644 --- a/library/PostObject/Decorators/PostObjectFromWpPost.test.php +++ b/library/PostObject/Decorators/PostObjectFromWpPost.test.php @@ -17,7 +17,7 @@ public function testGetCommentCountReturnsAmountOfComments() $wpService = new FakeWpService(['getCommentCount' => ['approved' => 2]]); $wpPost = WpMockFactory::createWpPost(['ID' => 1]); - $instance = new PostObjectFromWpPost(new PostObject(), $wpPost, $wpService); + $instance = new PostObjectFromWpPost(new PostObject(new FakeWpService()), $wpPost, $wpService); $result = $instance->getCommentCount(); @@ -32,7 +32,7 @@ public function testGetPermalinkReturnsPermalink() $wpService = new FakeWpService(['getPermalink' => 'http://example.com']); $wpPost = WpMockFactory::createWpPost(['ID' => 1]); - $instance = new PostObjectFromWpPost(new PostObject(), $wpPost, $wpService); + $instance = new PostObjectFromWpPost(new PostObject(new FakeWpService()), $wpPost, $wpService); $result = $instance->getPermalink(); @@ -45,7 +45,7 @@ public function testGetPermalinkReturnsPermalink() public function testGetTitleReturnsTitle() { $wpPost = WpMockFactory::createWpPost(['post_title' => 'Title']); - $instance = new PostObjectFromWpPost(new PostObject(), $wpPost, new FakeWpService()); + $instance = new PostObjectFromWpPost(new PostObject(new FakeWpService()), $wpPost, new FakeWpService()); $this->assertEquals('Title', $instance->getTitle()); } @@ -56,7 +56,7 @@ public function testGetTitleReturnsTitle() public function testGetPostTypeReturnsPostType() { $wpPost = WpMockFactory::createWpPost(['post_type' => 'post']); - $instance = new PostObjectFromWpPost(new PostObject(), $wpPost, new FakeWpService()); + $instance = new PostObjectFromWpPost(new PostObject(new FakeWpService()), $wpPost, new FakeWpService()); $this->assertEquals('post', $instance->getPostType()); } diff --git a/library/PostObject/Decorators/AbstractPostObjectDecorator.php b/library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.php similarity index 57% rename from library/PostObject/Decorators/AbstractPostObjectDecorator.php rename to library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.php index 91dc70232..f0f0ccb80 100644 --- a/library/PostObject/Decorators/AbstractPostObjectDecorator.php +++ b/library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.php @@ -4,14 +4,27 @@ use Municipio\PostObject\Icon\IconInterface; use Municipio\PostObject\PostObjectInterface; -use Municipio\PostObject\TermIcon\TermIconInterface; +use WpService\Contracts\GetCurrentBlogId; +use WpService\Contracts\MsIsSwitched; /** - * Abstract post object decorator. + * PostObjectWithOtherBlogIdFromSwitchedState */ -abstract class AbstractPostObjectDecorator implements PostObjectInterface +class PostObjectWithOtherBlogIdFromSwitchedState implements PostObjectInterface { - protected PostObjectInterface $postObject; + private ?int $blogId = null; + + /** + * Constructor. + */ + public function __construct( + private PostObjectInterface $postObject, + private MsIsSwitched&GetCurrentBlogId $wpService + ) { + if ($this->wpService->msIsSwitched() === true) { + $this->blogId = $this->wpService->getCurrentBlogId(); + } + } /** * @inheritDoc @@ -60,4 +73,12 @@ public function getIcon(): ?IconInterface { return $this->postObject->getIcon(); } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->blogId ?? $this->postObject->getBlogId(); + } } diff --git a/library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.test.php b/library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.test.php new file mode 100644 index 000000000..8ed0f2f6c --- /dev/null +++ b/library/PostObject/Decorators/PostObjectWithOtherBlogIdFromSwitchedState.test.php @@ -0,0 +1,54 @@ + true, 'msIsSwitched' => false, 'getCurrentBlogId' => 1]); + $postObject = new PostObject($wpService); + + $this->assertInstanceOf( + PostObjectWithOtherBlogIdFromSwitchedState::class, + new PostObjectWithOtherBlogIdFromSwitchedState($postObject, $wpService) + ); + } + + /** + * @testdox returns blog id from inner post object if not switched + */ + public function testReturnsBlogIdFromInnerPostObjectIfNotSwitched() + { + $wpService = new FakeWpService(['isMultisite' => true, 'msIsSwitched' => false, 'getCurrentBlogId' => 1]); + $postObject = new PostObject($wpService); + + $result = new PostObjectWithOtherBlogIdFromSwitchedState($postObject, $wpService); + + $this->assertEquals(1, $result->getBlogId()); + } + + /** + * @testdox returns blog id from wp service if switched + */ + public function testReturnsBlogIdFromWpServiceIfSwitched() + { + $wpService = new FakeWpService(['isMultisite' => true, 'msIsSwitched' => true, 'getCurrentBlogId' => 2]); + $postObject = new PostObject($wpService); + + $result = new PostObjectWithOtherBlogIdFromSwitchedState($postObject, $wpService); + + $this->assertEquals(2, $result->getBlogId()); + } +} diff --git a/library/PostObject/Icon/Resolvers/CachedIconResolver.php b/library/PostObject/Icon/Resolvers/CachedIconResolver.php index d2678f1e3..77e22c7d0 100644 --- a/library/PostObject/Icon/Resolvers/CachedIconResolver.php +++ b/library/PostObject/Icon/Resolvers/CachedIconResolver.php @@ -30,7 +30,7 @@ public function __construct(private PostObjectInterface $postObject, private Ico */ public function resolve(): ?IconInterface { - $cacheKey = (string)$this->postObject->getId(); + $cacheKey = "{$this->postObject->getBlogId()}_{$this->postObject->getId()}"; if (array_key_exists($cacheKey, self::$cache)) { return self::$cache[$cacheKey]; diff --git a/library/PostObject/PostObject.php b/library/PostObject/PostObject.php index c68136b38..ffc9b7ece 100644 --- a/library/PostObject/PostObject.php +++ b/library/PostObject/PostObject.php @@ -4,13 +4,20 @@ use Municipio\PostObject\Icon\IconInterface; use Municipio\PostObject\PostObjectInterface; -use Municipio\PostObject\TermIcon\TermIconInterface; +use WpService\Contracts\GetCurrentBlogId; /** * PostObject */ class PostObject implements PostObjectInterface { + /** + * Constructor. + */ + public function __construct(private GetCurrentBlogId $wpService) + { + } + /** * @inheritDoc */ @@ -58,4 +65,12 @@ public function getIcon(): ?IconInterface { return null; } + + /** + * @inheritDoc + */ + public function getBlogId(): int + { + return $this->wpService->getCurrentBlogId(); + } } diff --git a/library/PostObject/PostObject.test.php b/library/PostObject/PostObject.test.php index 6bb6fa3d7..0bb1d6a2f 100644 --- a/library/PostObject/PostObject.test.php +++ b/library/PostObject/PostObject.test.php @@ -3,6 +3,8 @@ namespace Municipio\PostObject; use PHPUnit\Framework\TestCase; +use WpService\Contracts\GetCurrentBlogId; +use WpService\Implementations\FakeWpService; /** * PostObject @@ -13,7 +15,9 @@ class PostObjectTest extends TestCase protected function setUp(): void { - $this->instance = new PostObject(); + $this->instance = new PostObject(new FakeWpService([ + 'getCurrentBlogId' => 1, + ])); } /** @@ -63,4 +67,12 @@ public function testGetIconReturnsNull() { $this->assertNull($this->instance->getIcon()); } + + /** + * @testdox getBlogId() current blog id + */ + public function testGetBlogIdReturns1() + { + $this->assertEquals(1, $this->instance->getBlogId()); + } } diff --git a/library/PostObject/PostObjectInterface.php b/library/PostObject/PostObjectInterface.php index 8a554f649..3f763c1ea 100644 --- a/library/PostObject/PostObjectInterface.php +++ b/library/PostObject/PostObjectInterface.php @@ -46,4 +46,12 @@ public function getPostType(): string; * @return IconInterface|null The post object icon or null if none is found. */ public function getIcon(): ?IconInterface; + + /** + * Get the post object blog id. + * Returns the blog id of the post objects origin. + * + * @return int + */ + public function getBlogId(): int; }