diff --git a/core/lib/Drupal/Component/Serialization/TaggedSerializationTrait.php b/core/lib/Drupal/Component/Serialization/TaggedSerializationTrait.php index 837c04b188..8253479841 100644 --- a/core/lib/Drupal/Component/Serialization/TaggedSerializationTrait.php +++ b/core/lib/Drupal/Component/Serialization/TaggedSerializationTrait.php @@ -14,6 +14,28 @@ trait TaggedSerializationTrait { */ protected static $tagCallbacks = []; + /** + * Executes a tag callback. + * + * @param mixed $value + * The parsed value. + * @param string $tag + * The tag name. + * + * @return mixed + * Result from the callback or original $value if no callback exists. + */ + public static function executeTagCallback($value, $tag) { + $callbacks = static::getTagCallbacks(); + + // Immediately return the original value if there is no callback. + if (!isset($callbacks[$tag])) { + return $value; + } + + return $callbacks[$tag](...(array) $value); + } + /** * Retrieves a map of tag callbacks. * @@ -22,7 +44,22 @@ trait TaggedSerializationTrait { * callback. */ public static function getTagCallbacks() { - return []; + return static::$tagCallbacks; + } + + /** + * Merges tag callbacks from this serializer onto a target serializer. + * + * @param string|\Drupal\Component\Serialization\TaggedSerializationInterface $serializer + * The target serializer to merge tag callbacks onto. + */ + protected static function mergeTagCallbacks($serializer) { + if ($serializer instanceof TaggedSerializationInterface || is_subclass_of($serializer, TaggedSerializationInterface::class)) { + $serializer::setTagCallbacks(array_merge( + $serializer::getTagCallbacks(), + static::getTagCallbacks() + )); + } } /** diff --git a/core/lib/Drupal/Component/Serialization/Yaml.php b/core/lib/Drupal/Component/Serialization/Yaml.php index 3889dd36f4..ec41c3accc 100644 --- a/core/lib/Drupal/Component/Serialization/Yaml.php +++ b/core/lib/Drupal/Component/Serialization/Yaml.php @@ -59,11 +59,9 @@ protected static function getSerializer() { // Otherwise, fallback to the Symfony implementation. static::$serializer = YamlSymfony::class; } + // Merge the tag callbacks from this proxy to the chosen serializer. - static::$serializer::setTagCallbacks(array_merge( - static::$serializer::getTagCallbacks(), - static::getTagCallbacks() - )); + static::mergeTagCallbacks(static::$serializer); } return static::$serializer; } diff --git a/core/lib/Drupal/Component/Serialization/YamlSymfony.php b/core/lib/Drupal/Component/Serialization/YamlSymfony.php index 2ea01d4ba2..ae6fce4f8b 100644 --- a/core/lib/Drupal/Component/Serialization/YamlSymfony.php +++ b/core/lib/Drupal/Component/Serialization/YamlSymfony.php @@ -45,12 +45,9 @@ public static function decode($raw) { } // Support Symfony 3.3 TaggedValue objects. - array_walk_recursive($data, function (&$value) { - if ($value instanceof TaggedValue) { - $callbacks = static::getTagCallbacks(); - $args = (array) $value->getValue(); - $tag = $value->getTag(); - return isset($callbacks[$tag]) ? $callbacks[$tag](...$args) : $args; + array_walk_recursive($data, function (&$item) { + if ($item instanceof TaggedValue) { + $item = static::executeTagCallback($item->getValue(), '!' . $item->getTag()); } }); diff --git a/core/lib/Drupal/Core/Serialization/Yaml.php b/core/lib/Drupal/Core/Serialization/Yaml.php index 1b089249cf..392b6fe86b 100644 --- a/core/lib/Drupal/Core/Serialization/Yaml.php +++ b/core/lib/Drupal/Core/Serialization/Yaml.php @@ -32,10 +32,7 @@ protected static function getSerializer() { // Merge the tag callbacks from this proxy to the chosen serializer. if (static::$serializer instanceof TaggedSerializationInterface) { - static::$serializer::setTagCallbacks(array_merge( - static::$serializer::getTagCallbacks(), - static::getTagCallbacks() - )); + static::mergeTagCallbacks(static::$serializer); } } return parent::getSerializer();