/framework/Yaml/lib/Horde/Yaml/Dumper.php

https://github.com/ewandor/horde · PHP · 216 lines · 107 code · 24 blank · 85 comment · 19 complexity · ccddc56fb48c1aa19c841e81fc2c1f24 MD5 · raw file

  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://www.horde.org/licenses/bsd BSD
  13. * @category Horde
  14. * @package Yaml
  15. */
  16. /**
  17. * Dump PHP data structures to YAML.
  18. *
  19. * @category Horde
  20. * @package 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' => 40);
  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 => $value) {
  60. $dump .= $this->_yamlize($key, $value, 0);
  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. * @return string
  71. */
  72. protected function _yamlize($key, $value, $indent)
  73. {
  74. if ($value instanceof Serializable) {
  75. // Dump serializable objects as !php/object::classname serialize_data
  76. $data = '!php/object::' . get_class($value) . ' ' . $value->serialize();
  77. $string = $this->_dumpNode($key, $data, $indent);
  78. } elseif (is_array($value) || $value instanceof Traversable) {
  79. // It has children. Make it the right kind of item.
  80. $string = $this->_dumpNode($key, null, $indent);
  81. // Add the indent.
  82. $indent += $this->_options['indent'];
  83. // Yamlize the array.
  84. $string .= $this->_yamlizeArray($value, $indent);
  85. } elseif (!is_array($value)) {
  86. // No children.
  87. $string = $this->_dumpNode($key, $value, $indent);
  88. }
  89. return $string;
  90. }
  91. /**
  92. * Attempts to convert an array to YAML
  93. *
  94. * @param array $array The array you want to convert
  95. * @param integer $indent The indent of the current level
  96. * @return string
  97. */
  98. protected function _yamlizeArray($array, $indent)
  99. {
  100. if (!is_array($array)) {
  101. return false;
  102. }
  103. $string = '';
  104. foreach ($array as $key => $value) {
  105. $string .= $this->_yamlize($key, $value, $indent);
  106. }
  107. return $string;
  108. }
  109. /**
  110. * Returns YAML from a key and a value
  111. *
  112. * @param string $key The name of the key
  113. * @param string $value The value of the item
  114. * @param integer $indent The indent of the current node
  115. * @return string
  116. */
  117. protected function _dumpNode($key, $value, $indent)
  118. {
  119. $literal = false;
  120. // Do some folding here, for blocks.
  121. if (strpos($value, "\n") !== false
  122. || strpos($value, ': ') !== false
  123. || strpos($value, '- ') !== false) {
  124. $value = $this->_doLiteralBlock($value, $indent);
  125. $literal = true;
  126. } else {
  127. $value = $this->_fold($value, $indent);
  128. }
  129. if (is_bool($value)) {
  130. $value = ($value) ? 'true' : 'false';
  131. } elseif (is_float($value)) {
  132. if (is_nan($value)) {
  133. $value = '.NAN';
  134. } elseif ($value === INF) {
  135. $value = '.INF';
  136. } elseif ($value === -INF) {
  137. $value = '-.INF';
  138. }
  139. }
  140. $spaces = str_repeat(' ', $indent);
  141. // Quote strings if necessary, and not folded
  142. if (!$literal && strpos($value, "\n") === false && strchr($value, '#')) {
  143. $value = "'{$value}'";
  144. }
  145. if (is_int($key)) {
  146. // It's a sequence.
  147. $string = $spaces . '- ' . $value . "\n";
  148. } else {
  149. // It's mapped.
  150. $string = $spaces . $key . ': ' . $value . "\n";
  151. }
  152. return $string;
  153. }
  154. /**
  155. * Creates a literal block for dumping
  156. *
  157. * @param string $value
  158. * @param integer $indent The value of the indent.
  159. * @return string
  160. */
  161. protected function _doLiteralBlock($value, $indent)
  162. {
  163. $exploded = explode("\n", $value);
  164. $newValue = '|';
  165. $indent += $this->_options['indent'];
  166. $spaces = str_repeat(' ', $indent);
  167. foreach ($exploded as $line) {
  168. $newValue .= "\n" . $spaces . trim($line);
  169. }
  170. return $newValue;
  171. }
  172. /**
  173. * Folds a string of text, if necessary
  174. *
  175. * @param $value The string you wish to fold
  176. * @return string
  177. */
  178. protected function _fold($value, $indent)
  179. {
  180. // Don't do anything if wordwrap is set to 0
  181. if (! $this->_options['wordwrap']) {
  182. return $value;
  183. }
  184. if (strlen($value) > $this->_options['wordwrap']) {
  185. $indent += $this->_options['indent'];
  186. $indent = str_repeat(' ', $indent);
  187. $wrapped = wordwrap($value, $this->_options['wordwrap'], "\n$indent");
  188. $value = ">\n" . $indent . $wrapped;
  189. }
  190. return $value;
  191. }
  192. }