<?php
declare(strict_types=1);
namespace H1web\Blog\Provider;
use Doctrine\DBAL\Connection;
use H1web\Blog\Blog\BlogCollection;
use H1web\Blog\Blog\BlogEntity;
use H1web\Blog\Blog\SalesChannel\BlogAvailableFilter;
use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
use Shopware\Core\Content\Sitemap\Provider\AbstractUrlProvider;
use Shopware\Core\Content\Sitemap\Struct\Url;
use Shopware\Core\Content\Sitemap\Struct\UrlResult;
use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\FetchModeHelper;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
class BlogProvider extends AbstractUrlProvider
{
public const CHANGE_FREQ = 'monthly';
private EntityRepositoryInterface $blogRepository;
private SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler;
private Connection $connection;
private RouterInterface $router;
public function __construct(
EntityRepositoryInterface $blogRepository,
SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
RouterInterface $router,
Connection $connection
) {
$this->blogRepository = $blogRepository;
$this->seoUrlPlaceholderHandler = $seoUrlPlaceholderHandler;
$this->router = $router;
$this->connection = $connection;
}
public function getName(): string
{
return 'blog';
}
public function getUrls(SalesChannelContext $context, int $limit, ?int $offset = null): UrlResult
{
$blogs = $this->getBlogposts($context, $limit, $offset);
if (empty($blogs)) {
return new UrlResult([], null);
}
$seoUrls = $this->getSeoUrls($blogs->getIds(), 'frontend.h1webblog.blog', $context, $this->connection);
$seoUrls = FetchModeHelper::groupUnique($seoUrls);
$tagUrls = [];
$urls = [];
$url = new Url();
/** @var BlogEntity $blog */
foreach ($blogs as $blog) {
/** @var \DateTimeInterface $lastmod */
$lastmod = $blog->getUpdatedAt() ?: $blog->getCreatedAt();
$newUrl = clone $url;
if (isset($seoUrls[$blog->getId()])) {
$newUrl->setLoc($seoUrls[$blog->getId()]['seo_path_info']);
} else {
$newUrl->setLoc($this->router->generate('frontend.h1webblog.blog', ['id' => $blog->getId()], UrlGeneratorInterface::ABSOLUTE_PATH));
}
$newUrl->setLastmod($lastmod);
$newUrl->setChangefreq(self::CHANGE_FREQ);
$newUrl->setResource(BlogEntity::class);
$newUrl->setIdentifier($blog->getId());
$newUrl->setPriority(0.2);
$urls[] = $newUrl;
if ($blog->getTags() === null) {
continue;
}
$tagSeoUrls = $this->getSeoUrls($blog->getTags()->getIds(), 'frontend.h1webblog.tag_overview', $context, $this->connection);
$tagSeoUrls = FetchModeHelper::groupUnique($tagSeoUrls);
foreach ($blog->getTags() as $tag) {
if (array_key_exists($tag->getId(), $tagUrls)) {
continue;
}
$tagUrl = new Url();
$tagUrl->setLoc($tagSeoUrls[$tag->getId()]['seo_path_info']);
$tagUrl->setLastmod(new \DateTime());
$tagUrl->setChangefreq(self::CHANGE_FREQ);
$tagUrl->setResource('tag');
$tagUrl->setIdentifier($tag->getId());
$tagUrl->setPriority(0.2);
$tagUrls[$tag->getId()] = $tagUrl;
}
}
if (\count($urls) < $limit) { // last run
$nextOffset = null;
} elseif ($offset === null) { // first run
$nextOffset = $limit;
} else { // 1+n run
$nextOffset = $offset + $limit;
}
$urls = array_merge($urls, array_values($tagUrls));
return new UrlResult($urls, $nextOffset);
}
private function getBlogposts(SalesChannelContext $salesChannelContext, int $limit, ?int $offset): BlogCollection
{
$blogCriteria = new Criteria();
$blogCriteria->setLimit($limit);
$blogCriteria->addFilter(new BlogAvailableFilter($salesChannelContext->getSalesChannelId()))
->addFilter(new EqualsFilter('isActive', 1))
->addAssociation('visibilities')->addAssociation('tags');
if ($offset !== null) {
$blogCriteria->setOffset($offset);
}
return $this->blogRepository->search($blogCriteria, $salesChannelContext->getContext())->getEntities();
}
public function getDecorated(): AbstractUrlProvider
{
throw new DecorationPatternException(self::class);
}
}