Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Component\Serialization;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
|
Chris@0
|
6
|
Chris@0
|
7 /**
|
Chris@0
|
8 * Provides default serialization for YAML using the PECL extension.
|
Chris@0
|
9 */
|
Chris@0
|
10 class YamlPecl implements SerializationInterface {
|
Chris@0
|
11
|
Chris@0
|
12 /**
|
Chris@0
|
13 * {@inheritdoc}
|
Chris@0
|
14 */
|
Chris@0
|
15 public static function encode($data) {
|
Chris@0
|
16 static $init;
|
Chris@0
|
17 if (!isset($init)) {
|
Chris@0
|
18 ini_set('yaml.output_indent', 2);
|
Chris@0
|
19 // Do not break lines at 80 characters.
|
Chris@0
|
20 ini_set('yaml.output_width', -1);
|
Chris@0
|
21 $init = TRUE;
|
Chris@0
|
22 }
|
Chris@0
|
23 return yaml_emit($data, YAML_UTF8_ENCODING, YAML_LN_BREAK);
|
Chris@0
|
24 }
|
Chris@0
|
25
|
Chris@0
|
26 /**
|
Chris@0
|
27 * {@inheritdoc}
|
Chris@0
|
28 */
|
Chris@0
|
29 public static function decode($raw) {
|
Chris@0
|
30 static $init;
|
Chris@0
|
31 if (!isset($init)) {
|
Chris@0
|
32 // Decode binary, since Symfony YAML parser encodes binary from 3.1
|
Chris@0
|
33 // onwards.
|
Chris@0
|
34 ini_set('yaml.decode_binary', 1);
|
Chris@0
|
35 // We never want to unserialize !php/object.
|
Chris@0
|
36 ini_set('yaml.decode_php', 0);
|
Chris@0
|
37 $init = TRUE;
|
Chris@0
|
38 }
|
Chris@0
|
39 // yaml_parse() will error with an empty value.
|
Chris@0
|
40 if (!trim($raw)) {
|
Chris@0
|
41 return NULL;
|
Chris@0
|
42 }
|
Chris@0
|
43 // @todo Use ErrorExceptions when https://drupal.org/node/1247666 is in.
|
Chris@0
|
44 // yaml_parse() will throw errors instead of raising an exception. Until
|
Chris@0
|
45 // such time as Drupal supports native PHP ErrorExceptions as the error
|
Chris@0
|
46 // handler, we need to temporarily set the error handler as ::errorHandler()
|
Chris@0
|
47 // and then restore it after decoding has occurred. This allows us to turn
|
Chris@0
|
48 // parsing errors into a throwable exception.
|
Chris@0
|
49 // @see Drupal\Component\Serialization\Exception\InvalidDataTypeException
|
Chris@14
|
50 // @see http://php.net/manual/class.errorexception.php
|
Chris@0
|
51 set_error_handler([__CLASS__, 'errorHandler']);
|
Chris@0
|
52 $ndocs = 0;
|
Chris@0
|
53 $data = yaml_parse($raw, 0, $ndocs, [
|
Chris@0
|
54 YAML_BOOL_TAG => '\Drupal\Component\Serialization\YamlPecl::applyBooleanCallbacks',
|
Chris@0
|
55 ]);
|
Chris@0
|
56 restore_error_handler();
|
Chris@0
|
57 return $data;
|
Chris@0
|
58 }
|
Chris@0
|
59
|
Chris@0
|
60 /**
|
Chris@0
|
61 * Handles errors for \Drupal\Component\Serialization\YamlPecl::decode().
|
Chris@0
|
62 *
|
Chris@0
|
63 * @param int $severity
|
Chris@0
|
64 * The severity level of the error.
|
Chris@0
|
65 * @param string $message
|
Chris@0
|
66 * The error message to display.
|
Chris@0
|
67 *
|
Chris@0
|
68 * @see \Drupal\Component\Serialization\YamlPecl::decode()
|
Chris@0
|
69 */
|
Chris@0
|
70 public static function errorHandler($severity, $message) {
|
Chris@0
|
71 restore_error_handler();
|
Chris@0
|
72 throw new InvalidDataTypeException($message, $severity);
|
Chris@0
|
73 }
|
Chris@0
|
74
|
Chris@0
|
75 /**
|
Chris@0
|
76 * {@inheritdoc}
|
Chris@0
|
77 */
|
Chris@0
|
78 public static function getFileExtension() {
|
Chris@0
|
79 return 'yml';
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 /**
|
Chris@0
|
83 * Applies callbacks after parsing to ignore 1.1 style booleans.
|
Chris@0
|
84 *
|
Chris@0
|
85 * @param mixed $value
|
Chris@0
|
86 * Value from YAML file.
|
Chris@0
|
87 * @param string $tag
|
Chris@0
|
88 * Tag that triggered the callback.
|
Chris@0
|
89 * @param int $flags
|
Chris@0
|
90 * Scalar entity style flags.
|
Chris@0
|
91 *
|
Chris@0
|
92 * @return string|bool
|
Chris@0
|
93 * FALSE, false, TRUE and true are returned as booleans, everything else is
|
Chris@0
|
94 * returned as a string.
|
Chris@0
|
95 */
|
Chris@0
|
96 public static function applyBooleanCallbacks($value, $tag, $flags) {
|
Chris@0
|
97 // YAML 1.1 spec dictates that 'Y', 'N', 'y' and 'n' are booleans. But, we
|
Chris@0
|
98 // want the 1.2 behavior, so we only consider 'false', 'FALSE', 'true' and
|
Chris@0
|
99 // 'TRUE' as booleans.
|
Chris@0
|
100 if (!in_array(strtolower($value), ['false', 'true'], TRUE)) {
|
Chris@0
|
101 return $value;
|
Chris@0
|
102 }
|
Chris@0
|
103 $map = [
|
Chris@0
|
104 'false' => FALSE,
|
Chris@0
|
105 'true' => TRUE,
|
Chris@0
|
106 ];
|
Chris@0
|
107 return $map[strtolower($value)];
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 }
|