From c6c4e37684d1faf2163fbf713680b1c808edf84e Mon Sep 17 00:00:00 2001 From: Mark Carver Date: Wed, 17 Jul 2019 14:46:28 -0500 Subject: [PATCH] Issue #3068483 by markcarver: Automatically map !translate YAML tag to TranslatableMarkup Signed-off-by: Mark Carver --- .../TaggedSerializationInterface.php | 28 +++++++ .../TaggedSerializationTrait.php | 76 +++++++++++++++++++ .../Drupal/Component/Serialization/Yaml.php | 9 ++- .../Component/Serialization/YamlPecl.php | 17 ++++- .../Component/Serialization/YamlSymfony.php | 21 ++++- core/lib/Drupal/Core/Serialization/Yaml.php | 48 ++++++++++++ 6 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 core/lib/Drupal/Component/Serialization/TaggedSerializationInterface.php create mode 100644 core/lib/Drupal/Component/Serialization/TaggedSerializationTrait.php diff --git a/core/lib/Drupal/Component/Serialization/TaggedSerializationInterface.php b/core/lib/Drupal/Component/Serialization/TaggedSerializationInterface.php new file mode 100644 index 0000000000..361ea65bf5 --- /dev/null +++ b/core/lib/Drupal/Component/Serialization/TaggedSerializationInterface.php @@ -0,0 +1,28 @@ + '\Drupal\Component\Serialization\YamlPecl::applyBooleanCallbacks', - ]); + $data = yaml_parse($raw, 0, $ndocs, static::getTagCallbacks()); restore_error_handler(); return $data; } @@ -79,6 +79,15 @@ public static function getFileExtension() { return 'yml'; } + /** + * {@inheritdoc} + */ + public static function getTagCallbacks() { + return [ + YAML_BOOL_TAG => static::class . '::applyBooleanCallbacks', + ]; + } + /** * Applies callbacks after parsing to ignore 1.1 style booleans. * diff --git a/core/lib/Drupal/Component/Serialization/YamlSymfony.php b/core/lib/Drupal/Component/Serialization/YamlSymfony.php index d35e09cd48..ae6fce4f8b 100644 --- a/core/lib/Drupal/Component/Serialization/YamlSymfony.php +++ b/core/lib/Drupal/Component/Serialization/YamlSymfony.php @@ -5,12 +5,15 @@ use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Dumper; +use Symfony\Component\Yaml\Tag\TaggedValue; use Symfony\Component\Yaml\Yaml as SymfonyYaml; /** * Default serialization for YAML using the Symfony component. */ -class YamlSymfony implements SerializationInterface { +class YamlSymfony implements TaggedSerializationInterface { + + use TaggedSerializationTrait; /** * {@inheritdoc} @@ -34,7 +37,21 @@ public static function decode($raw) { $yaml = new Parser(); // Make sure we have a single trailing newline. A very simple config like // 'foo: bar' with no newline will fail to parse otherwise. - return $yaml->parse($raw, SymfonyYaml::PARSE_EXCEPTION_ON_INVALID_TYPE); + $data = $yaml->parse($raw, SymfonyYaml::PARSE_EXCEPTION_ON_INVALID_TYPE | SymfonyYaml::PARSE_CUSTOM_TAGS); + + $is_array = is_array($data); + if (!$is_array) { + $data = [$data]; + } + + // Support Symfony 3.3 TaggedValue objects. + array_walk_recursive($data, function (&$item) { + if ($item instanceof TaggedValue) { + $item = static::executeTagCallback($item->getValue(), '!' . $item->getTag()); + } + }); + + return $is_array ? $data : reset($data); } catch (\Exception $e) { throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e); diff --git a/core/lib/Drupal/Core/Serialization/Yaml.php b/core/lib/Drupal/Core/Serialization/Yaml.php index 566f8cad4c..392b6fe86b 100644 --- a/core/lib/Drupal/Core/Serialization/Yaml.php +++ b/core/lib/Drupal/Core/Serialization/Yaml.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Serialization; +use Drupal\Component\Serialization\TaggedSerializationInterface; use Drupal\Core\Site\Settings; use Drupal\Component\Serialization\Yaml as ComponentYaml; @@ -12,6 +13,13 @@ */ class Yaml extends ComponentYaml { + /** + * Translation Manager. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface + */ + protected static $translation; + /** * {@inheritdoc} */ @@ -21,8 +29,48 @@ protected static function getSerializer() { $class = Settings::get('yaml_parser_class')) { static::$serializer = $class; + + // Merge the tag callbacks from this proxy to the chosen serializer. + if (static::$serializer instanceof TaggedSerializationInterface) { + static::mergeTagCallbacks(static::$serializer); + } } return parent::getSerializer(); } + /** + * Retrieves the Translation Manager. + * + * @return \Drupal\Core\StringTranslation\TranslationInterface + * The Translation Manager. + */ + protected static function getTranslation() { + if (!isset(static::$translation)) { + static::$translation = \Drupal::translation(); + } + return static::$translation; + } + + /** + * {@inheritdoc} + */ + public static function getTagCallbacks() { + return [ + '!translate' => static::class . '::applyTranslateCallback', + ]; + } + + /** + * Callback for applying the !translate tag. + * + * @param mixed ... + * The arguments to pass to the Translation manager. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * A new TranslatableMarkup object. + */ + public static function applyTranslateCallback(...$args) { + return static::getTranslation()->translate(...$args); + } + } -- 2.22.0