diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8346299..a56e80b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## Unreleased
+
+- Tax rates, customer groups and currency rates as cache entries in the local files: no select per request for them. A tax rule, rate, class or group save cleans the tax entries; a rate import cleans the currency entries.
+- A process keeps the entries it read in memory until they expire; a worker answers them without the include.
+
## 0.2.0-rc7
- Promote entries that Mage-OS stores through its compression decorator to the local files; the lifetime rule reads the packed record as the frontend answers it.
diff --git a/dev/README.md b/dev/README.md
index 31eefb3..0a097f1 100644
--- a/dev/README.md
+++ b/dev/README.md
@@ -27,6 +27,9 @@ Production installs use the default-enabled optimizations. These switches suppor
| `view_config` | Reuse of theme/area view XML as PHP data. | Yes |
| `guest_tax_factor` | Reuse of guest tax-factor calculations. | Yes |
| `placeholder_url` | Cached placeholder URLs, including theme and transport identity. | Yes |
+| `tax_rates` | Tax rates and applied rates per rate request from the cache, for requests that are not customer-specific. | Yes |
+| `customer_groups` | Customer groups by id from the cache, with their excluded websites. | Yes |
+| `currency_rates` | Currency rates from the cache; a rate import cleans them. | Yes |
These switches do not enable PHP class preload; that requires `opcache.preload` at FPM startup.
diff --git a/src/FastBoot/Plugin/Customer/GroupFromCache.php b/src/FastBoot/Plugin/Customer/GroupFromCache.php
new file mode 100644
index 0000000..854997a
--- /dev/null
+++ b/src/FastBoot/Plugin/Customer/GroupFromCache.php
@@ -0,0 +1,65 @@
+feature->on(self::SWITCH)) {
+ return $proceed($id);
+ }
+ $key = self::KEY . (int)$id;
+ $cached = $this->cache->load($key);
+ $data = is_string($cached) ? json_decode($cached, true) : null;
+ if (is_array($data)) {
+ $group = $this->groupFactory->create()
+ ->setId($data['id'])
+ ->setCode($data['code'])
+ ->setTaxClassId($data['tax_class_id'])
+ ->setTaxClassName($data['tax_class_name']);
+ if ($data['exclude_website_ids']) {
+ $group->setExtensionAttributes($this->extensionFactory->create(GroupInterface::class)->setExcludeWebsiteIds($data['exclude_website_ids']));
+ }
+
+ return $group;
+ }
+ $group = $proceed($id);
+ $this->cache->save(json_encode([
+ 'id' => $group->getId(),
+ 'code' => $group->getCode(),
+ 'tax_class_id' => $group->getTaxClassId(),
+ 'tax_class_name' => $group->getTaxClassName(),
+ 'exclude_website_ids' => $group->getExtensionAttributes()?->getExcludeWebsiteIds() ?? [],
+ ]), $key, [ConfigCache::CACHE_TAG, Tag::TAX]);
+
+ return $group;
+ }
+}
diff --git a/src/FastBoot/Plugin/Directory/CurrencyRatesFromCache.php b/src/FastBoot/Plugin/Directory/CurrencyRatesFromCache.php
new file mode 100644
index 0000000..9926fa0
--- /dev/null
+++ b/src/FastBoot/Plugin/Directory/CurrencyRatesFromCache.php
@@ -0,0 +1,63 @@
+rate('rate', $currencyFrom, $currencyTo, static fn() => $proceed($currencyFrom, $currencyTo));
+ }
+
+ public function aroundGetAnyRate(Currency $subject, callable $proceed, $currencyFrom, $currencyTo)
+ {
+ return $this->rate('any', $currencyFrom, $currencyTo, static fn() => $proceed($currencyFrom, $currencyTo));
+ }
+
+ public function afterSaveRates(Currency $subject, $result)
+ {
+ $this->cache->clean([Tag::CURRENCY]);
+
+ return $result;
+ }
+
+ private function rate(string $kind, $currencyFrom, $currencyTo, callable $compute)
+ {
+ $from = strtoupper($currencyFrom instanceof CurrencyModel ? (string)$currencyFrom->getCode() : (string)$currencyFrom);
+ $to = strtoupper($currencyTo instanceof CurrencyModel ? (string)$currencyTo->getCode() : (string)$currencyTo);
+ if ($from === $to || !$this->feature->on(self::SWITCH)) {
+ return $compute();
+ }
+ $key = self::KEY . $kind . '_' . $from . '_' . $to;
+ $cached = $this->cache->load($key);
+ $entry = is_string($cached) ? json_decode($cached, true) : null;
+ if (is_array($entry) && array_key_exists('rate', $entry)) {
+ return $entry['rate'];
+ }
+ $rate = $compute();
+ $this->cache->save(json_encode(['rate' => $rate], JSON_PRESERVE_ZERO_FRACTION), $key, [ConfigCache::CACHE_TAG, Tag::CURRENCY]);
+
+ return $rate;
+ }
+}
diff --git a/src/FastBoot/Plugin/Tax/ForgetRates.php b/src/FastBoot/Plugin/Tax/ForgetRates.php
new file mode 100644
index 0000000..b7903c2
--- /dev/null
+++ b/src/FastBoot/Plugin/Tax/ForgetRates.php
@@ -0,0 +1,33 @@
+cache->clean([Tag::TAX]);
+
+ return $result;
+ }
+
+ public function afterDelete($subject, $result)
+ {
+ $this->cache->clean([Tag::TAX]);
+
+ return $result;
+ }
+}
diff --git a/src/FastBoot/Plugin/Tax/RatesFromCache.php b/src/FastBoot/Plugin/Tax/RatesFromCache.php
new file mode 100644
index 0000000..906b819
--- /dev/null
+++ b/src/FastBoot/Plugin/Tax/RatesFromCache.php
@@ -0,0 +1,73 @@
+entry('info', $request, static fn(): array => $proceed($request));
+ }
+
+ public function aroundGetCalculationProcess(Calculation $subject, callable $proceed, $request, $rates = null): array
+ {
+ if ($rates !== null) {
+ return $proceed($request, $rates);
+ }
+
+ return $this->entry('process', $request, static fn(): array => $proceed($request));
+ }
+
+ private function entry(string $kind, $request, callable $compute): array
+ {
+ if (!$this->feature->on(self::SWITCH) || (int)$this->userContext->getUserType() === UserContextInterface::USER_TYPE_CUSTOMER) {
+ return $compute();
+ }
+ $key = self::KEY . $kind . '_' . md5(implode('|', [
+ $this->storeManager->getStore($request->getStore())->getId(),
+ implode(',', (array)$request->getProductClassId()),
+ $request->getCustomerClassId(),
+ $request->getCountryId(),
+ $request->getRegionId(),
+ $request->getPostcode(),
+ ]));
+ $cached = $this->cache->load($key);
+ if (is_string($cached)) {
+ $value = json_decode($cached, true);
+ if (is_array($value)) {
+ return $value;
+ }
+ }
+ $value = $compute();
+ $this->cache->save(json_encode($value, JSON_PRESERVE_ZERO_FRACTION), $key, [ConfigCache::CACHE_TAG, Tag::TAX]);
+
+ return $value;
+ }
+}
diff --git a/src/FastBoot/Test/Unit/Plugin/Customer/GroupFromCacheTest.php b/src/FastBoot/Test/Unit/Plugin/Customer/GroupFromCacheTest.php
new file mode 100644
index 0000000..5eafa49
--- /dev/null
+++ b/src/FastBoot/Test/Unit/Plugin/Customer/GroupFromCacheTest.php
@@ -0,0 +1,90 @@
+createStub(CacheInterface::class);
+ $cache->method('load')->willReturnCallback(fn(string $id) => $this->entries[$id] ?? false);
+ $cache->method('save')->willReturnCallback(function (string $data, string $id) {
+ $this->entries[$id] = $data;
+
+ return true;
+ });
+ $feature = $this->createStub(Feature::class);
+ $feature->method('on')->willReturn(true);
+ $groups = $this->createStub(GroupInterfaceFactory::class);
+ $groups->method('create')->willReturnCallback(fn(): GroupInterface => $this->group());
+ $extensions = $this->createStub(ExtensionAttributesFactory::class);
+ $extensions->method('create')->willReturnCallback(static fn(): GroupExtension => new GroupExtension());
+
+ return new GroupFromCache($cache, $feature, $groups, $extensions);
+ }
+
+ /** A group data object that keeps what its setters receive. */
+ private function group(): GroupInterface
+ {
+ return new class extends DataObject implements GroupInterface {
+ public function getId() { return $this->getData('id'); }
+ public function setId($id) { return $this->setData('id', $id); }
+ public function getCode() { return $this->getData('code'); }
+ public function setCode($code) { return $this->setData('code', $code); }
+ public function getTaxClassId() { return $this->getData('tax_class_id'); }
+ public function setTaxClassId($taxClassId) { return $this->setData('tax_class_id', $taxClassId); }
+ public function getTaxClassName() { return $this->getData('tax_class_name'); }
+ public function setTaxClassName($taxClassName) { return $this->setData('tax_class_name', $taxClassName); }
+ public function getExtensionAttributes() { return $this->getData('extension_attributes'); }
+ public function setExtensionAttributes(\Magento\Customer\Api\Data\GroupExtensionInterface $extensionAttributes) { return $this->setData('extension_attributes', $extensionAttributes); }
+ };
+ }
+
+ public function testAGroupWithExcludedWebsitesComesBackWholeFromTheEntry(): void
+ {
+ $plugin = $this->plugin();
+ $subject = $this->createStub(GroupRepositoryInterface::class);
+ $calls = 0;
+ $proceed = function () use (&$calls): GroupInterface {
+ $calls++;
+ $group = $this->group()->setId(3)->setCode('Wholesale')->setTaxClassId(5)->setTaxClassName('Retail Customer');
+
+ return $group->setExtensionAttributes((new GroupExtension())->setExcludeWebsiteIds([2]));
+ };
+ $plugin->aroundGetById($subject, $proceed, 3);
+ $group = $plugin->aroundGetById($subject, $proceed, 3);
+ self::assertSame(1, $calls);
+ self::assertSame(3, $group->getId());
+ self::assertSame('Wholesale', $group->getCode());
+ self::assertSame(5, $group->getTaxClassId());
+ self::assertSame('Retail Customer', $group->getTaxClassName());
+ self::assertSame([2], $group->getExtensionAttributes()->getExcludeWebsiteIds());
+ }
+
+ public function testAGroupWithoutExcludedWebsitesCarriesNoExtensionAttributes(): void
+ {
+ $plugin = $this->plugin();
+ $subject = $this->createStub(GroupRepositoryInterface::class);
+ $proceed = fn(): GroupInterface => $this->group()->setId(0)->setCode('NOT LOGGED IN')->setTaxClassId(3)->setTaxClassName('Retail Customer');
+ $plugin->aroundGetById($subject, $proceed, 0);
+ $group = $plugin->aroundGetById($subject, $proceed, 0);
+ self::assertSame('NOT LOGGED IN', $group->getCode());
+ self::assertNull($group->getExtensionAttributes());
+ }
+}
diff --git a/src/FastBoot/Test/Unit/Plugin/Directory/CurrencyRatesFromCacheTest.php b/src/FastBoot/Test/Unit/Plugin/Directory/CurrencyRatesFromCacheTest.php
new file mode 100644
index 0000000..ee82da4
--- /dev/null
+++ b/src/FastBoot/Test/Unit/Plugin/Directory/CurrencyRatesFromCacheTest.php
@@ -0,0 +1,54 @@
+cache = $this->createMock(CacheInterface::class);
+ $this->cache->method('load')->willReturnCallback(fn(string $id) => $this->entries[$id] ?? false);
+ $this->cache->method('save')->willReturnCallback(function (string $data, string $id) {
+ $this->entries[$id] = $data;
+
+ return true;
+ });
+ $feature = $this->createStub(Feature::class);
+ $feature->method('on')->willReturn(true);
+
+ return new CurrencyRatesFromCache($this->cache, $feature);
+ }
+
+ public function testARateAndAMissingRateAreEntriesAndARateImportCleansThem(): void
+ {
+ $plugin = $this->plugin();
+ $subject = $this->createStub(Currency::class);
+ $calls = 0;
+ $proceed = function () use (&$calls) {
+ $calls++;
+
+ return $calls === 1 ? '0.8500' : false;
+ };
+ self::assertSame('0.8500', $plugin->aroundGetRate($subject, $proceed, 'EUR', 'usd'));
+ self::assertSame('0.8500', $plugin->aroundGetRate($subject, $proceed, 'eur', 'USD'));
+ self::assertFalse($plugin->aroundGetAnyRate($subject, $proceed, 'EUR', 'GBP'));
+ self::assertFalse($plugin->aroundGetAnyRate($subject, $proceed, 'EUR', 'GBP'));
+ self::assertSame(2, $calls);
+ self::assertSame(1, $plugin->aroundGetRate($subject, static fn() => 1, 'EUR', 'EUR'));
+ self::assertCount(2, $this->entries);
+ $this->cache->expects(self::once())->method('clean')->with([Tag::CURRENCY]);
+ $plugin->afterSaveRates($subject, null);
+ }
+}
diff --git a/src/FastBoot/Test/Unit/Plugin/Tax/RatesFromCacheTest.php b/src/FastBoot/Test/Unit/Plugin/Tax/RatesFromCacheTest.php
new file mode 100644
index 0000000..bac77c1
--- /dev/null
+++ b/src/FastBoot/Test/Unit/Plugin/Tax/RatesFromCacheTest.php
@@ -0,0 +1,95 @@
+ */
+ private array $entries = [];
+ private array $tags = [];
+
+ private function plugin(bool $on = true, int $userType = UserContextInterface::USER_TYPE_GUEST): RatesFromCache
+ {
+ $cache = $this->createStub(CacheInterface::class);
+ $cache->method('load')->willReturnCallback(fn(string $id) => $this->entries[$id] ?? false);
+ $cache->method('save')->willReturnCallback(function (string $data, string $id, array $tags) {
+ $this->entries[$id] = $data;
+ $this->tags[$id] = $tags;
+
+ return true;
+ });
+ $feature = $this->createStub(Feature::class);
+ $feature->method('on')->willReturn($on);
+ $store = $this->createStub(StoreInterface::class);
+ $store->method('getId')->willReturn(1);
+ $stores = $this->createStub(StoreManagerInterface::class);
+ $stores->method('getStore')->willReturn($store);
+
+ $user = $this->createStub(UserContextInterface::class);
+ $user->method('getUserType')->willReturn($userType);
+
+ return new RatesFromCache($cache, $feature, $stores, $user);
+ }
+
+ private function request(string $country = 'NL', int $productClass = 2): DataObject
+ {
+ return new DataObject(['store' => 1, 'product_class_id' => $productClass, 'customer_class_id' => 3, 'country_id' => $country, 'region_id' => 0, 'postcode' => '*']);
+ }
+
+ public function testTheRateInfoOfARequestKeyIsComputedOnceAndTaggedForTaxSaves(): void
+ {
+ $plugin = $this->plugin();
+ $subject = $this->createStub(Calculation::class);
+ $calls = 0;
+ $proceed = function () use (&$calls): array {
+ $calls++;
+
+ return ['process' => [['id' => 'NL', 'percent' => 21.0, 'rates' => [['code' => 'NL', 'title' => 'BTW', 'percent' => 21.0, 'position' => 1, 'priority' => 1]]]], 'value' => 21.0];
+ };
+ $first = $plugin->aroundGetRateInfo($subject, $proceed, $this->request());
+ $second = $plugin->aroundGetRateInfo($subject, $proceed, $this->request());
+ self::assertSame(1, $calls);
+ self::assertSame($first, $second);
+ self::assertSame(21.0, $second['value']);
+ self::assertContains(Tag::TAX, $this->tags[array_key_first($this->tags)]);
+ $plugin->aroundGetRateInfo($subject, $proceed, $this->request('DE'));
+ self::assertSame(2, $calls, 'Another destination is another entry');
+ }
+
+ public function testGivenRatesAnOffSwitchAndACustomerRequestBypassTheCache(): void
+ {
+ $subject = $this->createStub(Calculation::class);
+ $calls = 0;
+ $proceed = function () use (&$calls): array {
+ $calls++;
+
+ return [];
+ };
+ $plugin = $this->plugin();
+ $plugin->aroundGetCalculationProcess($subject, $proceed, $this->request(), [['code' => 'x']]);
+ $plugin->aroundGetCalculationProcess($subject, $proceed, $this->request(), [['code' => 'x']]);
+ self::assertSame(2, $calls);
+ self::assertSame([], $this->entries);
+ $off = $this->plugin(false);
+ $off->aroundGetCalculationProcess($subject, $proceed, $this->request());
+ $off->aroundGetCalculationProcess($subject, $proceed, $this->request());
+ self::assertSame(4, $calls);
+ $customer = $this->plugin(true, UserContextInterface::USER_TYPE_CUSTOMER);
+ $customer->aroundGetRateInfo($subject, $proceed, $this->request());
+ $customer->aroundGetRateInfo($subject, $proceed, $this->request());
+ self::assertSame(6, $calls, 'A customer request keeps its own address out of the entries');
+ self::assertSame([], $this->entries);
+ }
+}
diff --git a/src/FastBoot/Test/Unit/_files/customer-group-generated.php b/src/FastBoot/Test/Unit/_files/customer-group-generated.php
new file mode 100644
index 0000000..ebdb35e
--- /dev/null
+++ b/src/FastBoot/Test/Unit/_files/customer-group-generated.php
@@ -0,0 +1,39 @@
+_get('exclude_website_ids');
+ }
+
+ public function setExcludeWebsiteIds($excludeWebsiteIds)
+ {
+ return $this->setData('exclude_website_ids', $excludeWebsiteIds);
+ }
+ }
+}
+
+if (!class_exists(GroupInterfaceFactory::class)) {
+ class GroupInterfaceFactory
+ {
+ public function create(array $data = []): GroupInterface
+ {
+ throw new \LogicException('The test stubs the factory');
+ }
+ }
+}
diff --git a/src/FastBoot/etc/di.xml b/src/FastBoot/etc/di.xml
index 1779d7e..0bf2428 100644
--- a/src/FastBoot/etc/di.xml
+++ b/src/FastBoot/etc/di.xml
@@ -7,7 +7,13 @@
- FASTBOOT_SCOPES
- FASTBOOT_CONFIG_UNCHANGED_
- FASTBOOT_WEBSITE_STORES_
- - PRODUCT_LISTING_SORT_BY_ATTRIBUTES
+ - FASTBOOT_TAX_RATE_
+ - FASTBOOT_GROUP_
+ - FASTBOOT_CURRENCY_RATE_
+
+
+ - GraphCommerce\FastBootCache\Model\Tag::TAX
+ - GraphCommerce\FastBootCache\Model\Tag::CURRENCY
@@ -53,6 +59,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- GraphCommerce\FastBoot\Console\StatusCommand
diff --git a/src/FastBoot/etc/module.xml b/src/FastBoot/etc/module.xml
index c069bc5..6ea29ec 100644
--- a/src/FastBoot/etc/module.xml
+++ b/src/FastBoot/etc/module.xml
@@ -6,6 +6,10 @@
+
+
+
+
diff --git a/src/FastBootCache/Model/Feature.php b/src/FastBootCache/Model/Feature.php
index 09dd5d2..486dc80 100644
--- a/src/FastBootCache/Model/Feature.php
+++ b/src/FastBootCache/Model/Feature.php
@@ -15,7 +15,7 @@
class Feature
{
private ?array $switches = null;
- private const CACHED = ['schema_array' => true,'cache_files' => true,'system_config_array' => true,'view_config' => true,'parsed_queries' => true,'validated_queries' => true,'scopes_cache' => true,'website_stores' => true,'deploy_config_unchanged' => true,'placeholder_url' => true,'guest_tax_factor' => true];
+ private const CACHED = ['schema_array' => true,'cache_files' => true,'system_config_array' => true,'view_config' => true,'parsed_queries' => true,'validated_queries' => true,'scopes_cache' => true,'website_stores' => true,'deploy_config_unchanged' => true,'placeholder_url' => true,'guest_tax_factor' => true,'tax_rates' => true,'customer_groups' => true,'currency_rates' => true];
public function __construct(
private readonly DeploymentConfig $deploymentConfig,
diff --git a/src/FastBootCache/Model/PhpFiles.php b/src/FastBootCache/Model/PhpFiles.php
index 7fc9d8e..1851d89 100644
--- a/src/FastBootCache/Model/PhpFiles.php
+++ b/src/FastBootCache/Model/PhpFiles.php
@@ -12,6 +12,9 @@
class PhpFiles
{
private ?string $root = null;
+
+ /** @var array the entries this process read or wrote, by index path */
+ private array $loaded = [];
public const LOADED_LIFETIME = 0; // Unknown backend lifetimes must never be extended.
public function __construct(private Filesystem $filesystem, private Version $version, private DeploymentConfig $deploymentConfig, private Release $release)
{
@@ -44,6 +47,9 @@ public function read(string $group, string $id): mixed
return null;
}
$index = $this->path($group, $id);
+ if (isset($this->loaded[$index]) && ($this->loaded[$index]['expires'] === null || $this->loaded[$index]['expires'] > microtime(true))) {
+ return $this->loaded[$index]['value'];
+ }
$record = is_file($index) ? json_decode((string)@file_get_contents($index), true) : null;
if (!is_array($record) || !isset($record['hash']) || !is_string($record['hash']) || !preg_match('/^[a-f0-9]{64}$/D', $record['hash']) || !array_key_exists('expires', $record) || ($record['expires'] !== null && !is_numeric($record['expires'])) || ($record['expires'] !== null && $record['expires'] <= microtime(true))) {
return null;
@@ -65,8 +71,21 @@ public function read(string $group, string $id): mixed
@unlink($file);
return null;
}
+ $this->remember($index, $value['value'], $record['expires'] === null ? null : (float)$record['expires']);
return $value['value'];
}
+
+ /**
+ * A worker process answers the entry from memory until it expires; the index path carries
+ * the version, so a bump leaves the memory behind.
+ */
+ private function remember(string $index, mixed $value, ?float $expires): void
+ {
+ if (count($this->loaded) >= 512) {
+ $this->loaded = [];
+ }
+ $this->loaded[$index] = ['value' => $value, 'expires' => $expires];
+ }
public function write(string $group, string $id, mixed $value, ?int $lifeTime = null, ?string $expectedVersion = null): void
{
if ($this->release->id() === null) {
@@ -126,7 +145,10 @@ public function write(string $group, string $id, mixed $value, ?int $lifeTime =
if (!is_dir(dirname($index)) && !@mkdir(dirname($index), 0700, true) && !is_dir(dirname($index))) {
return;
}
- $this->atomic($index, json_encode(['hash' => $hash,'expires' => $lifeTime === null ? null : microtime(true) + $lifeTime], JSON_THROW_ON_ERROR));
+ $expires = $lifeTime === null ? null : microtime(true) + $lifeTime;
+ if ($this->atomic($index, json_encode(['hash' => $hash,'expires' => $expires], JSON_THROW_ON_ERROR))) {
+ $this->remember($index, $value, $expires);
+ }
} finally {
flock($lock, LOCK_UN);
fclose($lock);
@@ -162,11 +184,13 @@ private static function exportable(mixed $value, int $depth = 0): bool
}
public function remove(string $group, string $id): void
{
+ unset($this->loaded[$this->path($group, $id)]);
@unlink($this->path($group, $id));
}
/** Remove obsolete indexes only. Blobs stay reusable and bounded until release cleanup/FPM restart. */
public function sweep(): void
{
+ $this->loaded = [];
$root = $this->namespaceDirectory().'/indexes';
foreach (glob($root.'/*', GLOB_ONLYDIR) ?: [] as $dir) {
$this->removeDirectory($dir);
diff --git a/src/FastBootCache/Model/Tag.php b/src/FastBootCache/Model/Tag.php
new file mode 100644
index 0000000..ebcb35a
--- /dev/null
+++ b/src/FastBootCache/Model/Tag.php
@@ -0,0 +1,14 @@
+ true], $b->read('CONFIG', 'a/b'));
self::assertSame('different', $b->read('CONFIG', 'a_b'));
$b->sweep();
- self::assertNull($a->read('CONFIG', 'a/b'));
self::assertNull($b->read('CONFIG', 'a/b'));
+ self::assertNull($this->files('a')->read('CONFIG', 'a/b'), 'A sweep comes with a version bump, so another process reads under a new path');
}
public function testPublicationGenerationAndExpiryAreRespected(): void
{
@@ -81,4 +81,19 @@ public function testAdmissionIsBoundedAndObjectsAreNeverExported(): void
$f->write('CONFIG', 'object', new \stdClass());
self::assertNull($f->read('CONFIG', 'object'));
}
+
+ public function testAProcessAnswersAnEntryFromMemoryUntilItExpiresOrIsRemoved(): void
+ {
+ $files = $this->files('v1');
+ $files->write('G', 'kept', ['a' => 1]);
+ $files->write('G', 'brief', ['b' => 2], 1);
+ $this->remove($this->var.'/fastboot');
+ self::assertSame(['a' => 1], $files->read('G', 'kept'), 'The memory of this process answers after the files are gone');
+ self::assertSame(['b' => 2], $files->read('G', 'brief'));
+ usleep(1100000);
+ self::assertNull($files->read('G', 'brief'), 'An expired entry leaves the memory');
+ $files->remove('G', 'kept');
+ self::assertNull($files->read('G', 'kept'));
+ self::assertNull($this->files('v1')->read('G', 'kept'), 'Another process reads the files');
+ }
}
diff --git a/src/FastBootGraphQl/Plugin/CacheId/GuestTaxFactor.php b/src/FastBootGraphQl/Plugin/CacheId/GuestTaxFactor.php
index ec216b2..053ce62 100644
--- a/src/FastBootGraphQl/Plugin/CacheId/GuestTaxFactor.php
+++ b/src/FastBootGraphQl/Plugin/CacheId/GuestTaxFactor.php
@@ -4,6 +4,7 @@
namespace GraphCommerce\FastBootGraphQl\Plugin\CacheId;
use GraphCommerce\FastBootCache\Model\Feature;
+use GraphCommerce\FastBootCache\Model\Tag;
use Magento\CustomerGraphQl\CacheIdFactorProviders\CustomerTaxRateProvider;
use Magento\Framework\App\Cache\Type\Config as ConfigCache;
use Magento\Framework\App\CacheInterface;
@@ -21,7 +22,7 @@ class GuestTaxFactor
{
private const SWITCH = 'guest_tax_factor';
- public const TAG = 'FASTBOOT_TAX';
+ public const TAG = Tag::TAX;
private const KEY = 'FASTBOOT_TAX_FACTOR_';
diff --git a/src/FastBootGraphQl/Plugin/Tax/ForgetTaxFactors.php b/src/FastBootGraphQl/Plugin/Tax/ForgetTaxFactors.php
deleted file mode 100644
index 61a7f8c..0000000
--- a/src/FastBootGraphQl/Plugin/Tax/ForgetTaxFactors.php
+++ /dev/null
@@ -1,33 +0,0 @@
-cache->clean([GuestTaxFactor::TAG]);
-
- return $result;
- }
-
- public function afterDelete($subject, $result)
- {
- $this->cache->clean([GuestTaxFactor::TAG]);
-
- return $result;
- }
-}
diff --git a/src/FastBootGraphQl/etc/di.xml b/src/FastBootGraphQl/etc/di.xml
index d5f092f..b81f447 100644
--- a/src/FastBootGraphQl/etc/di.xml
+++ b/src/FastBootGraphQl/etc/di.xml
@@ -40,18 +40,6 @@
-
-
-
-
-
-
-
-
-
-
-
-