Skip to content

Commit

Permalink
Updated core.
Browse files Browse the repository at this point in the history
  • Loading branch information
dmundra committed Nov 27, 2024
1 parent e79de22 commit 8b60069
Show file tree
Hide file tree
Showing 25 changed files with 384 additions and 171 deletions.
236 changes: 118 additions & 118 deletions composer.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/lib/Drupal.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '11.0.7';
const VERSION = '11.0.9';

/**
* Core API compatibility.
Expand Down
10 changes: 7 additions & 3 deletions core/lib/Drupal/Core/Ajax/MessageCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Drupal\Core\Ajax;

use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Asset\AttachedAssets;

/**
Expand Down Expand Up @@ -68,7 +70,7 @@ class MessageCommand implements CommandInterface, CommandWithAttachedAssetsInter
/**
* The message text.
*
* @var string
* @var string|\Drupal\Component\Render\MarkupInterface
*/
protected $message;

Expand Down Expand Up @@ -96,7 +98,7 @@ class MessageCommand implements CommandInterface, CommandWithAttachedAssetsInter
/**
* Constructs a MessageCommand object.
*
* @param string $message
* @param string|\Drupal\Component\Render\MarkupInterface $message
* The text of the message.
* @param string|null $wrapper_query_selector
* The query selector of the element to display messages in when they
Expand All @@ -120,7 +122,9 @@ public function __construct($message, $wrapper_query_selector = NULL, array $opt
public function render() {
return [
'command' => 'message',
'message' => $this->message,
'message' => $this->message instanceof MarkupInterface
? (string) $this->message
: Xss::filterAdmin($this->message),
'messageWrapperQuerySelector' => $this->wrapperQuerySelector,
'messageOptions' => $this->options,
'clearPrevious' => $this->clearPrevious,
Expand Down
3 changes: 2 additions & 1 deletion core/lib/Drupal/Core/Config/StorageComparer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Drupal\Component\Datetime\Time;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\Cache\NullBackend;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
Expand Down Expand Up @@ -85,7 +86,7 @@ class StorageComparer implements StorageComparerInterface {
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $targetCacheStorage;
protected CacheBackendInterface $targetCacheStorage;

/**
* Indicates whether the target storage should be wrapped in a cache.
Expand Down
6 changes: 3 additions & 3 deletions core/lib/Drupal/Core/Form/ConfigTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ final class ConfigTarget {
* return an array with the transformed values, also keyed by property path.
* The callback will receive the form state object as its second argument.
* The callback may return a special values:
* - ToConfig::NoMapping, to indicate that the given form value does not
* need to be mapped onto the Config object
* - ToConfig::NoOp, to indicate that the given form value does not need to
* be mapped onto the Config object
* - ToConfig::DeleteKey to indicate that the targeted property path should
* be deleted from config.
* Defaults to NULL.
Expand Down Expand Up @@ -237,7 +237,7 @@ public function setValue(Config $config, mixed $value, FormStateInterface $form_
}

// Set the returned value, or if a special value (one of the cases in the
// ConfigTargetValue enum): apply the appropriate action.
// ToConfig enum): apply the appropriate action.
array_walk($value, fn (mixed $value, string $property) => match ($value) {
// No-op.
ToConfig::NoOp => NULL,
Expand Down
2 changes: 1 addition & 1 deletion core/lib/Drupal/Core/Mail/Plugin/Mail/PhpMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function mail(array $message) {
if (in_array(strtolower($name), self::MAILBOX_LIST_HEADERS, TRUE)) {
// Split values by comma, but ignore commas encapsulated in double
// quotes.
$value = str_getcsv($value, ',');
$value = str_getcsv($value, escape: '\\');
}
$headers->addHeader($name, $value);
}
Expand Down
2 changes: 1 addition & 1 deletion core/lib/Drupal/Core/Mail/Plugin/Mail/SymfonyMailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public function mail(array $message) {
if (in_array(strtolower($name), self::MAILBOX_LIST_HEADERS, TRUE)) {
// Split values by comma, but ignore commas encapsulated in double
// quotes.
$value = str_getcsv($value, ',');
$value = str_getcsv($value, escape: '\\');
}
$headers->addHeader($name, $value);
}
Expand Down
12 changes: 11 additions & 1 deletion core/lib/Drupal/Core/Recipe/RecipeConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ final class RecipeConfigurator {
*/
public readonly array $recipes;

