diff options
Diffstat (limited to 'core/lib')
12 files changed, 243 insertions, 15 deletions
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index 63514b60eff8..9b6dc8765017 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -76,7 +76,7 @@ class Drupal { /** * The current system version. */ - const VERSION = '11.2-dev'; + const VERSION = '11.3-dev'; /** * Core API compatibility. diff --git a/core/lib/Drupal/Core/Cache/CacheTagsInvalidator.php b/core/lib/Drupal/Core/Cache/CacheTagsInvalidator.php index 6c02649d2705..dad8bc10a21e 100644 --- a/core/lib/Drupal/Core/Cache/CacheTagsInvalidator.php +++ b/core/lib/Drupal/Core/Cache/CacheTagsInvalidator.php @@ -7,7 +7,7 @@ use Drupal\Component\Assertion\Inspector; /** * Passes cache tag events to classes that wish to respond to them. */ -class CacheTagsInvalidator implements CacheTagsInvalidatorInterface { +class CacheTagsInvalidator implements CacheTagsInvalidatorInterface, CacheTagsPurgeInterface { /** * Holds an array of cache tags invalidators. @@ -54,6 +54,17 @@ class CacheTagsInvalidator implements CacheTagsInvalidatorInterface { } /** + * {@inheritdoc} + */ + public function purge(): void { + foreach ($this->invalidators as $invalidator) { + if ($invalidator instanceof CacheTagsPurgeInterface) { + $invalidator->purge(); + } + } + } + + /** * Adds a cache tags invalidator. * * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $invalidator diff --git a/core/lib/Drupal/Core/Cache/CacheTagsPurgeInterface.php b/core/lib/Drupal/Core/Cache/CacheTagsPurgeInterface.php new file mode 100644 index 000000000000..24c110372d12 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagsPurgeInterface.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Cache; + +/** + * Provides purging of cache tag invalidations. + * + * Backends that persistently store cache tag invalidations can use this + * interface to implement purging of cache tag invalidations. By default, cache + * tag purging will only be called during drupal_flush_all_caches(), after all + * other caches have been cleared. + * + * @ingroup cache + */ +interface CacheTagsPurgeInterface { + + /** + * Purge cache tag invalidations. + */ + public function purge(): void; + +} diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php index cb88c69495a7..9602bc8ba5d5 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php +++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php @@ -8,7 +8,7 @@ use Drupal\Core\Database\DatabaseException; /** * Cache tags invalidations checksum implementation that uses the database. */ -class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface, CacheTagsChecksumPreloadInterface { +class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface, CacheTagsChecksumPreloadInterface, CacheTagsPurgeInterface { use CacheTagsChecksumTrait; @@ -70,6 +70,22 @@ class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTags } /** + * {@inheritdoc} + */ + public function purge(): void { + try { + $this->connection->truncate('cachetags')->execute(); + } + catch (\Throwable $e) { + // If the table does not exist yet, there is nothing to purge. + if (!$this->ensureTableExists()) { + throw $e; + } + } + $this->reset(); + } + + /** * Check if the cache tags table exists and create it if not. */ protected function ensureTableExists() { diff --git a/core/lib/Drupal/Core/Mailer/Transport/SendmailCommandValidationTransportFactory.php b/core/lib/Drupal/Core/Mailer/Transport/SendmailCommandValidationTransportFactory.php new file mode 100644 index 000000000000..84dfb64c7b28 --- /dev/null +++ b/core/lib/Drupal/Core/Mailer/Transport/SendmailCommandValidationTransportFactory.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Mailer\Transport; + +use Drupal\Core\Site\Settings; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportFactoryInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * Command validation decorator for sendmail transport factory. + */ +class SendmailCommandValidationTransportFactory implements TransportFactoryInterface { + + /** + * Construct command validation decorator for sendmail transport factory. + * + * @param \Symfony\Component\Mailer\Transport\TransportFactoryInterface $inner + * The decorated sendmail transport factory. + */ + public function __construct( + #[AutowireDecorated] + protected TransportFactoryInterface $inner, + ) { + } + + /** + * {@inheritdoc} + */ + public function create(Dsn $dsn): TransportInterface { + $command = $dsn->getOption('command'); + if (!empty($command)) { + $commands = Settings::get('mailer_sendmail_commands', []); + if (!in_array($command, $commands, TRUE)) { + throw new \RuntimeException("Unsafe sendmail command {$command}"); + } + } + + return $this->inner->create($dsn); + } + + /** + * {@inheritdoc} + */ + public function supports(Dsn $dsn): bool { + return $this->inner->supports($dsn); + } + +} diff --git a/core/lib/Drupal/Core/Mailer/TransportServiceFactory.php b/core/lib/Drupal/Core/Mailer/TransportServiceFactory.php new file mode 100644 index 000000000000..8950d44e3648 --- /dev/null +++ b/core/lib/Drupal/Core/Mailer/TransportServiceFactory.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Mailer; + +use Drupal\Core\Config\ConfigFactoryInterface; +use Symfony\Component\DependencyInjection\Attribute\AutowireIterator; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * The default mailer transport service factory. + */ +class TransportServiceFactory implements TransportServiceFactoryInterface { + + use TransportServiceFactoryTrait; + + /** + * Constructs a new transport service factory. + * + * @param Iterable<TransportFactoryInterface> $factories + * A list of transport factories. + * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory + * The config factory service. + */ + public function __construct( + #[AutowireIterator(tag: 'mailer.transport_factory')] + iterable $factories, + protected ConfigFactoryInterface $configFactory, + ) { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + */ + public function createTransport(): TransportInterface { + $dsn = $this->configFactory->get('system.mail')->get('mailer_dsn'); + $dsnObject = new Dsn(...$dsn); + return $this->fromDsnObject($dsnObject); + } + +} diff --git a/core/lib/Drupal/Core/Mailer/TransportServiceFactoryInterface.php b/core/lib/Drupal/Core/Mailer/TransportServiceFactoryInterface.php new file mode 100644 index 000000000000..8a2b5368db05 --- /dev/null +++ b/core/lib/Drupal/Core/Mailer/TransportServiceFactoryInterface.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Mailer; + +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * An interface defining mailer transport service factory implementations. + * + * The transport service factory is responsible to create a transport instance + * according to the site configuration. The default service factory looks up the + * `mailer_dsn` key from the `system.mail` config and returns an appropriate + * transport implementation. + * + * Contrib and custom code may choose to replace or decorate the transport + * service factory in order to provide a mailer transport instance which + * requires more complex setup. + */ +interface TransportServiceFactoryInterface { + + /** + * Creates and returns a configured mailer transport class. + */ + public function createTransport(): TransportInterface; + +} diff --git a/core/lib/Drupal/Core/Mailer/TransportServiceFactoryTrait.php b/core/lib/Drupal/Core/Mailer/TransportServiceFactoryTrait.php new file mode 100644 index 000000000000..c4aa2c736a4e --- /dev/null +++ b/core/lib/Drupal/Core/Mailer/TransportServiceFactoryTrait.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Mailer; + +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * A trait containing helper methods for transport service construction. + */ +trait TransportServiceFactoryTrait { + + /** + * A list of transport factories. + * + * @var Iterable<TransportFactoryInterface> + */ + protected iterable $factories; + + /** + * Constructs a transport instance given a DSN object. + * + * @param \Symfony\Component\Mailer\Transport\Dsn $dsn + * The mailer DSN object. + * + * @throws \Symfony\Component\Mailer\Exception\IncompleteDsnException + * @throws \Symfony\Component\Mailer\Exception\UnsupportedSchemeException + */ + protected function fromDsnObject(Dsn $dsn): TransportInterface { + foreach ($this->factories as $factory) { + if ($factory->supports($dsn)) { + return $factory->create($dsn); + } + } + + throw new UnsupportedSchemeException($dsn); + } + +} diff --git a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php index f1db3a342af1..9feb9bed8da7 100644 --- a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php +++ b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php @@ -93,11 +93,14 @@ final class ConsoleInputCollector implements InputCollectorInterface { $method = $settings['method']; $arguments = $settings['arguments'] ?? []; - // Most of the input-collecting methods of StyleInterface have a `default` - // parameter. - $arguments += [ - 'default' => $default_value, - ]; + if ($method !== 'askHidden') { + // Most of the input-collecting methods of StyleInterface have a `default` + // parameter. + $arguments += [ + 'default' => $default_value, + ]; + } + // We don't support using Symfony Console's inline validation; instead, // input definitions should define constraints. unset($arguments['validator']); diff --git a/core/lib/Drupal/Core/Session/SessionManager.php b/core/lib/Drupal/Core/Session/SessionManager.php index 0170626181c0..6927ba2ebbec 100644 --- a/core/lib/Drupal/Core/Session/SessionManager.php +++ b/core/lib/Drupal/Core/Session/SessionManager.php @@ -6,6 +6,7 @@ use Drupal\Component\Datetime\TimeInterface; use Drupal\Core\Database\Connection; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\SessionBagInterface; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** @@ -162,6 +163,16 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter parent::save(); } + $allowedKeys = array_map( + fn (SessionBagInterface $bag) => $bag->getStorageKey(), + $this->bags + ); + $allowedKeys[] = $this->getMetadataBag()->getStorageKey(); + $deprecatedKeys = array_diff(array_keys($_SESSION), $allowedKeys); + if (count($deprecatedKeys) > 0) { + @trigger_error(sprintf('Storing values directly in $_SESSION is deprecated in drupal:11.2.0 and will become unsupported in drupal:12.0.0. Use $request->getSession()->set() instead. Affected keys: %s. See https://www.drupal.org/node/3518527', implode(", ", $deprecatedKeys)), E_USER_DEPRECATED); + } + $this->startedLazy = FALSE; } diff --git a/core/lib/Drupal/Core/Template/Loader/ComponentLoader.php b/core/lib/Drupal/Core/Template/Loader/ComponentLoader.php index d141d202ecb0..e3669f8f1450 100644 --- a/core/lib/Drupal/Core/Template/Loader/ComponentLoader.php +++ b/core/lib/Drupal/Core/Template/Loader/ComponentLoader.php @@ -122,13 +122,8 @@ class ComponentLoader implements LoaderInterface { catch (ComponentNotFoundException) { throw new LoaderError('Unable to find component'); } - // If any of the templates, or the component definition, are fresh. Then the - // component is fresh. $metadata_path = $component->getPluginDefinition()[YamlDirectoryDiscovery::FILE_KEY]; - if ($file_is_fresh($metadata_path)) { - return TRUE; - } - return $file_is_fresh($component->getTemplatePath()); + return $file_is_fresh($component->getTemplatePath()) && $file_is_fresh($metadata_path); } } diff --git a/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php b/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php index 246f143d4e25..ff102b5170a9 100644 --- a/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php +++ b/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php @@ -199,7 +199,9 @@ class ComponentValidator { $errors = array_filter( $this->validator->getErrors(), function (array $error) use ($context): bool { - if (($error['constraint'] ?? '') !== 'type') { + // Support 5.0 ($error['constraint']) and 6.0 + // ($error['constraint']['name']) at the same time. + if (($error['constraint']['name'] ?? $error['constraint'] ?? '') !== 'type') { return TRUE; } return !Element::isRenderArray($context[$error['property']] ?? NULL); |