PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Config/Yaml.php

https://bitbucket.org/Ebozavrik/test-application
PHP | 426 lines | 221 code | 49 blank | 156 comment | 40 complexity | 971e596b653a14cc44a958bc37f3e0cc MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Config
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Yaml.php 24807 2012-05-15 12:10:42Z adamlundrigan $
  20. */
  21. /**
  22. * @see Zend_Config
  23. */
  24. require_once 'Zend/Config.php';
  25. /**
  26. * YAML Adapter for Zend_Config
  27. *
  28. * @category Zend
  29. * @package Zend_Config
  30. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_Config_Yaml extends Zend_Config
  34. {
  35. /**
  36. * Attribute name that indicates what section a config extends from
  37. */
  38. const EXTENDS_NAME = "_extends";
  39. /**
  40. * Whether to skip extends or not
  41. *
  42. * @var boolean
  43. */
  44. protected $_skipExtends = false;
  45. /**
  46. * What to call when we need to decode some YAML?
  47. *
  48. * @var callable
  49. */
  50. protected $_yamlDecoder = array( __CLASS__, 'decode' );
  51. /**
  52. * Whether or not to ignore constants in parsed YAML
  53. * @var bool
  54. */
  55. protected static $_ignoreConstants = false;
  56. /**
  57. * Indicate whether parser should ignore constants or not
  58. *
  59. * @param bool $flag
  60. *
  61. * @return void
  62. */
  63. public static function setIgnoreConstants ($flag)
  64. {
  65. self::$_ignoreConstants = (bool)$flag;
  66. }
  67. /**
  68. * Whether parser should ignore constants or not
  69. *
  70. * @return bool
  71. */
  72. public static function ignoreConstants ()
  73. {
  74. return self::$_ignoreConstants;
  75. }
  76. /**
  77. * Get callback for decoding YAML
  78. *
  79. * @return callable
  80. */
  81. public function getYamlDecoder ()
  82. {
  83. return $this->_yamlDecoder;
  84. }
  85. /**
  86. * Set callback for decoding YAML
  87. *
  88. * @param callable $yamlDecoder the decoder to set
  89. *
  90. * @return Zend_Config_Yaml
  91. */
  92. public function setYamlDecoder ($yamlDecoder)
  93. {
  94. if (!is_callable($yamlDecoder)) {
  95. require_once 'Zend/Config/Exception.php';
  96. throw new Zend_Config_Exception( 'Invalid parameter to setYamlDecoder() - must be callable' );
  97. }
  98. $this->_yamlDecoder = $yamlDecoder;
  99. return $this;
  100. }
  101. /**
  102. * Loads the section $section from the config file encoded as YAML
  103. *
  104. * Sections are defined as properties of the main object
  105. *
  106. * In order to extend another section, a section defines the "_extends"
  107. * property having a value of the section name from which the extending
  108. * section inherits values.
  109. *
  110. * Note that the keys in $section will override any keys of the same
  111. * name in the sections that have been included via "_extends".
  112. *
  113. * Options may include:
  114. * - allow_modifications: whether or not the config object is mutable
  115. * - skip_extends: whether or not to skip processing of parent configuration
  116. * - yaml_decoder: a callback to use to decode the Yaml source
  117. *
  118. * @param string $yaml YAML file to process
  119. * @param mixed $section Section to process
  120. * @param array|boolean $options
  121. */
  122. public function __construct ($yaml, $section = null, $options = false)
  123. {
  124. if (empty( $yaml )) {
  125. require_once 'Zend/Config/Exception.php';
  126. throw new Zend_Config_Exception( 'Filename is not set' );
  127. }
  128. $ignoreConstants = $staticIgnoreConstants = self::ignoreConstants();
  129. $allowModifications = false;
  130. if (is_bool($options)) {
  131. $allowModifications = $options;
  132. } elseif (is_array($options)) {
  133. foreach ($options as $key => $value) {
  134. switch (strtolower($key)) {
  135. case 'allow_modifications':
  136. case 'allowmodifications':
  137. $allowModifications = (bool)$value;
  138. break;
  139. case 'skip_extends':
  140. case 'skipextends':
  141. $this->_skipExtends = (bool)$value;
  142. break;
  143. case 'ignore_constants':
  144. case 'ignoreconstants':
  145. $ignoreConstants = (bool)$value;
  146. break;
  147. case 'yaml_decoder':
  148. case 'yamldecoder':
  149. $this->setYamlDecoder($value);
  150. break;
  151. default:
  152. break;
  153. }
  154. }
  155. }
  156. // Suppress warnings and errors while loading file
  157. set_error_handler(array( $this, '_loadFileErrorHandler' ));
  158. $yaml = file_get_contents($yaml);
  159. restore_error_handler();
  160. // Check if there was a error while loading file
  161. if ($this->_loadFileErrorStr !== null) {
  162. require_once 'Zend/Config/Exception.php';
  163. throw new Zend_Config_Exception( $this->_loadFileErrorStr );
  164. }
  165. // Override static value for ignore_constants if provided in $options
  166. self::setIgnoreConstants($ignoreConstants);
  167. // Parse YAML
  168. $config = call_user_func($this->getYamlDecoder(), $yaml);
  169. // Reset original static state of ignore_constants
  170. self::setIgnoreConstants($staticIgnoreConstants);
  171. if (null === $config) {
  172. // decode failed
  173. require_once 'Zend/Config/Exception.php';
  174. throw new Zend_Config_Exception( "Error parsing YAML data" );
  175. }
  176. if (null === $section) {
  177. $dataArray = array();
  178. foreach ($config as $sectionName => $sectionData) {
  179. $dataArray[$sectionName] = $this->_processExtends($config, $sectionName);
  180. }
  181. parent::__construct($dataArray, $allowModifications);
  182. } elseif (is_array($section)) {
  183. $dataArray = array();
  184. foreach ($section as $sectionName) {
  185. if (!isset( $config[$sectionName] )) {
  186. require_once 'Zend/Config/Exception.php';
  187. throw new Zend_Config_Exception( sprintf(
  188. 'Section "%s" cannot be found',
  189. implode(' ', (array)$section)
  190. ) );
  191. }
  192. $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray);
  193. }
  194. parent::__construct($dataArray, $allowModifications);
  195. } else {
  196. if (!isset( $config[$section] )) {
  197. require_once 'Zend/Config/Exception.php';
  198. throw new Zend_Config_Exception( sprintf(
  199. 'Section "%s" cannot be found',
  200. implode(' ', (array)$section)
  201. ) );
  202. }
  203. $dataArray = $this->_processExtends($config, $section);
  204. if (!is_array($dataArray)) {
  205. // Section in the yaml data contains just one top level string
  206. $dataArray = array( $section => $dataArray );
  207. }
  208. parent::__construct($dataArray, $allowModifications);
  209. }
  210. $this->_loadedSection = $section;
  211. }
  212. /**
  213. * Helper function to process each element in the section and handle
  214. * the "_extends" inheritance attribute.
  215. *
  216. * @param array $data Data array to process
  217. * @param string $section Section to process
  218. * @param array $config Configuration which was parsed yet
  219. *
  220. * @return array
  221. * @throws Zend_Config_Exception When $section cannot be found
  222. */
  223. protected function _processExtends (array $data, $section, array $config = array())
  224. {
  225. if (!isset( $data[$section] )) {
  226. require_once 'Zend/Config/Exception.php';
  227. throw new Zend_Config_Exception( sprintf('Section "%s" cannot be found', $section) );
  228. }
  229. $thisSection = $data[$section];
  230. if (is_array($thisSection) && isset( $thisSection[self::EXTENDS_NAME] )) {
  231. $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]);
  232. if (!$this->_skipExtends) {
  233. $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config);
  234. }
  235. unset( $thisSection[self::EXTENDS_NAME] );
  236. }
  237. $config = $this->_arrayMergeRecursive($config, $thisSection);
  238. return $config;
  239. }
  240. /**
  241. * Very dumb YAML parser
  242. *
  243. * Until we have Zend_Yaml...
  244. *
  245. * @param string $yaml YAML source
  246. *
  247. * @return array Decoded data
  248. */
  249. public static function decode ($yaml)
  250. {
  251. $lines = explode("\n", $yaml);
  252. reset($lines);
  253. return self::_decodeYaml(0, $lines);
  254. }
  255. /**
  256. * Service function to decode YAML
  257. *
  258. * @param int $currentIndent Current indent level
  259. * @param array $lines YAML lines
  260. *
  261. * @return array|string
  262. */
  263. protected static function _decodeYaml ($currentIndent, &$lines)
  264. {
  265. $config = array();
  266. $inIndent = false;
  267. while (list( $n, $line ) = each($lines)) {
  268. $lineno = $n + 1;
  269. $line = rtrim(preg_replace("/#.*$/", "", $line));
  270. if (strlen($line) == 0) {
  271. continue;
  272. }
  273. $indent = strspn($line, " ");
  274. // line without the spaces
  275. $line = trim($line);
  276. if (strlen($line) == 0) {
  277. continue;
  278. }
  279. if ($indent < $currentIndent) {
  280. // this level is done
  281. prev($lines);
  282. return $config;
  283. }
  284. if (!$inIndent) {
  285. $currentIndent = $indent;
  286. $inIndent = true;
  287. }
  288. if (preg_match("/(?!-)([\w\-]+):\s*(.*)/", $line, $m)) {
  289. // key: value
  290. if (strlen($m[2])) {
  291. // simple key: value
  292. $value = preg_replace("/#.*$/", "", $m[2]);
  293. $value = self::_parseValue($value);
  294. } else {
  295. // key: and then values on new lines
  296. $value = self::_decodeYaml($currentIndent + 1, $lines);
  297. if (is_array($value) && !count($value)) {
  298. $value = "";
  299. }
  300. }
  301. $config[$m[1]] = $value;
  302. } elseif ($line[0] == "-") {
  303. // item in the list:
  304. // - FOO
  305. if (strlen($line) > 2) {
  306. $value = substr($line, 2);
  307. $config[] = self::_parseValue($value);
  308. } else {
  309. $config[] = self::_decodeYaml($currentIndent + 1, $lines);
  310. }
  311. } else {
  312. require_once 'Zend/Config/Exception.php';
  313. throw new Zend_Config_Exception( sprintf(
  314. 'Error parsing YAML at line %d - unsupported syntax: "%s"',
  315. $lineno, $line
  316. ) );
  317. }
  318. }
  319. return $config;
  320. }
  321. /**
  322. * Parse values
  323. *
  324. * @param string $value
  325. *
  326. * @return string
  327. */
  328. protected static function _parseValue ($value)
  329. {
  330. $value = trim($value);
  331. // remove quotes from string.
  332. if ('"' == $value['0']) {
  333. if ('"' == $value[count($value) - 1]) {
  334. $value = substr($value, 1, -1);
  335. }
  336. } elseif ('\'' == $value['0'] && '\'' == $value[count($value) - 1]) {
  337. $value = strtr($value, array( "''" => "'", "'" => '' ));
  338. }
  339. // Check for booleans and constants
  340. if (preg_match('/^(t(rue)?|on|y(es)?)$/i', $value)) {
  341. $value = true;
  342. } elseif (preg_match('/^(f(alse)?|off|n(o)?)$/i', $value)) {
  343. $value = false;
  344. } elseif (!self::$_ignoreConstants) {
  345. // test for constants
  346. $value = self::_replaceConstants($value);
  347. }
  348. return $value;
  349. }
  350. /**
  351. * Replace any constants referenced in a string with their values
  352. *
  353. * @param string $value
  354. *
  355. * @return string
  356. */
  357. protected static function _replaceConstants ($value)
  358. {
  359. foreach (self::_getConstants() as $constant) {
  360. if (strstr($value, $constant)) {
  361. $value = str_replace($constant, constant($constant), $value);
  362. }
  363. }
  364. return $value;
  365. }
  366. /**
  367. * Get (reverse) sorted list of defined constant names
  368. *
  369. * @return array
  370. */
  371. protected static function _getConstants ()
  372. {
  373. $constants = array_keys(get_defined_constants());
  374. rsort($constants, SORT_STRING);
  375. return $constants;
  376. }
  377. }