/**
* A cache of already-loaded recipes, keyed by path.
*
* @var \Drupal\Core\Recipe\Recipe[]
*/
private static array $cache = [];

/**
* @param string[] $recipes
* A list of recipes for a recipe to apply. The recipes will be applied in
Expand Down Expand Up @@ -56,8 +63,11 @@ public static function getIncludedRecipe(string $include_path, string $name): Re
$path = $include_path . "/$name/recipe.yml";
}

if (array_key_exists($path, static::$cache)) {
return static::$cache[$path];
}
if (file_exists($path)) {
return Recipe::createFromDirectory(dirname($path));
return static::$cache[$path] = Recipe::createFromDirectory(dirname($path));
}
$search_path = dirname($path, 2);
throw new UnknownRecipeException($name, $search_path, sprintf("Can not find the %s recipe, search path: %s", $name, $search_path));
Expand Down
56 changes: 56 additions & 0 deletions core/lib/Drupal/Core/Template/RemoveCheckToStringNodeVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Drupal\Core\Template;

use Twig\Environment;
use Twig\Node\CheckToStringNode;
use Twig\Node\Node;
use Twig\NodeVisitor\NodeVisitorInterface;

/**
* Defines a TwigNodeVisitor that replaces CheckToStringNodes.
*
* Twig 3.14.1 resulted in a performance regression in Drupal due to checking if
* __toString is an allowed method on objects. __toString is allowed on all
* objects when Drupal's default SandboxPolicy is active. Therefore, Twig's
* SandboxExtension checks are unnecessary.
*/
final class RemoveCheckToStringNodeVisitor implements NodeVisitorInterface {

/**
* {@inheritdoc}
*/
public function enterNode(Node $node, Environment $env): Node {
if ($node instanceof CheckToStringNode) {
// Replace CheckToStringNode with the faster equivalent, __toString is an
// allowed method so any checking of __toString on a per-object basis is
// performance overhead.
$new = new TwigSimpleCheckToStringNode($node->getNode('expr'));
// @todo https://www.drupal.org/project/drupal/issues/3488584 Update for
// Twig 4 as the spread attribute has been removed there.
if ($node->hasAttribute('spread')) {
$new->setAttribute('spread', $node->getAttribute('spread'));
}
return $new;
}
return $node;
}

/**
* {@inheritdoc}
*/
public function leaveNode(Node $node, Environment $env): ?Node {
return $node;
}

/**
* {@inheritdoc}
*/
public function getPriority() {
// Runs after sandbox visitor.
return 1;
}

}
10 changes: 9 additions & 1 deletion core/lib/Drupal/Core/Template/TwigExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,18 @@ public function getFilters() {
public function getNodeVisitors() {
// The node visitor is needed to wrap all variables with
// render_var -> TwigExtension->renderVar() function.
return [
$visitors = [
new TwigNodeVisitor(),
new TwigNodeVisitorCheckDeprecations(),
];
if (\in_array('__toString', TwigSandboxPolicy::getMethodsAllowedOnAllObjects(), TRUE)) {
// When __toString is an allowed method, there is no point in running
// \Twig\Extension\SandboxExtension::ensureToStringAllowed, so we add a
// node visitor to remove any CheckToStringNode nodes added by the
// sandbox extension.
$visitors[] = new RemoveCheckToStringNodeVisitor();
}
return $visitors;
}

/**
Expand Down
28 changes: 19 additions & 9 deletions core/lib/Drupal/Core/Template/TwigSandboxPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,7 @@ public function __construct() {
// Flip the array so we can check using isset().
$this->allowed_classes = array_flip($allowed_classes);

$allowed_methods = Settings::get('twig_sandbox_allowed_methods', [
// Only allow idempotent methods.
'id',
'label',
'bundle',
'get',
'__toString',
'toString',
]);
$allowed_methods = static::getMethodsAllowedOnAllObjects();
// Flip the array so we can check using isset().
$this->allowed_methods = array_flip($allowed_methods);

Expand Down Expand Up @@ -112,4 +104,22 @@ public function checkMethodAllowed($obj, $method): void {
throw new SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
}

/**
* Gets the list of allowed methods on all objects.
*
* @return string[]
* The list of allowed methods on all objects.
*/
public static function getMethodsAllowedOnAllObjects(): array {
return Settings::get('twig_sandbox_allowed_methods', [
// Only allow idempotent methods.
'id',
'label',
'bundle',
'get',
'__toString',
'toString',
]);
}

}
33 changes: 33 additions & 0 deletions core/lib/Drupal/Core/Template/TwigSimpleCheckToStringNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Drupal\Core\Template;

use Twig\Compiler;
use Twig\Node\CheckToStringNode;

/**
* Defines a twig node for simplifying CheckToStringNode.
*
* Drupal's sandbox policy is very permissive with checking whether an object
* can be converted to a string. We allow any object with a __toString method.
* This means that the array traversal in the default SandboxExtension
* implementation added by the parent class is a performance overhead we don't
* need.
*
* @see \Drupal\Core\Template\TwigSandboxPolicy
* @see \Drupal\Core\Template\RemoveCheckToStringNodeVisitor
*/
final class TwigSimpleCheckToStringNode extends CheckToStringNode {

/**
* {@inheritdoc}
*/
public function compile(Compiler $compiler): void {
$expr = $this->getNode('expr');
$compiler
->subcompile($expr);
}

}
33 changes: 27 additions & 6 deletions core/lib/Drupal/Core/Test/PhpUnitTestRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;

// cspell:ignore testdox

/**
* Run PHPUnit-based tests.
*
Expand Down Expand Up @@ -100,16 +102,24 @@ public function phpUnitCommand(): string {
* A fully qualified test class name.
* @param string $log_junit_file_path
* A filepath to use for PHPUnit's --log-junit option.
* @param int $status
* @param int|null $status
* (optional) The exit status code of the PHPUnit process will be assigned
* to this variable.
* @param string[] $output
* @param string[]|null $output
* (optional) The output by running the phpunit command. If provided, this
* array will contain the lines output by the command.
* @param bool $colors
* (optional) Whether to use colors in output. Defaults to FALSE.
*
* @internal
*/
protected function runCommand(string $test_class_name, string $log_junit_file_path, ?int &$status = NULL, ?array &$output = NULL): void {
protected function runCommand(
string $test_class_name,
string $log_junit_file_path,
?int &$status = NULL,
?array &$output = NULL,
bool $colors = FALSE,
): void {
global $base_url;
// Setup an environment variable containing the database connection so that
// functional tests can connect to the database.
Expand All @@ -130,9 +140,13 @@ protected function runCommand(string $test_class_name, string $log_junit_file_pa
// Build the command line for the PHPUnit CLI invocation.
$command = [
$phpunit_bin,
'--testdox',
'--log-junit',
$log_junit_file_path,
];
if ($colors) {
$command[] = '--colors=always';
}

// If the deprecation handler bridge is active, we need to fail when there
// are deprecations that get reported (i.e. not ignored or expected).
Expand All @@ -159,21 +173,28 @@ protected function runCommand(string $test_class_name, string $log_junit_file_pa
* The test run object.
* @param string $test_class_name
* A fully qualified test class name.
* @param int $status
* @param int|null $status
* (optional) The exit status code of the PHPUnit process will be assigned
* to this variable.
* @param bool $colors
* (optional) Whether to use colors in output. Defaults to FALSE.
*
* @return array
* The parsed results of PHPUnit's JUnit XML output, in the format of
* {simpletest}'s schema.
*
* @internal
*/
public function execute(TestRun $test_run, string $test_class_name, ?int &$status = NULL): array {
public function execute(
TestRun $test_run,
string $test_class_name,
?int &$status = NULL,
bool $colors = FALSE,
): array {
$log_junit_file_path = $this->xmlLogFilePath($test_run->id());
// Store output from our test run.
$output = [];
$this->runCommand($test_class_name, $log_junit_file_path, $status, $output);
$this->runCommand($test_class_name, $log_junit_file_path, $status, $output, $colors);

if ($status == TestStatus::PASS) {
return JUnitConverter::xmlToRows($test_run->id(), $log_junit_file_path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ class UniqueFieldConstraint extends SymfonyConstraint {

public $message = 'A @entity_type with @field_name %value already exists.';

/**
* This constraint is case-insensitive by default.
*
* For example "FOO" and "foo" would be considered as equivalent, and
* validation of the constraint would fail.
*
* @var bool
*/
public $caseSensitive = FALSE;

/**
* {@inheritdoc}
*/
Expand Down
Loading

0 comments on commit 8b60069

Please sign in to comment.