Commit b390475f authored by webchick's avatar webchick

Issue #2208633 by sun: Add a Yaml class to Drupal\Component\Serialization.

parent 26817505
......@@ -9,6 +9,8 @@
*/
use Drupal\Component\Serialization\Json;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Number;
use Drupal\Component\Utility\Settings;
......@@ -21,8 +23,6 @@
use Drupal\Core\Language\Language;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Exception\ParseException;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Datetime\DrupalDateTime;
......
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\Core\Discovery\DiscoverableInterface.
* Contains \Drupal\Component\Discovery\DiscoverableInterface.
*/
namespace Drupal\Component\Discovery;
......
......@@ -7,7 +7,7 @@
namespace Drupal\Component\Discovery;
use Symfony\Component\Yaml\Parser;
use Drupal\Component\Serialization\Yaml;
/**
* Provides discovery for YAML files within a given set of directories.
......@@ -28,13 +28,6 @@ class YamlDiscovery implements DiscoverableInterface {
*/
protected $directories = array();
/**
* The symfony YAML parser.
*
* @var \Symfony\Component\Yaml\Parser
*/
protected $parser;
/**
* Constructs a YamlDiscovery object.
*
......@@ -54,28 +47,13 @@ public function __construct($name, array $directories) {
*/
public function findAll() {
$all = array();
$parser = $this->parser();
foreach ($this->findFiles() as $provider => $file) {
$all[$provider] = $parser->parse(file_get_contents($file));
$all[$provider] = Yaml::decode(file_get_contents($file));
}
return $all;
}
/**
* Returns the YAML parser.
*
* @return \Symfony\Component\Yaml\Parser
* The symfony YAML parser.
*/
protected function parser() {
if (!isset($this->parser)) {
$this->parser = new Parser();
}
return $this->parser;
}
/**
* Returns an array of file paths, keyed by provider.
*
......
<?php
/**
* @file
* Contains \Drupal\Component\Serialization\Exception\InvalidDataTypeException.
*/
namespace Drupal\Component\Serialization\Exception;
/**
* Exception thrown when a data type is invalid.
*/
class InvalidDataTypeException extends \InvalidArgumentException {
}
<?php
/**
* @file
* Contains \Drupal\Component\Serialization\SerializationInterface.
*/
namespace Drupal\Component\Serialization;
/**
* Defines an interface for serialization formats.
*/
interface SerializationInterface {
/**
* Encodes data into the serialization format.
*
* @param mixed $data
* The data to encode.
*
* @return string
* The encoded data.
*/
public static function encode($data);
/**
* Decodes data from the serialization format.
*
* @param string $raw
* The raw data string to decode.
*
* @return mixed
* The decoded data.
*/
public static function decode($raw);
/**
* Returns the file extension for this serialization format.
*
* @return string
* The file extension, without leading dot.
*/
public static function getFileExtension();
}
<?php
/**
* @file
* Contains \Drupal\Component\Serialization\Yaml.
*/
namespace Drupal\Component\Serialization;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Symfony\Component\Yaml\Yaml as Symfony;
/**
* Default serialization for YAML using the Symfony component.
*/
class Yaml implements SerializationInterface {
/**
* {@inheritdoc}
*/
public static function encode($data) {
try {
return Symfony::dump($data, PHP_INT_MAX, 2, TRUE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public static function decode($raw) {
try {
return Symfony::parse($raw, TRUE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public static function getFileExtension() {
return 'yml';
}
}
......@@ -7,15 +7,14 @@
namespace Drupal\Core\Asset;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException;
use Drupal\Core\Asset\Exception\InvalidLibraryFileException;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
/**
* Discovers available asset libraries in Drupal.
......@@ -299,12 +298,11 @@ protected function fileValidUri($source) {
* Thrown when a parser exception got thrown.
*/
protected function parseLibraryInfo($extension, $library_file) {
$parser = new Parser();
try {
$this->libraries[$extension] = $parser->parse(file_get_contents(DRUPAL_ROOT . '/' . $library_file));
$this->libraries[$extension] = Yaml::decode(file_get_contents(DRUPAL_ROOT . '/' . $library_file));
}
catch (ParseException $e) {
// Rethrow a more helpful exception, since ParseException lacks context.
catch (InvalidDataTypeException $e) {
// Rethrow a more helpful exception to provide context.
throw new InvalidLibraryFileException(sprintf('Invalid library definition in %s: %s', $library_file, $e->getMessage()), 0, $e);
}
// Allow modules to alter the module's registered libraries.
......
......@@ -7,11 +7,11 @@
namespace Drupal\Core\Config;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\Yaml\Dumper;
/**
* The ConfigManager provides helper functions for the configuration system.
......@@ -111,11 +111,8 @@ public function diff(StorageInterface $source_storage, StorageInterface $target_
// The output should show configuration object differences formatted as YAML.
// But the configuration is not necessarily stored in files. Therefore, they
// need to be read and parsed, and lastly, dumped into YAML strings.
$dumper = new Dumper();
$dumper->setIndentation(2);
$source_data = explode("\n", $dumper->dump($source_storage->read($source_name), PHP_INT_MAX));
$target_data = explode("\n", $dumper->dump($target_storage->read($target_name), PHP_INT_MAX));
$source_data = explode("\n", Yaml::encode($source_storage->read($source_name)));
$target_data = explode("\n", Yaml::encode($target_storage->read($target_name)));
// Check for new or removed files.
if ($source_data === array('false')) {
......
......@@ -7,10 +7,9 @@
namespace Drupal\Core\Config;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Component\Utility\String;
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Parser;
/**
* Defines the file storage.
......@@ -24,20 +23,6 @@ class FileStorage implements StorageInterface {
*/
protected $directory = '';
/**
* A shared YAML dumper instance.
*
* @var \Symfony\Component\Yaml\Dumper
*/
protected $dumper;
/**
* A shared YAML parser instance.
*
* @var \Symfony\Component\Yaml\Parser
*/
protected $parser;
/**
* Constructs a new FileStorage.
*
......@@ -90,16 +75,22 @@ public function exists($name) {
/**
* Implements Drupal\Core\Config\StorageInterface::read().
*
* @throws Symfony\Component\Yaml\Exception\ParseException
* @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException
*/
public function read($name) {
if (!$this->exists($name)) {
return FALSE;
}
$data = file_get_contents($this->getFilePath($name));
// @todo Yaml throws a ParseException on invalid data. Is it expected to be
// caught or not?
$data = $this->decode($data);
try {
$data = $this->decode($data);
}
catch (InvalidDataTypeException $e) {
throw new UnsupportedDataTypeConfigException(String::format('Invalid data type in config @name: !message', array(
'@name' => $name,
'!message' => $e->getMessage(),
)));
}
return $data;
}
......@@ -123,8 +114,11 @@ public function write($name, array $data) {
try {
$data = $this->encode($data);
}
catch(DumpException $e) {
throw new StorageException(String::format('Invalid data type for used in config: @name', array('@name' => $name)));
catch (InvalidDataTypeException $e) {
throw new StorageException(String::format('Invalid data type in config @name: !message', array(
'@name' => $name,
'!message' => $e->getMessage(),
)));
}
$target = $this->getFilePath($name);
......@@ -167,52 +161,18 @@ public function rename($name, $new_name) {
return TRUE;
}
/**
* Gets the YAML dumper instance.
*
* @return Symfony\Component\Yaml\Dumper
*/
protected function getDumper() {
if (!isset($this->dumper)) {
$this->dumper = new Dumper();
// Set Yaml\Dumper's default indentation for nested nodes/collections to
// 2 spaces for consistency with Drupal coding standards.
$this->dumper->setIndentation(2);
}
return $this->dumper;
}
/**
* Gets the YAML parser instance.
*
* @return Symfony\Component\Yaml\Parser
*/
protected function getParser() {
if (!isset($this->parser)) {
$this->parser = new Parser();
}
return $this->parser;
}
/**
* Implements Drupal\Core\Config\StorageInterface::encode().
*
* @throws Symfony\Component\Yaml\Exception\DumpException
*/
public function encode($data) {
// The level where you switch to inline YAML is set to PHP_INT_MAX to ensure
// this does not occur. Also set the exceptionOnInvalidType parameter to
// TRUE, so exceptions are thrown for an invalid data type.
return $this->getDumper()->dump($data, PHP_INT_MAX, 0, TRUE);
return Yaml::encode($data);
}
/**
* Implements Drupal\Core\Config\StorageInterface::decode().
*
* @throws Symfony\Component\Yaml\Exception\ParseException
*/
public function decode($raw) {
$data = $this->getParser()->parse($raw);
$data = Yaml::decode($raw);
// A simple string is valid YAML for any reason.
if (!is_array($data)) {
return FALSE;
......
......@@ -7,12 +7,12 @@
namespace Drupal\Core\DependencyInjection;
use Drupal\Component\Serialization\Yaml;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Yaml\Parser;
/**
* YamlFileLoader loads YAML files service definitions.
......@@ -194,8 +194,7 @@ protected function parseDefinition($id, $service, $filename) {
* The file content.
*/
protected function loadFile($filename) {
$parser = new Parser();
return $this->validate($parser->parse(file_get_contents($filename)), $filename);
return $this->validate(Yaml::decode(file_get_contents($filename)), $filename);
}
/**
......
......@@ -7,9 +7,9 @@
namespace Drupal\Core\Extension;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Component\Utility\String;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
/**
* Parses extension .info.yml files.
......@@ -23,13 +23,6 @@ class InfoParser implements InfoParserInterface {
*/
protected static $parsedInfos = array();
/**
* Symfony YAML parser object.
*
* @var \Symfony\Component\Yaml\Parser
*/
protected $parser;
/**
* {@inheritdoc}
*/
......@@ -40,16 +33,16 @@ public function parse($filename) {
}
else {
try {
static::$parsedInfos[$filename] = $this->getParser()->parse(file_get_contents($filename));
static::$parsedInfos[$filename] = Yaml::decode(file_get_contents($filename));
}
catch (ParseException $e) {
$message = String::format("Unable to parse !file. Parser error !error.", array('!file' => $filename, '!error' => $e->getMessage()));
throw new InfoParserException($message, $filename);
catch (InvalidDataTypeException $e) {
$message = String::format("Unable to parse !file: !error", array('!file' => $filename, '!error' => $e->getMessage()));
throw new InfoParserException($message);
}
$missing_keys = array_diff($this->getRequiredKeys(), array_keys(static::$parsedInfos[$filename]));
if (!empty($missing_keys)) {
$message = format_plural(count($missing_keys), 'Missing required key (!missing_keys) in !file.', 'Missing required keys (!missing_keys) in !file.', array('!missing_keys' => implode(', ', $missing_keys), '!file' => $filename));
throw new InfoParserException($message, $filename);
throw new InfoParserException($message);
}
if (isset(static::$parsedInfos[$filename]['version']) && static::$parsedInfos[$filename]['version'] === 'VERSION') {
static::$parsedInfos[$filename]['version'] = \Drupal::VERSION;
......@@ -59,19 +52,6 @@ public function parse($filename) {
return static::$parsedInfos[$filename];
}
/**
* Returns a parser for parsing .info.yml files.
*
* @return \Symfony\Component\Yaml\Parser
* Symfony YAML parser object.
*/
protected function getParser() {
if (!$this->parser) {
$this->parser = new Parser();
}
return $this->parser;
}
/**
* Returns an array of keys required to exist in .info.yml file.
*
......
......@@ -10,35 +10,4 @@
* An exception thrown by the InfoParser class whilst parsing info.yml files.
*/
class InfoParserException extends \RuntimeException {
/**
* The info.yml filename.
*
* @var string
*/
protected $infoFilename;
/**
* Constructs the InfoParserException object.
*
* @param string $message
* The Exception message to throw.
* @param string $filename
* The info.yml filename.
*/
public function __construct($message, $info_filename) {
$this->infoFilename = $info_filename;
parent::__construct($message);
}
/**
* Gets the info.yml filename.
*
* @return string
* The info.yml filename.
*/
public function getInfoFilename () {
return $this->infoFilename;
}
}
......@@ -8,7 +8,7 @@
namespace Drupal\Core\Extension;
use Drupal\Component\Graph\Graph;
use Symfony\Component\Yaml\Parser;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\CacheBackendInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -939,8 +939,7 @@ protected function removeCacheBins($module) {
// Remove any cache bins defined by a module.
$service_yaml_file = drupal_get_path('module', $module) . "/$module.services.yml";
if (file_exists($service_yaml_file)) {
$parser = new Parser;
$definitions = $parser->parse(file_get_contents($service_yaml_file));
$definitions = Yaml::decode(file_get_contents($service_yaml_file));
if (isset($definitions['services'])) {
foreach ($definitions['services'] as $id => $definition) {
if (isset($definition['tags'])) {
......
......@@ -8,11 +8,11 @@
namespace Drupal\config\Controller;
use Drupal\Component\Archiver\ArchiveTar;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\system\FileDownloadController;
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
......@@ -84,12 +84,9 @@ public function __construct(StorageInterface $target_storage, StorageInterface $
public function downloadExport() {
file_unmanaged_delete(file_directory_temp() . '/config.tar.gz');
$dumper = new Dumper();
$dumper->setIndentation(2);
$archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz');
foreach (\Drupal::service('config.storage')->listAll() as $name) {
$archiver->addString("$name.yml", $dumper->dump(\Drupal::config($name)->get(), PHP_INT_MAX, 0, TRUE));
$archiver->addString("$name.yml", Yaml::encode(\Drupal::config($name)->get()));
}
$request = new Request(array('file' => 'config.tar.gz'));
......
......@@ -7,12 +7,12 @@
namespace Drupal\config\Form;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Yaml\Dumper;
/**
* Provides a form for exporting a single configuration file.
......@@ -33,13 +33,6 @@ class ConfigSingleExportForm extends FormBase {
*/
protected $configStorage;
/**
* The YAML dumper.
*
* @var \Symfony\Component\Yaml\Dumper
*/
protected $dumper;
/**
* Tracks the valid config entity type definitions.
*
......@@ -54,14 +47,10 @@ class ConfigSingleExportForm extends FormBase {
* The entity manager.
* @param \Drupal\Core\Config\StorageInterface $config_storage
* The config storage.
* @param \Symfony\Component\Yaml\Dumper $dumper
* The yaml dumper.
*/
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage, Dumper $dumper) {
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) {
$this->entityManager = $entity_manager;
$this->configStorage = $config_storage;
$this->dumper = $dumper;
$this->dumper->setIndentation(2);
}
/**
......@@ -70,8 +59,7 @@ public function __construct(EntityManagerInterface $entity_manager, StorageInter
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('config.storage'),
new Dumper()
$container->get('config.storage')
);
}
......@@ -164,7 +152,7 @@ public function updateExport($form, &$form_state) {
$name = $form_state['values']['config_name'];
}
// Read the raw data for this config name, encode it, and display it.
$form['export']['#value'] = $this->dumper->dump($this->configStorage->read($name), PHP_INT_MAX);
$form['export']['#value'] = Yaml::encode($this->configStorage->read($name));
$form['export']['#description'] = $this->t('The filename is %name.', array('%name' => $name . '.yml'));
return $form['export'];
}
......
......@@ -7,11 +7,11 @@
namespace Drupal\config\Form;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Yaml\Yaml;
/**
* Provides a form for importing a single configuration file.
......@@ -32,13 +32,6 @@ class ConfigSingleImportForm extends ConfirmFormBase {
*/
protected $configStorage;
/**
* The YAML component.
*
* @var \Symfony\Component\Yaml\Yaml
*/
protected $yaml;
/**
* If the config exists, this is that object. Otherwise, FALSE.
*
......@@ -60,13 +53,10 @@ class ConfigSingleImportForm extends ConfirmFormBase {
* The entity manager.
* @param \Drupal\Core\Config\StorageInterface $config_storage
* The config storage.
* @param \Symfony\Component\Yaml\Yaml $yaml
* The YAML component.
*/
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage, Yaml $yaml) {
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) {
$this->entityManager = $entity_manager;
$this->configStorage = $config_storage;
$this->yaml = $yaml;
}
/**
......@@ -75,8 +65,7 @@ public function __construct(EntityManagerInterface $entity_manager, StorageInter
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('config.storage'),
new Yaml()
$container->get('config.storage')
);
}
......@@ -196,7 +185,7 @@ public function validateForm(array &$form, array &$form_state) {
}
// Decode the submitted import.
$data = $this->yaml->parse($form_state['values']['import']);