PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/Guzzle/Service/AbstractConfigLoader.php

https://gitlab.com/x33n/ampache
PHP | 177 lines | 95 code | 22 blank | 60 comment | 15 complexity | fadda279693196ee2b060c08c690e85e MD5 | raw file
  1. <?php
  2. namespace Guzzle\Service;
  3. use Guzzle\Common\Exception\InvalidArgumentException;
  4. use Guzzle\Common\Exception\RuntimeException;
  5. /**
  6. * Abstract config loader
  7. */
  8. abstract class AbstractConfigLoader implements ConfigLoaderInterface
  9. {
  10. /** @var array Array of aliases for actual filenames */
  11. protected $aliases = array();
  12. /** @var array Hash of previously loaded filenames */
  13. protected $loadedFiles = array();
  14. /** @var array JSON error code mappings */
  15. protected static $jsonErrors = array(
  16. JSON_ERROR_NONE => 'JSON_ERROR_NONE - No errors',
  17. JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
  18. JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
  19. JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
  20. JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
  21. JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
  22. );
  23. public function load($config, array $options = array())
  24. {
  25. // Reset the array of loaded files because this is a new config
  26. $this->loadedFiles = array();
  27. if (is_string($config)) {
  28. $config = $this->loadFile($config);
  29. } elseif (!is_array($config)) {
  30. throw new InvalidArgumentException('Unknown type passed to configuration loader: ' . gettype($config));
  31. } else {
  32. $this->mergeIncludes($config);
  33. }
  34. return $this->build($config, $options);
  35. }
  36. /**
  37. * Add an include alias to the loader
  38. *
  39. * @param string $filename Filename to alias (e.g. _foo)
  40. * @param string $alias Actual file to use (e.g. /path/to/foo.json)
  41. *
  42. * @return self
  43. */
  44. public function addAlias($filename, $alias)
  45. {
  46. $this->aliases[$filename] = $alias;
  47. return $this;
  48. }
  49. /**
  50. * Remove an alias from the loader
  51. *
  52. * @param string $alias Alias to remove
  53. *
  54. * @return self
  55. */
  56. public function removeAlias($alias)
  57. {
  58. unset($this->aliases[$alias]);
  59. return $this;
  60. }
  61. /**
  62. * Perform the parsing of a config file and create the end result
  63. *
  64. * @param array $config Configuration data
  65. * @param array $options Options to use when building
  66. *
  67. * @return mixed
  68. */
  69. protected abstract function build($config, array $options);
  70. /**
  71. * Load a configuration file (can load JSON or PHP files that return an array when included)
  72. *
  73. * @param string $filename File to load
  74. *
  75. * @return array
  76. * @throws InvalidArgumentException
  77. * @throws RuntimeException when the JSON cannot be parsed
  78. */
  79. protected function loadFile($filename)
  80. {
  81. if (isset($this->aliases[$filename])) {
  82. $filename = $this->aliases[$filename];
  83. }
  84. switch (pathinfo($filename, PATHINFO_EXTENSION)) {
  85. case 'js':
  86. case 'json':
  87. $level = error_reporting(0);
  88. $json = file_get_contents($filename);
  89. error_reporting($level);
  90. if ($json === false) {
  91. $err = error_get_last();
  92. throw new InvalidArgumentException("Unable to open {$filename}: " . $err['message']);
  93. }
  94. $config = json_decode($json, true);
  95. // Throw an exception if there was an error loading the file
  96. if ($error = json_last_error()) {
  97. $message = isset(self::$jsonErrors[$error]) ? self::$jsonErrors[$error] : 'Unknown error';
  98. throw new RuntimeException("Error loading JSON data from {$filename}: ({$error}) - {$message}");
  99. }
  100. break;
  101. case 'php':
  102. if (!is_readable($filename)) {
  103. throw new InvalidArgumentException("Unable to open {$filename} for reading");
  104. }
  105. $config = require $filename;
  106. if (!is_array($config)) {
  107. throw new InvalidArgumentException('PHP files must return an array of configuration data');
  108. }
  109. break;
  110. default:
  111. throw new InvalidArgumentException('Unknown file extension: ' . $filename);
  112. }
  113. // Keep track of this file being loaded to prevent infinite recursion
  114. $this->loadedFiles[$filename] = true;
  115. // Merge include files into the configuration array
  116. $this->mergeIncludes($config, dirname($filename));
  117. return $config;
  118. }
  119. /**
  120. * Merges in all include files
  121. *
  122. * @param array $config Config data that contains includes
  123. * @param string $basePath Base path to use when a relative path is encountered
  124. *
  125. * @return array Returns the merged and included data
  126. */
  127. protected function mergeIncludes(&$config, $basePath = null)
  128. {
  129. if (!empty($config['includes'])) {
  130. foreach ($config['includes'] as &$path) {
  131. // Account for relative paths
  132. if ($path[0] != DIRECTORY_SEPARATOR && !isset($this->aliases[$path]) && $basePath) {
  133. $path = "{$basePath}/{$path}";
  134. }
  135. // Don't load the same files more than once
  136. if (!isset($this->loadedFiles[$path])) {
  137. $this->loadedFiles[$path] = true;
  138. $config = $this->mergeData($this->loadFile($path), $config);
  139. }
  140. }
  141. }
  142. }
  143. /**
  144. * Default implementation for merging two arrays of data (uses array_merge_recursive)
  145. *
  146. * @param array $a Original data
  147. * @param array $b Data to merge into the original and overwrite existing values
  148. *
  149. * @return array
  150. */
  151. protected function mergeData(array $a, array $b)
  152. {
  153. return array_merge_recursive($a, $b);
  154. }
  155. }