KXStudio Website https://kx.studio/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
6.5KB

  1. <?php
  2. /**
  3. * Horde YAML package
  4. *
  5. * This package is heavily inspired by the Spyc PHP YAML
  6. * implementation (http://spyc.sourceforge.net/), and portions are
  7. * copyright 2005-2006 Chris Wanstrath.
  8. *
  9. * @author Chris Wanstrath (chris@ozmm.org)
  10. * @author Chuck Hagenbuch (chuck@horde.org)
  11. * @author Mike Naberezny (mike@maintainable.com)
  12. * @license http://opensource.org/licenses/bsd-license.php BSD
  13. * @category Horde
  14. * @package Horde_Yaml
  15. */
  16. /**
  17. * Dump PHP data structures to YAML.
  18. *
  19. * @category Horde
  20. * @package Horde_Yaml
  21. */
  22. class Horde_Yaml_Dumper
  23. {
  24. protected $_options = array();
  25. /**
  26. * Dump PHP array to YAML
  27. *
  28. * The dump method, when supplied with an array, will do its best
  29. * to convert the array into valid YAML.
  30. *
  31. * Options:
  32. * `indent`:
  33. * number of spaces to indent children (default 2)
  34. * `wordwrap`:
  35. * wordwrap column number (default 40)
  36. *
  37. * @param array|Traversable $array PHP array or traversable object
  38. * @param integer $options Options for dumping
  39. * @return string YAML representation of $value
  40. */
  41. public function dump($value, $options = array())
  42. {
  43. // validate & merge default options
  44. if (!is_array($options)) {
  45. throw new InvalidArgumentException('Options must be an array');
  46. }
  47. $defaults = array('indent' => 2,
  48. 'wordwrap' => 0);
  49. $this->_options = array_merge($defaults, $options);
  50. if (! is_int($this->_options['indent'])) {
  51. throw new InvalidArgumentException('Indent must be an integer');
  52. }
  53. if (! is_int($this->_options['wordwrap'])) {
  54. throw new InvalidArgumentException('Wordwrap column must be an integer');
  55. }
  56. // new YAML document
  57. $dump = "---\n";
  58. // iterate through array and yamlize it
  59. foreach ($value as $key => $val) {
  60. $dump .= $this->_yamlize($key, $val, 0, ($value === array_values($value)));
  61. }
  62. return $dump;
  63. }
  64. /**
  65. * Attempts to convert a key / value array item to YAML
  66. *
  67. * @param string $key The name of the key
  68. * @param string|array $value The value of the item
  69. * @param integer $indent The indent of the current node
  70. * @param boolean $seq Is the item part of a sequence?
  71. * @return string
  72. */
  73. protected function _yamlize($key, $value, $indent, $seq = false)
  74. {
  75. if ($value instanceof Serializable) {
  76. // Dump serializable objects as !php/object::classname serialize_data
  77. $data = '!php/object::' . get_class($value) . ' ' . $value->serialize();
  78. $string = $this->_dumpNode($key, $data, $indent);
  79. } elseif (is_array($value) || $value instanceof Traversable) {
  80. // It has children. Make it the right kind of item.
  81. $string = $this->_dumpNode($key, null, $indent);
  82. // Add the indent.
  83. $indent += $this->_options['indent'];
  84. // Yamlize the array.
  85. $string .= $this->_yamlizeArray($value, $indent);
  86. } elseif (!is_array($value)) {
  87. // No children.
  88. $string = $this->_dumpNode($key, $value, $indent, $seq);
  89. }
  90. return $string;
  91. }
  92. /**
  93. * Attempts to convert an array to YAML
  94. *
  95. * @param array $array The array you want to convert
  96. * @param integer $indent The indent of the current level
  97. * @return string
  98. */
  99. protected function _yamlizeArray($array, $indent)
  100. {
  101. if (!is_array($array)) {
  102. return false;
  103. }
  104. $seq = ($array === array_values($array));
  105. $string = '';
  106. foreach ($array as $key => $value) {
  107. $string .= $this->_yamlize($key, $value, $indent, $seq);
  108. }
  109. return $string;
  110. }
  111. /**
  112. * Returns YAML from a key and a value
  113. *
  114. * @param string $key The name of the key
  115. * @param string $value The value of the item
  116. * @param integer $indent The indent of the current node
  117. * @param boolean $seq Is the item part of a sequence?
  118. * @return string
  119. */
  120. protected function _dumpNode($key, $value, $indent, $seq = false)
  121. {
  122. // Do some folding here, for blocks.
  123. if (strpos($value, "\n") !== false
  124. || strpos($value, ': ') !== false
  125. || strpos($value, '- ') !== false) {
  126. $value = $this->_doLiteralBlock($value, $indent);
  127. } else {
  128. $value = $this->_fold($value, $indent);
  129. }
  130. if (is_bool($value)) {
  131. $value = ($value) ? 'true' : 'false';
  132. } elseif (is_float($value)) {
  133. if (is_nan($value)) {
  134. $value = '.NAN';
  135. } elseif ($value === INF) {
  136. $value = '.INF';
  137. } elseif ($value === -INF) {
  138. $value = '-.INF';
  139. }
  140. }
  141. $spaces = str_repeat(' ', $indent);
  142. if ($seq) {
  143. // It's a sequence.
  144. $string = $spaces . '- ' . $value . "\n";
  145. } else {
  146. // It's mapped.
  147. $string = $spaces . $key . ': ' . $value . "\n";
  148. }
  149. return $string;
  150. }
  151. /**
  152. * Creates a literal block for dumping
  153. *
  154. * @param string $value
  155. * @param integer $indent The value of the indent.
  156. * @return string
  157. */
  158. protected function _doLiteralBlock($value, $indent)
  159. {
  160. $exploded = explode("\n", $value);
  161. $newValue = '|';
  162. $indent += $this->_options['indent'];
  163. $spaces = str_repeat(' ', $indent);
  164. foreach ($exploded as $line) {
  165. $newValue .= "\n" . $spaces . trim($line);
  166. }
  167. return $newValue;
  168. }
  169. /**
  170. * Folds a string of text, if necessary
  171. *
  172. * @param $value The string you wish to fold
  173. * @return string
  174. */
  175. protected function _fold($value, $indent)
  176. {
  177. // Don't do anything if wordwrap is set to 0
  178. if (! $this->_options['wordwrap']) {
  179. return (is_string($value) and !is_numeric($value) and !empty($value)) ? '"'.str_replace("\"", "\\\"", $value).'"' : $value ;
  180. }
  181. if (strlen($value) > $this->_options['wordwrap']) {
  182. $indent += $this->_options['indent'];
  183. $indent = str_repeat(' ', $indent);
  184. $wrapped = wordwrap($value, $this->_options['wordwrap'], "\n$indent");
  185. $value = ">\n" . $indent . $wrapped;
  186. }
  187. return $value;
  188. }
  189. }