mirror of
https://github.com/jbcr/core.git
synced 2026-03-27 10:22:18 +01:00
@@ -9,9 +9,13 @@ secret: '%env(APP_SECRET)%'
|
||||
|
||||
# Set the caching configuration for various areas of Bolt.
|
||||
# The expires_after is counted in seconds.
|
||||
caching:
|
||||
related_options: true
|
||||
expires_after: 3600
|
||||
caching:
|
||||
related_options: 1800
|
||||
canonical: 10
|
||||
selectoptions: 1800
|
||||
content_array: 1800
|
||||
frontend_menu: 3600
|
||||
backend_menu: 1800
|
||||
|
||||
# The theme to use.
|
||||
#
|
||||
|
||||
@@ -93,6 +93,15 @@ services:
|
||||
Bolt\Cache\RelatedOptionsUtilityCacher:
|
||||
decorates: Bolt\Utils\RelatedOptionsUtility
|
||||
|
||||
Bolt\Cache\CanonicalCacher:
|
||||
decorates: Bolt\Canonical
|
||||
|
||||
Bolt\Cache\SelectOptionsCacher:
|
||||
decorates: Bolt\Twig\FieldExtension
|
||||
|
||||
Bolt\Cache\ContentToArrayCacher:
|
||||
decorates: Bolt\Twig\JsonExtension
|
||||
|
||||
Bolt\Menu\BackendMenuBuilderInterface: '@Bolt\Menu\BackendMenu'
|
||||
|
||||
Bolt\Menu\FrontendMenuBuilder: ~
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Bolt\Cache;
|
||||
interface CachingInterface
|
||||
{
|
||||
public function getCacheKey(): string;
|
||||
public function setCacheKey(string $key): void;
|
||||
|
||||
public function setCacheKey(array $tokens): void;
|
||||
|
||||
public function execute(callable $fn, array $params = []);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Bolt\Cache;
|
||||
|
||||
use Bolt\Configuration\Config;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
|
||||
@@ -11,8 +12,14 @@ trait CachingTrait
|
||||
/** @var TagAwareCacheInterface */
|
||||
private $cache;
|
||||
|
||||
/** @var Stopwatch */
|
||||
private $stopwatch;
|
||||
|
||||
/** @var string */
|
||||
private $cacheKey;
|
||||
private $cacheKey = '';
|
||||
|
||||
/** @var array */
|
||||
private $cacheTags = [];
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
@@ -20,9 +27,10 @@ trait CachingTrait
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function setCache(TagAwareCacheInterface $cache): void
|
||||
public function setCache(TagAwareCacheInterface $cache, Stopwatch $stopwatch): void
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->stopwatch = $stopwatch;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,9 +41,9 @@ trait CachingTrait
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function setCacheKey(string $key): void
|
||||
public function setCacheKey(array $tokens): void
|
||||
{
|
||||
$this->cacheKey = $key;
|
||||
$this->cacheKey = self::CACHE_CONFIG_KEY . '_' . md5(implode('', $tokens));
|
||||
}
|
||||
|
||||
public function getCacheKey(): string
|
||||
@@ -43,26 +51,47 @@ trait CachingTrait
|
||||
return $this->cacheKey ?? '';
|
||||
}
|
||||
|
||||
public function setCacheTags(array $tags): void
|
||||
{
|
||||
$this->cacheTags = $tags;
|
||||
}
|
||||
|
||||
public function getCacheTags(): array
|
||||
{
|
||||
return $this->cacheTags;
|
||||
}
|
||||
|
||||
public function execute(callable $fn, array $params = [])
|
||||
{
|
||||
$key = $this->getCacheKey();
|
||||
|
||||
$this->stopwatch->start('bolt.cache.' . $key);
|
||||
|
||||
if ($this->isCachingEnabled()) {
|
||||
return $this->cache->get($this->getCacheKey(), function(ItemInterface $item) use ($fn, $params) {
|
||||
$results = $this->cache->get($key, function (ItemInterface $item) use ($fn, $params) {
|
||||
$item->expiresAfter($this->getExpiresAfter());
|
||||
$item->tag($this->getCacheTags());
|
||||
|
||||
return call_user_func_array($fn, $params);
|
||||
});
|
||||
} else {
|
||||
$results = call_user_func_array($fn, $params);
|
||||
}
|
||||
|
||||
return call_user_func_array($fn, $params);
|
||||
$this->stopwatch->stop('bolt.cache.' . $key);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function isCachingEnabled(): bool
|
||||
{
|
||||
return $this->config->get('general/caching/' . self::CACHE_CONFIG_KEY, true);
|
||||
$configKey = $this->config->get('general/caching/' . self::CACHE_CONFIG_KEY);
|
||||
|
||||
return $configKey > 0;
|
||||
}
|
||||
|
||||
private function getExpiresAfter(): int
|
||||
{
|
||||
return $this->config->get('general/caching/expires_after', 3600);
|
||||
return (int) $this->config->get('general/caching/' . self::CACHE_CONFIG_KEY, 3600);
|
||||
}
|
||||
}
|
||||
|
||||
19
src/Cache/CanonicalCacher.php
Normal file
19
src/Cache/CanonicalCacher.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Cache;
|
||||
|
||||
use Bolt\Canonical;
|
||||
|
||||
class CanonicalCacher extends Canonical implements CachingInterface
|
||||
{
|
||||
use CachingTrait;
|
||||
|
||||
public const CACHE_CONFIG_KEY = 'canonical';
|
||||
|
||||
public function generateLink(?string $route, ?array $params, $canonical = false): ?string
|
||||
{
|
||||
$this->setCacheKey([$route, $canonical] + $params);
|
||||
|
||||
return $this->execute([parent::class, __FUNCTION__], [$route, $params, $canonical]);
|
||||
}
|
||||
}
|
||||
21
src/Cache/ContentToArrayCacher.php
Normal file
21
src/Cache/ContentToArrayCacher.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Cache;
|
||||
|
||||
use Bolt\Entity\Content;
|
||||
use Bolt\Twig\JsonExtension;
|
||||
|
||||
class ContentToArrayCacher extends JsonExtension implements CachingInterface
|
||||
{
|
||||
use CachingTrait;
|
||||
|
||||
public const CACHE_CONFIG_KEY = 'content_array';
|
||||
|
||||
protected function contentToArray(Content $content, string $locale = ''): array
|
||||
{
|
||||
$this->setCacheKey([$content->getCacheKey($locale)]);
|
||||
$this->setCacheTags([$content->getCacheKey()]);
|
||||
|
||||
return $this->execute([parent::class, __FUNCTION__], [$content, $locale]);
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,13 @@ use Bolt\Utils\RelatedOptionsUtility;
|
||||
|
||||
class RelatedOptionsUtilityCacher extends RelatedOptionsUtility implements CachingInterface
|
||||
{
|
||||
public const CACHE_CONFIG_KEY = 'related_options';
|
||||
|
||||
use CachingTrait;
|
||||
|
||||
public const CACHE_CONFIG_KEY = 'related_options';
|
||||
|
||||
public function fetchRelatedOptions(string $contentTypeSlug, string $order, string $format, bool $required, int $maxAmount): array
|
||||
{
|
||||
$this->setCacheKey('relatedOptions_' . md5($contentTypeSlug . $order . $format . (string) $required . $maxAmount));
|
||||
$this->setCacheKey([$contentTypeSlug, $order, $format, (string) $required, $maxAmount]);
|
||||
|
||||
return $this->execute([parent::class, __FUNCTION__], [$contentTypeSlug, $order, $format, $required, $maxAmount]);
|
||||
}
|
||||
|
||||
21
src/Cache/SelectOptionsCacher.php
Normal file
21
src/Cache/SelectOptionsCacher.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Cache;
|
||||
|
||||
use Bolt\Entity\Field;
|
||||
use Bolt\Twig\FieldExtension;
|
||||
|
||||
class SelectOptionsCacher extends FieldExtension implements CachingInterface
|
||||
{
|
||||
use CachingTrait;
|
||||
|
||||
public const CACHE_CONFIG_KEY = 'selectoptions';
|
||||
|
||||
public function selectOptionsHelper(string $contentTypeSlug, array $params, Field $field, string $format): array
|
||||
{
|
||||
$this->setCacheKey([$contentTypeSlug, $format] + $params);
|
||||
$this->setCacheTags([$contentTypeSlug]);
|
||||
|
||||
return $this->execute([parent::class, __FUNCTION__], [$contentTypeSlug, $params, $field, $format]);
|
||||
}
|
||||
}
|
||||
@@ -173,6 +173,9 @@ class Canonical
|
||||
$this->path = $this->generateLink($route, $params, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorated by `\Bolt\Utils\CanonicalCacher`
|
||||
*/
|
||||
public function generateLink(?string $route, ?array $params, $canonical = false): ?string
|
||||
{
|
||||
$removeDefaultLocaleOnCanonical = $this->config->get('general/localization/remove_default_locale_on_canonical', true);
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bolt\Menu;
|
||||
|
||||
use Bolt\Configuration\Config;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
@@ -24,12 +25,16 @@ final class BackendMenu implements BackendMenuBuilderInterface
|
||||
/** @var Stopwatch */
|
||||
private $stopwatch;
|
||||
|
||||
public function __construct(BackendMenuBuilder $menuBuilder, TagAwareCacheInterface $cache, RequestStack $requestStack, Stopwatch $stopwatch)
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(BackendMenuBuilder $menuBuilder, TagAwareCacheInterface $cache, RequestStack $requestStack, Stopwatch $stopwatch, Config $config)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->menuBuilder = $menuBuilder;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function buildAdminMenu(): array
|
||||
@@ -40,6 +45,7 @@ final class BackendMenu implements BackendMenuBuilderInterface
|
||||
$cacheKey = 'bolt.backendMenu_' . $locale;
|
||||
|
||||
$menu = $this->cache->get($cacheKey, function (ItemInterface $item) {
|
||||
$item->expiresAfter($this->config->get('general/caching/backend_menu'));
|
||||
$item->tag('backendmenu');
|
||||
|
||||
return $this->menuBuilder->buildAdminMenu();
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bolt\Menu;
|
||||
|
||||
use Bolt\Configuration\Config;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
@@ -26,12 +27,16 @@ final class FrontendMenu implements FrontendMenuBuilderInterface
|
||||
/** @var Stopwatch */
|
||||
private $stopwatch;
|
||||
|
||||
public function __construct(FrontendMenuBuilder $menuBuilder, TagAwareCacheInterface $cache, RequestStack $requestStack, Stopwatch $stopwatch)
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(FrontendMenuBuilder $menuBuilder, TagAwareCacheInterface $cache, RequestStack $requestStack, Stopwatch $stopwatch, Config $config)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->menuBuilder = $menuBuilder;
|
||||
$this->request = $requestStack->getCurrentRequest();
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function buildMenu(Environment $twig, ?string $name = null): array
|
||||
@@ -41,6 +46,7 @@ final class FrontendMenu implements FrontendMenuBuilderInterface
|
||||
$key = 'bolt.frontendMenu_' . ($name ?: 'main') . '_' . $this->request->getLocale();
|
||||
|
||||
$menu = $this->cache->get($key, function (ItemInterface $item) use ($name, $twig) {
|
||||
$item->expiresAfter($this->config->get('general/caching/frontend_menu'));
|
||||
$item->tag('frontendmenu');
|
||||
|
||||
return $this->menuBuilder->buildMenu($twig, $name);
|
||||
|
||||
@@ -16,9 +16,6 @@ use Bolt\Storage\Query;
|
||||
use Bolt\Utils\ContentHelper;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
use Twig\Environment;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
@@ -42,28 +39,19 @@ class FieldExtension extends AbstractExtension
|
||||
/** @var Query */
|
||||
private $query;
|
||||
|
||||
/** @var Stopwatch */
|
||||
private $stopwatch;
|
||||
|
||||
/** @var TagAwareCacheInterface */
|
||||
private $cache;
|
||||
|
||||
public function __construct(
|
||||
Notifications $notifications,
|
||||
ContentRepository $contentRepository,
|
||||
Config $config,
|
||||
ContentHelper $contentHelper,
|
||||
Query $query,
|
||||
Stopwatch $stopwatch,
|
||||
TagAwareCacheInterface $cache)
|
||||
Query $query)
|
||||
{
|
||||
$this->notifications = $notifications;
|
||||
$this->contentRepository = $contentRepository;
|
||||
$this->config = $config;
|
||||
$this->contentHelper = $contentHelper;
|
||||
$this->query = $query;
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,39 +276,30 @@ class FieldExtension extends AbstractExtension
|
||||
'order' => $order,
|
||||
];
|
||||
|
||||
$options = $this->selectOptionsContentTypeCache($contentTypeSlug, $params, $field, $format);
|
||||
$options = $this->selectOptionsHelper($contentTypeSlug, $params, $field, $format);
|
||||
|
||||
return new Collection($options);
|
||||
}
|
||||
|
||||
private function selectOptionsContentTypeCache(string $contentTypeSlug, array $params, Field $field, string $format)
|
||||
/**
|
||||
* Decorated by `\Bolt\Cache\SelectOptionsCacher`
|
||||
*/
|
||||
public function selectOptionsHelper(string $contentTypeSlug, array $params, Field $field, string $format): array
|
||||
{
|
||||
$cacheKey = 'selectOptions_' . md5($contentTypeSlug . implode('-', $params));
|
||||
/** @var Content[] $records */
|
||||
$records = iterator_to_array($this->query->getContent($contentTypeSlug, $params)->getCurrentPageResults());
|
||||
|
||||
$this->stopwatch->start('selectOptions');
|
||||
$options = [];
|
||||
|
||||
$options = $this->cache->get($cacheKey, function (ItemInterface $item) use ($contentTypeSlug, $params, $field, $format) {
|
||||
$item->tag($contentTypeSlug);
|
||||
|
||||
/** @var Content[] $records */
|
||||
$records = iterator_to_array($this->query->getContent($contentTypeSlug, $params)->getCurrentPageResults());
|
||||
|
||||
$options = [];
|
||||
|
||||
foreach ($records as $record) {
|
||||
if ($field->getDefinition()->get('mode') === 'format') {
|
||||
$formattedKey = $this->contentHelper->get($record, $field->getDefinition()->get('format'));
|
||||
}
|
||||
$options[] = [
|
||||
'key' => $formattedKey ?? $record->getId(),
|
||||
'value' => $this->contentHelper->get($record, $format),
|
||||
];
|
||||
foreach ($records as $record) {
|
||||
if ($field->getDefinition()->get('mode') === 'format') {
|
||||
$formattedKey = $this->contentHelper->get($record, $field->getDefinition()->get('format'));
|
||||
}
|
||||
|
||||
return $options;
|
||||
});
|
||||
|
||||
$this->stopwatch->stop('selectOptions');
|
||||
$options[] = [
|
||||
'key' => $formattedKey ?? $record->getId(),
|
||||
'value' => $this->contentHelper->get($record, $format),
|
||||
];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ use Bolt\Entity\Content;
|
||||
use Bolt\Entity\Field;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigTest;
|
||||
@@ -30,14 +28,10 @@ class JsonExtension extends AbstractExtension
|
||||
/** @var Stopwatch */
|
||||
private $stopwatch;
|
||||
|
||||
/** @var TagAwareCacheInterface */
|
||||
private $cache;
|
||||
|
||||
public function __construct(NormalizerInterface $normalizer, Stopwatch $stopwatch, TagAwareCacheInterface $cache)
|
||||
public function __construct(NormalizerInterface $normalizer, Stopwatch $stopwatch)
|
||||
{
|
||||
$this->normalizer = $normalizer;
|
||||
$this->stopwatch = $stopwatch;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,24 +89,10 @@ class JsonExtension extends AbstractExtension
|
||||
}, $normalizedRecords);
|
||||
}
|
||||
|
||||
private function contentToArray(Content $content, string $locale = ''): array
|
||||
{
|
||||
$cacheKey = 'bolt.contentToArray_' . $content->getCacheKey($locale);
|
||||
|
||||
$this->stopwatch->start($cacheKey);
|
||||
|
||||
$result = $this->cache->get($cacheKey, function (ItemInterface $item) use ($content, $locale) {
|
||||
$item->tag($content->getCacheKey());
|
||||
|
||||
return $this->contentToArrayCacheHelper($content, $locale);
|
||||
});
|
||||
|
||||
$this->stopwatch->stop($cacheKey);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function contentToArrayCacheHelper(Content $content, string $locale = ''): array
|
||||
/**
|
||||
* Decorated by `Bolt\Utils\ContentToArrayCacher`
|
||||
*/
|
||||
protected function contentToArray(Content $content, string $locale = ''): array
|
||||
{
|
||||
$group = [self::SERIALIZE_GROUP];
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ use Bolt\Repository\RelationRepository;
|
||||
use Bolt\Storage\Query;
|
||||
use Bolt\Utils\ContentHelper;
|
||||
use Bolt\Utils\RelatedOptionsUtility;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
@@ -35,9 +33,6 @@ class RelatedExtension extends AbstractExtension
|
||||
/** @var Notifications */
|
||||
private $notifications;
|
||||
|
||||
/** @var TagAwareCacheInterface */
|
||||
private $cache;
|
||||
|
||||
/** @var RelatedOptionsUtility */
|
||||
private $optionsUtility;
|
||||
|
||||
@@ -47,7 +42,6 @@ class RelatedExtension extends AbstractExtension
|
||||
Query $query,
|
||||
ContentHelper $contentHelper,
|
||||
Notifications $notifications,
|
||||
TagAwareCacheInterface $cache,
|
||||
RelatedOptionsUtility $optionsUtility)
|
||||
{
|
||||
$this->relationRepository = $relationRepository;
|
||||
@@ -55,7 +49,6 @@ class RelatedExtension extends AbstractExtension
|
||||
$this->query = $query;
|
||||
$this->contentHelper = $contentHelper;
|
||||
$this->notifications = $notifications;
|
||||
$this->cache = $cache;
|
||||
$this->optionsUtility = $optionsUtility;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@ namespace Bolt\Utils;
|
||||
use Bolt\Entity\Content;
|
||||
use Bolt\Storage\Query;
|
||||
|
||||
/**
|
||||
* Utility class to get the 'Related Records' as options to show as a pull-down in the Editor.
|
||||
*
|
||||
* Decorated by `Bolt\Cache\RelatedOptionsUtilityCacher`
|
||||
*/
|
||||
class RelatedOptionsUtility
|
||||
{
|
||||
/** @var Query */
|
||||
@@ -19,6 +24,9 @@ class RelatedOptionsUtility
|
||||
$this->contentHelper = $contentHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorated by `Bolt\Cache\RelatedOptionsUtilityCacher`
|
||||
*/
|
||||
public function fetchRelatedOptions(string $contentTypeSlug, string $order, string $format, bool $required, int $maxAmount): array
|
||||
{
|
||||
$pager = $this->query->getContent($contentTypeSlug, ['order' => $order])
|
||||
|
||||
Reference in New Issue
Block a user