From c9fd7dce358b43bb9b66b621cc67970773215bdf Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sat, 5 Jul 2025 20:10:58 +0200 Subject: [PATCH 1/3] Add support for NamespacedPoolInterface --- composer.json | 2 +- src/Tracing/Cache/TraceableCacheAdapterForV3.php | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a68c320a..2ffde8ca 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "guzzlehttp/psr7": "^2.1.1", "jean85/pretty-package-versions": "^1.5||^2.0", "sentry/sentry": "^4.14.1", - "symfony/cache-contracts": "^1.1||^2.4||^3.0", + "symfony/cache-contracts": "^1.1||^2.4||^3.6", "symfony/config": "^4.4.20||^5.0.11||^6.0||^7.0", "symfony/console": "^4.4.20||^5.0.11||^6.0||^7.0", "symfony/dependency-injection": "^4.4.20||^5.0.11||^6.0||^7.0", diff --git a/src/Tracing/Cache/TraceableCacheAdapterForV3.php b/src/Tracing/Cache/TraceableCacheAdapterForV3.php index ef276620..dc1ea613 100644 --- a/src/Tracing/Cache/TraceableCacheAdapterForV3.php +++ b/src/Tracing/Cache/TraceableCacheAdapterForV3.php @@ -9,6 +9,7 @@ use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\NamespacedPoolInterface; /** * This implementation of a cache adapter supports the distributed tracing @@ -16,7 +17,7 @@ * * @internal */ -final class TraceableCacheAdapterForV3 implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface +final class TraceableCacheAdapterForV3 implements AdapterInterface, NamespacedPoolInterface, CacheInterface, PruneableInterface, ResettableInterface { /** * @phpstan-use TraceableCacheAdapterTrait @@ -48,4 +49,16 @@ public function get(string $key, callable $callback, ?float $beta = null, ?array return $this->decoratedAdapter->get($key, $callback, $beta, $metadata); }, $key); } + + public function withSubNamespace(string $namespace): static + { + if (!$this->decoratedAdapter instanceof NamespacedPoolInterface) { + throw new \BadMethodCallException(\sprintf('The %s::withSubNamespace() method is not supported because the decorated adapter does not implement the "%s" interface.', self::class, NamespacedPoolInterface::class)); + } + + $clone = clone $this; + $clone->decoratedAdapter = $this->decoratedAdapter->withSubNamespace($namespace); + + return $clone; + } } From 760895e3b959bcbe0fd9867e4289f641918bb06c Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 7 Jul 2025 13:52:29 +0200 Subject: [PATCH 2/3] Rework --- composer.json | 2 +- .../Cache/TraceableCacheAdapterForV3.php | 15 +---- ...raceableCacheAdapterForV3WithNamespace.php | 64 +++++++++++++++++++ src/aliases.php | 8 ++- 4 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 src/Tracing/Cache/TraceableCacheAdapterForV3WithNamespace.php diff --git a/composer.json b/composer.json index 2ffde8ca..a68c320a 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "guzzlehttp/psr7": "^2.1.1", "jean85/pretty-package-versions": "^1.5||^2.0", "sentry/sentry": "^4.14.1", - "symfony/cache-contracts": "^1.1||^2.4||^3.6", + "symfony/cache-contracts": "^1.1||^2.4||^3.0", "symfony/config": "^4.4.20||^5.0.11||^6.0||^7.0", "symfony/console": "^4.4.20||^5.0.11||^6.0||^7.0", "symfony/dependency-injection": "^4.4.20||^5.0.11||^6.0||^7.0", diff --git a/src/Tracing/Cache/TraceableCacheAdapterForV3.php b/src/Tracing/Cache/TraceableCacheAdapterForV3.php index dc1ea613..ef276620 100644 --- a/src/Tracing/Cache/TraceableCacheAdapterForV3.php +++ b/src/Tracing/Cache/TraceableCacheAdapterForV3.php @@ -9,7 +9,6 @@ use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; use Symfony\Contracts\Cache\CacheInterface; -use Symfony\Contracts\Cache\NamespacedPoolInterface; /** * This implementation of a cache adapter supports the distributed tracing @@ -17,7 +16,7 @@ * * @internal */ -final class TraceableCacheAdapterForV3 implements AdapterInterface, NamespacedPoolInterface, CacheInterface, PruneableInterface, ResettableInterface +final class TraceableCacheAdapterForV3 implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { /** * @phpstan-use TraceableCacheAdapterTrait @@ -49,16 +48,4 @@ public function get(string $key, callable $callback, ?float $beta = null, ?array return $this->decoratedAdapter->get($key, $callback, $beta, $metadata); }, $key); } - - public function withSubNamespace(string $namespace): static - { - if (!$this->decoratedAdapter instanceof NamespacedPoolInterface) { - throw new \BadMethodCallException(\sprintf('The %s::withSubNamespace() method is not supported because the decorated adapter does not implement the "%s" interface.', self::class, NamespacedPoolInterface::class)); - } - - $clone = clone $this; - $clone->decoratedAdapter = $this->decoratedAdapter->withSubNamespace($namespace); - - return $clone; - } } diff --git a/src/Tracing/Cache/TraceableCacheAdapterForV3WithNamespace.php b/src/Tracing/Cache/TraceableCacheAdapterForV3WithNamespace.php new file mode 100644 index 00000000..7b53c286 --- /dev/null +++ b/src/Tracing/Cache/TraceableCacheAdapterForV3WithNamespace.php @@ -0,0 +1,64 @@ + + */ + use TraceableCacheAdapterTrait; + + /** + * @param HubInterface $hub The current hub + * @param AdapterInterface $decoratedAdapter The decorated cache adapter + */ + public function __construct(HubInterface $hub, AdapterInterface $decoratedAdapter) + { + $this->hub = $hub; + $this->decoratedAdapter = $decoratedAdapter; + } + + /** + * {@inheritdoc} + * + * @param mixed[] $metadata + */ + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + return $this->traceFunction('cache.get_item', function () use ($key, $callback, $beta, &$metadata) { + if (!$this->decoratedAdapter instanceof CacheInterface) { + throw new \BadMethodCallException(\sprintf('The %s::get() method is not supported because the decorated adapter does not implement the "%s" interface.', self::class, CacheInterface::class)); + } + + return $this->decoratedAdapter->get($key, $callback, $beta, $metadata); + }, $key); + } + + public function withSubNamespace(string $namespace): static + { + if (!$this->decoratedAdapter instanceof NamespacedPoolInterface) { + throw new \BadMethodCallException(\sprintf('The %s::withSubNamespace() method is not supported because the decorated adapter does not implement the "%s" interface.', self::class, NamespacedPoolInterface::class)); + } + + $clone = clone $this; + $clone->decoratedAdapter = $this->decoratedAdapter->withSubNamespace($namespace); + + return $clone; + } +} diff --git a/src/aliases.php b/src/aliases.php index 92272bef..44dac6b2 100644 --- a/src/aliases.php +++ b/src/aliases.php @@ -9,6 +9,7 @@ use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapter; use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapterForV2; use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapterForV3; +use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapterForV3WithNamespace; use Sentry\SentryBundle\Tracing\Cache\TraceableTagAwareCacheAdapter; use Sentry\SentryBundle\Tracing\Cache\TraceableTagAwareCacheAdapterForV2; use Sentry\SentryBundle\Tracing\Cache\TraceableTagAwareCacheAdapterForV3; @@ -38,12 +39,17 @@ use Symfony\Component\Cache\DoctrineProvider; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\Response\StreamableInterface; +use Symfony\Contracts\Cache\NamespacedPoolInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; if (interface_exists(AdapterInterface::class)) { if (!class_exists(DoctrineProvider::class, false) && version_compare(\PHP_VERSION, '8.0.0', '>=')) { if (!class_exists(TraceableCacheAdapter::class, false)) { - class_alias(TraceableCacheAdapterForV3::class, TraceableCacheAdapter::class); + if (class_exists(NamespacedPoolInterface::class, false)) { + class_alias(TraceableCacheAdapterForV3WithNamespace::class, TraceableCacheAdapter::class); + } else { + class_alias(TraceableCacheAdapterForV3::class, TraceableCacheAdapter::class); + } } if (!class_exists(TraceableTagAwareCacheAdapter::class, false)) { From aff1481370b3aa288be133546387a4748f6e9443 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 7 Jul 2025 14:49:37 +0200 Subject: [PATCH 3/3] Fix and add test --- src/aliases.php | 2 +- tests/Tracing/Cache/TraceableCacheAdapterTest.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/aliases.php b/src/aliases.php index 44dac6b2..e0433bcb 100644 --- a/src/aliases.php +++ b/src/aliases.php @@ -45,7 +45,7 @@ if (interface_exists(AdapterInterface::class)) { if (!class_exists(DoctrineProvider::class, false) && version_compare(\PHP_VERSION, '8.0.0', '>=')) { if (!class_exists(TraceableCacheAdapter::class, false)) { - if (class_exists(NamespacedPoolInterface::class, false)) { + if (interface_exists(NamespacedPoolInterface::class)) { class_alias(TraceableCacheAdapterForV3WithNamespace::class, TraceableCacheAdapter::class); } else { class_alias(TraceableCacheAdapterForV3::class, TraceableCacheAdapter::class); diff --git a/tests/Tracing/Cache/TraceableCacheAdapterTest.php b/tests/Tracing/Cache/TraceableCacheAdapterTest.php index 1536adfd..5e5b9c29 100644 --- a/tests/Tracing/Cache/TraceableCacheAdapterTest.php +++ b/tests/Tracing/Cache/TraceableCacheAdapterTest.php @@ -6,6 +6,7 @@ use Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapter; use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Contracts\Cache\NamespacedPoolInterface; /** * @phpstan-extends AbstractTraceableCacheAdapterTest @@ -27,4 +28,16 @@ protected static function getAdapterClassFqcn(): string { return AdapterInterface::class; } + + public function testNamespacePoolImplementation(): void + { + if (!interface_exists(NamespacedPoolInterface::class)) { + $this->markTestSkipped('NamespacedPoolInterface does not exists.'); + } + + $decoratedAdapter = $this->createMock(static::getAdapterClassFqcn()); + $adapter = $this->createCacheAdapter($decoratedAdapter); + + static::assertInstanceOf(NamespacedPoolInterface::class, $adapter); + } }