diff --git a/core/core.services.yml b/core/core.services.yml index ef3aefb9d07663cbfd64f4189c2d17bdcfd402cd..476b1443fbf5d5216c6ebbd9d3cb39c75628776b 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -229,7 +229,7 @@ services: - [setContainer, ['@service_container']] cache.backend.database: class: Drupal\Core\Cache\DatabaseBackendFactory - arguments: ['@database', '@cache_tags.invalidator.checksum', '@settings'] + arguments: ['@database', '@cache_tags.invalidator.checksum', '@settings', '@serialization.phpserialize'] tags: - { name: backend_overridable } cache.backend.apcu: @@ -541,6 +541,7 @@ services: class: Drupal\Component\Serialization\Json serialization.phpserialize: class: Drupal\Component\Serialization\PhpSerialize + Drupal\Component\Serialization\ObjectAwareSerializationInterface: '@serialization.phpserialize' serialization.yaml: class: Drupal\Component\Serialization\Yaml diff --git a/core/lib/Drupal/Component/Serialization/ObjectAwareSerializationInterface.php b/core/lib/Drupal/Component/Serialization/ObjectAwareSerializationInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..6177550363da43cd232017a31407999521a6b262 --- /dev/null +++ b/core/lib/Drupal/Component/Serialization/ObjectAwareSerializationInterface.php @@ -0,0 +1,18 @@ +<?php + +namespace Drupal\Component\Serialization; + +// cspell:ignore serializers igbinary + +/** + * Ensures that a serializer is usable for serializing PHP objects. + * + * Other Serializers that implement the SerializationInterface, for example + * serializers that use JSON or YAML, are suitable for different PHP types + * except objects. Serializers that implement the + * ObjectAwareSerializationInterface instead are clearly indicating that they're + * suitable for PHP objects, for example using the PHP string serialization + * format or the igbinary format. + */ +interface ObjectAwareSerializationInterface extends SerializationInterface { +} diff --git a/core/lib/Drupal/Component/Serialization/PhpSerialize.php b/core/lib/Drupal/Component/Serialization/PhpSerialize.php index 1f7e03d75b447e1419e89c386cc6bef3d226f5a5..a5e47220cc57526827dc85ac49d5299ee1d73715 100644 --- a/core/lib/Drupal/Component/Serialization/PhpSerialize.php +++ b/core/lib/Drupal/Component/Serialization/PhpSerialize.php @@ -5,7 +5,7 @@ /** * Default serialization for serialized PHP. */ -class PhpSerialize implements SerializationInterface { +class PhpSerialize implements ObjectAwareSerializationInterface { /** * {@inheritdoc} diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index 29e4fe5c7b3edff67832a9cad9c52c5418ec380b..7a36c5612c91bee4756a3fec4171f5b311596199 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Cache; +use Drupal\Component\Serialization\ObjectAwareSerializationInterface; use Drupal\Component\Assertion\Inspector; use Drupal\Component\Utility\Crypt; use Drupal\Core\Database\Connection; @@ -66,6 +67,13 @@ class DatabaseBackend implements CacheBackendInterface { */ protected $checksumProvider; + /** + * The serializer to use. + * + * @var \Drupal\Component\Serialization\ObjectAwareSerializationInterface + */ + protected ObjectAwareSerializationInterface $serializer; + /** * Constructs a DatabaseBackend object. * @@ -75,17 +83,29 @@ class DatabaseBackend implements CacheBackendInterface { * The cache tags checksum provider. * @param string $bin * The cache bin for which the object is created. + * @param \Drupal\Component\Serialization\ObjectAwareSerializationInterface|int|null $serializer + * (optional) The serializer to use. * @param int $max_rows * (optional) The maximum number of rows that are allowed in this cache bin * table. */ - public function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider, $bin, $max_rows = NULL) { + public function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider, $bin, ObjectAwareSerializationInterface|int $serializer = NULL, $max_rows = NULL) { // All cache tables should be prefixed with 'cache_'. $bin = 'cache_' . $bin; $this->bin = $bin; $this->connection = $connection; $this->checksumProvider = $checksum_provider; + if (is_int($serializer)) { + @trigger_error('Calling ' . __METHOD__ . ' with the $max_rows as 3rd argument is deprecated in drupal:10.3.0 and it will be the 4th argument in drupal:11.0.0. See https://www.drupal.org/node/3014684', E_USER_DEPRECATED); + $max_rows = $serializer; + $serializer = \Drupal::service('serialization.phpserialize'); + } + elseif ($serializer === NULL) { + @trigger_error('Calling ' . __METHOD__ . ' without the $serializer argument is deprecated in drupal:10.3.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/3014684', E_USER_DEPRECATED); + $serializer = \Drupal::service('serialization.phpserialize'); + } + $this->serializer = $serializer; $this->maxRows = $max_rows === NULL ? static::DEFAULT_MAX_ROWS : $max_rows; } @@ -169,7 +189,7 @@ protected function prepareItem($cache, $allow_invalid) { // Unserialize and return the cached data. if ($cache->serialized) { - $cache->data = unserialize($cache->data); + $cache->data = $this->serializer->decode($cache->data); } return $cache; @@ -252,7 +272,7 @@ protected function doSetMultiple(array $items) { } if (!is_string($item['data'])) { - $fields['data'] = serialize($item['data']); + $fields['data'] = $this->serializer->encode($item['data']); $fields['serialized'] = 1; } else { diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php index 175639444c26b82a9572866fdd7f7008963b0050..fd176e045ebe5b6fc59ebbaea0a38da5159656f4 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Cache; +use Drupal\Component\Serialization\ObjectAwareSerializationInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Site\Settings; @@ -21,13 +22,6 @@ class DatabaseBackendFactory implements CacheFactoryInterface { */ protected $checksumProvider; - /** - * The site settings. - * - * @var \Drupal\Core\Site\Settings - */ - protected $settings; - /** * Constructs the DatabaseBackendFactory object. * @@ -37,13 +31,22 @@ class DatabaseBackendFactory implements CacheFactoryInterface { * The cache tags checksum provider. * @param \Drupal\Core\Site\Settings $settings * (optional) The site settings. + * @param \Drupal\Component\Serialization\ObjectAwareSerializationInterface|null $serializer + * (optional) The serializer to use. * * @throws \BadMethodCallException */ - public function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider, Settings $settings = NULL) { + public function __construct(Connection $connection, CacheTagsChecksumInterface $checksum_provider, protected ?Settings $settings = NULL, protected ?ObjectAwareSerializationInterface $serializer = NULL) { $this->connection = $connection; $this->checksumProvider = $checksum_provider; - $this->settings = $settings ?: Settings::getInstance(); + if ($this->settings === NULL) { + @trigger_error('Calling ' . __METHOD__ . ' without the $settings argument is deprecated in drupal:10.3.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/3014684', E_USER_DEPRECATED); + $this->settings = Settings::getInstance(); + } + if ($this->serializer === NULL) { + @trigger_error('Calling ' . __METHOD__ . ' without the $serializer argument is deprecated in drupal:10.3.0 and it will be required in drupal:11.0.0. See https://www.drupal.org/node/3014684', E_USER_DEPRECATED); + $this->serializer = \Drupal::service('serialization.phpserialize'); + } } /** @@ -57,7 +60,7 @@ public function __construct(Connection $connection, CacheTagsChecksumInterface $ */ public function get($bin) { $max_rows = $this->getMaxRowsForBin($bin); - return new DatabaseBackend($this->connection, $this->checksumProvider, $bin, $max_rows); + return new DatabaseBackend($this->connection, $this->checksumProvider, $bin, $this->serializer, $max_rows); } /** diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 9a9a14f1ca31471821a2ee15aa8474cb0a5a4c76..c0bdc552582e93cc2cd44042534deefa581b2957 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -5,6 +5,7 @@ use Composer\Autoload\ClassLoader; use Drupal\Component\EventDispatcher\Event; use Drupal\Component\FileCache\FileCacheFactory; +use Drupal\Component\Serialization\PhpSerialize; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\DatabaseBackend; use Drupal\Core\Config\BootstrapConfigStorageFactory; @@ -76,12 +77,21 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { ], 'cache.container' => [ 'class' => 'Drupal\Core\Cache\DatabaseBackend', - 'arguments' => ['@database', '@cache_tags_provider.container', 'container', DatabaseBackend::MAXIMUM_NONE], + 'arguments' => [ + '@database', + '@cache_tags_provider.container', + 'container', + '@serialization.phpserialize', + DatabaseBackend::MAXIMUM_NONE, + ], ], 'cache_tags_provider.container' => [ 'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum', 'arguments' => ['@database'], ], + 'serialization.phpserialize' => [ + 'class' => PhpSerialize::class, + ], ], ]; diff --git a/core/modules/mysql/tests/src/Kernel/mysql/DbDumpTest.php b/core/modules/mysql/tests/src/Kernel/mysql/DbDumpTest.php index 2ff0f6a6a645a78f1a3fecdc0f7ab63ad532f6bf..7e5c18a41b5c488b948e9d801d9622f6d17305a1 100644 --- a/core/modules/mysql/tests/src/Kernel/mysql/DbDumpTest.php +++ b/core/modules/mysql/tests/src/Kernel/mysql/DbDumpTest.php @@ -74,7 +74,8 @@ public function register(ContainerBuilder $container) { $container->register('cache_factory', 'Drupal\Core\Cache\DatabaseBackendFactory') ->addArgument(new Reference('database')) ->addArgument(new Reference('cache_tags.invalidator.checksum')) - ->addArgument(new Reference('settings')); + ->addArgument(new Reference('settings')) + ->addArgument(new Reference('serialization.phpserialize')); } /** diff --git a/core/tests/Drupal/KernelTests/Core/Cache/ChainedFastBackendTest.php b/core/tests/Drupal/KernelTests/Core/Cache/ChainedFastBackendTest.php index a93b674d5cf0ecc61dbd09fb92e7eb33b0e0ad4c..1a84ddee080962b0b188eb1c2300ba36495b4ed9 100644 --- a/core/tests/Drupal/KernelTests/Core/Cache/ChainedFastBackendTest.php +++ b/core/tests/Drupal/KernelTests/Core/Cache/ChainedFastBackendTest.php @@ -20,7 +20,7 @@ class ChainedFastBackendTest extends GenericCacheBackendUnitTestBase { * A new ChainedFastBackend object. */ protected function createCacheBackend($bin) { - $consistent_backend = new DatabaseBackend(\Drupal::service('database'), \Drupal::service('cache_tags.invalidator.checksum'), $bin, 100); + $consistent_backend = new DatabaseBackend(\Drupal::service('database'), \Drupal::service('cache_tags.invalidator.checksum'), $bin, \Drupal::service('serialization.phpserialize'), 100); $fast_backend = new PhpBackend($bin, \Drupal::service('cache_tags.invalidator.checksum')); $backend = new ChainedFastBackend($consistent_backend, $fast_backend, $bin); // Explicitly register the cache bin as it can not work through the diff --git a/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php b/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php index 79d32d37167d50eea26f40a361230ec2c19db9a4..8a40e909a5fb58c45a140280fa00529bad2612c2 100644 --- a/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php +++ b/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php @@ -32,7 +32,7 @@ class DatabaseBackendTest extends GenericCacheBackendUnitTestBase { * A new DatabaseBackend object. */ protected function createCacheBackend($bin) { - return new DatabaseBackend($this->container->get('database'), $this->container->get('cache_tags.invalidator.checksum'), $bin, static::$maxRows); + return new DatabaseBackend($this->container->get('database'), $this->container->get('cache_tags.invalidator.checksum'), $bin, $this->container->get('serialization.phpserialize'), static::$maxRows); } /** diff --git a/core/tests/Drupal/KernelTests/Core/Cache/EndOfTransactionQueriesTest.php b/core/tests/Drupal/KernelTests/Core/Cache/EndOfTransactionQueriesTest.php index 83ea69e10f1777a34fe06fd9b030b83836572a51..63ecff81f2e06b86cba96e0f38b0373b92f5136f 100644 --- a/core/tests/Drupal/KernelTests/Core/Cache/EndOfTransactionQueriesTest.php +++ b/core/tests/Drupal/KernelTests/Core/Cache/EndOfTransactionQueriesTest.php @@ -10,6 +10,7 @@ use Drupal\KernelTests\KernelTestBase; use Drupal\user\Entity\User; use Symfony\Component\DependencyInjection\Reference; +use Drupal\Component\Serialization\PhpSerialize; /** * Tests delaying of cache tag invalidation queries to the end of transactions. @@ -47,11 +48,13 @@ protected function setUp(): void { public function register(ContainerBuilder $container) { parent::register($container); + $container->register('serializer', PhpSerialize::class); // Register a database cache backend rather than memory-based. $container->register('cache_factory', DatabaseBackendFactory::class) ->addArgument(new Reference('database')) ->addArgument(new Reference('cache_tags.invalidator.checksum')) - ->addArgument(new Reference('settings')); + ->addArgument(new Reference('settings')) + ->addArgument(new Reference('serializer')); } /** diff --git a/core/tests/Drupal/Tests/Core/Cache/DatabaseBackendFactoryTest.php b/core/tests/Drupal/Tests/Core/Cache/DatabaseBackendFactoryTest.php index bf94caa009eab44859b53cfbcab73de9ec0c8b13..a0ea25e7823ab8896a2193f7fbe993ad491a35b7 100644 --- a/core/tests/Drupal/Tests/Core/Cache/DatabaseBackendFactoryTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/DatabaseBackendFactoryTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\Core\Cache; +use Drupal\Component\Serialization\PhpSerialize; use Drupal\Core\Cache\CacheTagsChecksumInterface; use Drupal\Core\Cache\DatabaseBackend; use Drupal\Core\Cache\DatabaseBackendFactory; @@ -26,7 +27,8 @@ public function testGet(array $settings, $expected_max_rows_foo, $expected_max_r $database_backend_factory = new DatabaseBackendFactory( $this->prophesize(Connection::class)->reveal(), $this->prophesize(CacheTagsChecksumInterface::class)->reveal(), - new Settings($settings) + new Settings($settings), + new PhpSerialize() ); $this->assertSame($expected_max_rows_foo, $database_backend_factory->get('foo')->getMaxRows());