<?php declare(strict_types=1);
namespace NetzpBlog6\Controller\StoreApi\BlogListing;
use OpenApi\Annotations as OA;
use Shopware\Core\Framework\Routing\Annotation\Entity;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Symfony\Component\Routing\Annotation\Route;
use Psr\Log\LoggerInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Framework\Adapter\Cache\AbstractCacheTracer;
use Shopware\Core\Framework\Adapter\Cache\CacheCompressor;
use Shopware\Core\Framework\DataAbstractionLayer\Cache\EntityCacheKeyGenerator;
use Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer\JsonFieldSerializer;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
/**
* @RouteScope(scopes={"store-api"})
*/
class CachedBlogListingRoute extends AbstractBlogListingRoute
{
private AbstractBlogListingRoute $decorated;
private TagAwareAdapterInterface $cache;
private EntityCacheKeyGenerator $generator;
private AbstractCacheTracer $tracer;
private array $states;
private LoggerInterface $logger;
public function __construct(
AbstractBlogListingRoute $decorated,
TagAwareAdapterInterface $cache,
EntityCacheKeyGenerator $generator,
AbstractCacheTracer $tracer,
LoggerInterface $logger
) {
$this->decorated = $decorated;
$this->cache = $cache;
$this->generator = $generator;
$this->tracer = $tracer;
$this->states = [];
$this->logger = $logger;
}
public function getDecorated(): AbstractBlogListingRoute
{
return $this->decorated;
}
/**
* @Entity("s_plugin_netzp_blog")
* @OA\Post(
* path="/bloglisting",
* summary="This route can be used to load a blog listing",
* operationId="readNetzpBlogListing",
* tags={"Store API", "NetzpBlog"},
* @OA\Parameter(name="Api-Basic-Parameters"),
* @OA\Response(
* response="200",
* description="",
* @OA\JsonContent(type="object",
* @OA\Property(
* property="total",
* type="integer",
* description="Total amount"
* ),
* @OA\Property(
* property="aggregations",
* type="object",
* description="aggregation result"
* )
* )
* )
* )
* @Route("/store-api/bloglisting/{navigationId?}", name="store-api.s_plugin_netzp_blog_listing.load", methods={"GET", "POST"})
*/
public function load($navigationId, Criteria $criteria, SalesChannelContext $context,
?string $categoryId, ?string $authorId, ?array $tags, ?string $sortOrder): BlogListingRouteResponse
{
// The context is provided with a state where the route cannot be cached
if ($context->hasState(...$this->states)) {
return $this->getDecorated()->load($navigationId, $criteria, $context, $categoryId, $authorId, $tags, $sortOrder);
}
// Fetch item from the cache pool
$item = $this->cache->getItem(
$this->generateKey($navigationId, $context, $criteria)
);
try {
if ($item->isHit() && $item->get()) {
// Use cache compressor to uncompress the cache value
return CacheCompressor::uncompress($item);
}
} catch (\Throwable $e) {
// Something went wrong when uncompress the cache item - we log the error and continue to overwrite the invalid cache item
$this->logger->error($e->getMessage());
}
$name = self::buildName($navigationId);
// start tracing of nested cache tags and system config keys
$response = $this->tracer->trace($name, function () use ($navigationId, $criteria, $context, $categoryId, $authorId, $tags, $sortOrder) {
return $this->getDecorated()->load($navigationId, $criteria, $context, $categoryId, $authorId, $tags, $sortOrder);
});
// compress cache content to reduce cache size
$item = CacheCompressor::compress($item, $response);
$item->tag(array_merge(
// get traced tags and configs
$this->tracer->get(self::buildName($navigationId)),
[self::buildName($navigationId), self::buildName('')]
));
$this->cache->save($item);
return $response;
}
public static function buildName($navigationId): string
{
return 'blog-listing-route-' . $navigationId;
}
private function generateKey($navigationId, SalesChannelContext $context, Criteria $criteria): string
{
$parts = [
self::buildName($navigationId),
// generate a hash for the route criteria
$this->generator->getCriteriaHash($criteria),
// generate a hash for the current context
$this->generator->getSalesChannelContextHash($context),
];
return md5(JsonFieldSerializer::encodeJson($parts));
}
}