<?php declare(strict_types=1);
namespace ShopStudio\Blog\Storefront\Page\BlogPost;
use ShopStudio\Blog\Content\BlogPost\BlogPostDefinition;
use ShopStudio\Blog\Content\BlogPost\BlogPostEntity;
use ShopStudio\Blog\Content\BlogPost\Exception\BlogPostNotFoundException;
use ShopStudio\Blog\Content\BlogPost\SalesChannel\Detail\AbstractBlogPostDetailRoute;
use ShopStudio\Blog\Storefront\Page\BlogPost\Comment\BlogPostCommentLoader;
use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Content\Cms\DataResolver\CmsSlotsDataResolver;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\GenericPageLoader;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* @since 1.0.0
*/
class BlogPostPageLoader
{
/**
* @since 1.0.0
*/
private GenericPageLoader $genericLoader;
/**
* @since 1.0.0
*/
private EntityRepositoryInterface $blogPostRepository;
/**
* @since 1.0.0
*/
private EventDispatcherInterface $eventDispatcher;
/**
* @since 1.0.0
*/
private SalesChannelCmsPageRepository $cmsPageRepository;
/**
* @since 1.0.0
*/
private CmsSlotsDataResolver $slotDataResolver;
/**
* @since 1.0.0
*/
private BlogPostDefinition $blogPostDefinition;
/**
* @since 2.0.0
*/
private AbstractBlogPostDetailRoute $blogPostDetailRoute;
/**
* @since 1.0.0
*/
private BlogPostCommentLoader $blogPostCommentLoader;
/**
* @since 2.0.0
*/
public function __construct(
GenericPageLoader $genericLoader,
EntityRepositoryInterface $blogPostRepository,
EventDispatcherInterface $eventDispatcher,
SalesChannelCmsPageRepository $cmsPageRepository,
CmsSlotsDataResolver $slotDataResolver,
BlogPostDefinition $blogPostDefinition,
AbstractBlogPostDetailRoute $blogPostDetailRoute,
BlogPostCommentLoader $blogPostCommentLoader
) {
$this->genericLoader = $genericLoader;
$this->blogPostRepository = $blogPostRepository;
$this->eventDispatcher = $eventDispatcher;
$this->cmsPageRepository = $cmsPageRepository;
$this->slotDataResolver = $slotDataResolver;
$this->blogPostDefinition = $blogPostDefinition;
$this->blogPostDetailRoute = $blogPostDetailRoute;
$this->blogPostCommentLoader = $blogPostCommentLoader;
}
/**
* @since 1.0.0
*
* @throws CategoryNotFoundException
* @throws InconsistentCriteriaIdsException
* @throws MissingRequestParameterException
* @throws BlogPostNotFoundException
*/
public function load(Request $request, SalesChannelContext $salesChannelContext): BlogPostPage
{
$page = $this->genericLoader->load($request, $salesChannelContext);
$page = BlogPostPage::createFrom($page);
$blogPostId = $request->attributes->get('blogPostId');
if (!$blogPostId) {
throw new MissingRequestParameterException('blogPostId', '/blogPostId');
}
$criteria = $this->buildCriteria($blogPostId);
$this->eventDispatcher->dispatch(
new BlogPostPageCriteriaEvent($blogPostId, $criteria, $salesChannelContext)
);
$blogPostDetailRouteResponse = $this->blogPostDetailRoute->load($blogPostId, $request, $salesChannelContext, $criteria);
$blogPost = $blogPostDetailRouteResponse->getBlogPost();
$page->setBlogPost($blogPost);
$schema = $blogPostDetailRouteResponse->getSchema();
$page->setSchema($schema);
$commentLoaderResults = $this->blogPostCommentLoader->load($request, $salesChannelContext);
$page->setComments($commentLoaderResults);
$cmsPage = $this->getCmsPage($salesChannelContext);
if ($cmsPage !== null) {
$this->loadSlotData($cmsPage, $salesChannelContext, $blogPost);
$page->setCmsPage($cmsPage);
}
$this->loadMetaData($page);
$this->eventDispatcher->dispatch(
new BlogPostPageLoadedEvent($page, $salesChannelContext, $request)
);
return $page;
}
/**
* @since 1.0.0
*/
private function loadMetaData(BlogPostPage $page): void
{
$blogPost = $page->getBlogPost();
$metaInformation = $page->getMetaInformation();
if ($metaInformation === null) {
$metaInformation = new MetaInformation();
}
$metaTitle = $blogPost->getTranslation('metaTitle') ?? $blogPost->getTranslation('title');
$metaInformation->setMetaTitle($metaTitle);
$metaDescription = $blogPost->getTranslation('metaDescription') ?? $blogPost->getTranslation('description');
$metaInformation->setMetaDescription((string) $metaDescription);
$keywords = $blogPost->getTranslation('keywords');
$metaInformation->setMetaKeywords((string) $keywords);
$author = $blogPost->getAuthor();
if (!empty($author)) {
$metaInformation->setAuthor($author);
}
}
/**
* @since 1.0.0
*/
private function loadSlotData(CmsPageEntity $page, SalesChannelContext $salesChannelContext, BlogPostEntity $blogPost): void
{
if (!$page->getSections()) {
return;
}
$request = new Request();
$resolverContext = new EntityResolverContext($salesChannelContext, $request, $this->blogPostDefinition, $blogPost);
foreach ($page->getSections() as $section) {
$slots = $this->slotDataResolver->resolve($section->getBlocks()->getSlots(), $resolverContext);
$section->getBlocks()->setSlots($slots);
}
}
/**
* @since 1.0.0
*/
private function getCmsPage(SalesChannelContext $context): ?CmsPageEntity
{
$pages = $this->cmsPageRepository->getPagesByType('blog_post_detail', $context);
if ($pages->count() === 0) {
return null;
}
/** @var CmsPageEntity $page */
$page = $pages->first();
return $page;
}
/**
* @since 1.0.0
*/
private function buildCriteria(string $blogPostId): Criteria
{
$criteria = (new Criteria([$blogPostId]))
->addAssociation('mainImage')
->addAssociation('mainCategory')
->addAssociation('categories')
->addAssociation('salesChannels')
->addAssociation('translations')
->addAssociation('content')
->addAssociation('content.translations')
;
$criteria
->getAssociation('content')
->addSorting(new FieldSorting('position', FieldSorting::ASCENDING))
;
return $criteria;
}
}