PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/core/lib/Drupal/Core/Config/FileStorage.php

https://gitlab.com/reasonat/test8
PHP | 335 lines | 179 code | 29 blank | 127 comment | 30 complexity | fef8c2669963c59cfe4f84d62dffcfe5 MD5 | raw file
  1. <?php
  2. namespace Drupal\Core\Config;
  3. use Drupal\Component\Serialization\Yaml;
  4. use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
  5. /**
  6. * Defines the file storage.
  7. */
  8. class FileStorage implements StorageInterface {
  9. /**
  10. * The storage collection.
  11. *
  12. * @var string
  13. */
  14. protected $collection;
  15. /**
  16. * The filesystem path for configuration objects.
  17. *
  18. * @var string
  19. */
  20. protected $directory = '';
  21. /**
  22. * Constructs a new FileStorage.
  23. *
  24. * @param string $directory
  25. * A directory path to use for reading and writing of configuration files.
  26. * @param string $collection
  27. * (optional) The collection to store configuration in. Defaults to the
  28. * default collection.
  29. */
  30. public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
  31. $this->directory = $directory;
  32. $this->collection = $collection;
  33. }
  34. /**
  35. * Returns the path to the configuration file.
  36. *
  37. * @return string
  38. * The path to the configuration file.
  39. */
  40. public function getFilePath($name) {
  41. return $this->getCollectionDirectory() . '/' . $name . '.' . static::getFileExtension();
  42. }
  43. /**
  44. * Returns the file extension used by the file storage for all configuration files.
  45. *
  46. * @return string
  47. * The file extension.
  48. */
  49. public static function getFileExtension() {
  50. return 'yml';
  51. }
  52. /**
  53. * Check if the directory exists and create it if not.
  54. */
  55. protected function ensureStorage() {
  56. $dir = $this->getCollectionDirectory();
  57. $success = file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  58. // Only create .htaccess file in root directory.
  59. if ($dir == $this->directory) {
  60. $success = $success && file_save_htaccess($this->directory, TRUE, TRUE);
  61. }
  62. if (!$success) {
  63. throw new StorageException('Failed to create config directory ' . $dir);
  64. }
  65. return $this;
  66. }
  67. /**
  68. * {@inheritdoc}
  69. */
  70. public function exists($name) {
  71. return file_exists($this->getFilePath($name));
  72. }
  73. /**
  74. * Implements Drupal\Core\Config\StorageInterface::read().
  75. *
  76. * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException
  77. */
  78. public function read($name) {
  79. if (!$this->exists($name)) {
  80. return FALSE;
  81. }
  82. $filepath = $this->getFilePath($name);
  83. $data = file_get_contents($filepath);
  84. try {
  85. $data = $this->decode($data);
  86. }
  87. catch (InvalidDataTypeException $e) {
  88. throw new UnsupportedDataTypeConfigException('Invalid data type in config ' . $name . ', found in file' . $filepath . ' : ' . $e->getMessage());
  89. }
  90. return $data;
  91. }
  92. /**
  93. * {@inheritdoc}
  94. */
  95. public function readMultiple(array $names) {
  96. $list = array();
  97. foreach ($names as $name) {
  98. if ($data = $this->read($name)) {
  99. $list[$name] = $data;
  100. }
  101. }
  102. return $list;
  103. }
  104. /**
  105. * {@inheritdoc}
  106. */
  107. public function write($name, array $data) {
  108. try {
  109. $data = $this->encode($data);
  110. }
  111. catch (InvalidDataTypeException $e) {
  112. throw new StorageException("Invalid data type in config $name: {$e->getMessage()}");
  113. }
  114. $target = $this->getFilePath($name);
  115. $status = @file_put_contents($target, $data);
  116. if ($status === FALSE) {
  117. // Try to make sure the directory exists and try writing again.
  118. $this->ensureStorage();
  119. $status = @file_put_contents($target, $data);
  120. }
  121. if ($status === FALSE) {
  122. throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
  123. }
  124. else {
  125. drupal_chmod($target);
  126. }
  127. return TRUE;
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function delete($name) {
  133. if (!$this->exists($name)) {
  134. $dir = $this->getCollectionDirectory();
  135. if (!file_exists($dir)) {
  136. throw new StorageException($dir . '/ not found.');
  137. }
  138. return FALSE;
  139. }
  140. return drupal_unlink($this->getFilePath($name));
  141. }
  142. /**
  143. * {@inheritdoc}
  144. */
  145. public function rename($name, $new_name) {
  146. $status = @rename($this->getFilePath($name), $this->getFilePath($new_name));
  147. if ($status === FALSE) {
  148. throw new StorageException('Failed to rename configuration file from: ' . $this->getFilePath($name) . ' to: ' . $this->getFilePath($new_name));
  149. }
  150. return TRUE;
  151. }
  152. /**
  153. * {@inheritdoc}
  154. */
  155. public function encode($data) {
  156. return Yaml::encode($data);
  157. }
  158. /**
  159. * {@inheritdoc}
  160. */
  161. public function decode($raw) {
  162. $data = Yaml::decode($raw);
  163. // A simple string is valid YAML for any reason.
  164. if (!is_array($data)) {
  165. return FALSE;
  166. }
  167. return $data;
  168. }
  169. /**
  170. * {@inheritdoc}
  171. */
  172. public function listAll($prefix = '') {
  173. $dir = $this->getCollectionDirectory();
  174. if (!is_dir($dir)) {
  175. return array();
  176. }
  177. $extension = '.' . static::getFileExtension();
  178. // glob() directly calls into libc glob(), which is not aware of PHP stream
  179. // wrappers. Same for \GlobIterator (which additionally requires an absolute
  180. // realpath() on Windows).
  181. // @see https://github.com/mikey179/vfsStream/issues/2
  182. $files = scandir($dir);
  183. $names = array();
  184. $pattern = '/^' . preg_quote($prefix, '/') . '.*' . preg_quote($extension, '/') . '$/';
  185. foreach ($files as $file) {
  186. if ($file[0] !== '.' && preg_match($pattern, $file)) {
  187. $names[] = basename($file, $extension);
  188. }
  189. }
  190. return $names;
  191. }
  192. /**
  193. * {@inheritdoc}
  194. */
  195. public function deleteAll($prefix = '') {
  196. $success = TRUE;
  197. $files = $this->listAll($prefix);
  198. foreach ($files as $name) {
  199. if (!$this->delete($name) && $success) {
  200. $success = FALSE;
  201. }
  202. }
  203. if ($success && $this->collection != StorageInterface::DEFAULT_COLLECTION) {
  204. // Remove empty directories.
  205. if (!(new \FilesystemIterator($this->getCollectionDirectory()))->valid()) {
  206. drupal_rmdir($this->getCollectionDirectory());
  207. }
  208. }
  209. return $success;
  210. }
  211. /**
  212. * {@inheritdoc}
  213. */
  214. public function createCollection($collection) {
  215. return new static(
  216. $this->directory,
  217. $collection
  218. );
  219. }
  220. /**
  221. * {@inheritdoc}
  222. */
  223. public function getCollectionName() {
  224. return $this->collection;
  225. }
  226. /**
  227. * {@inheritdoc}
  228. */
  229. public function getAllCollectionNames() {
  230. $collections = $this->getAllCollectionNamesHelper($this->directory);
  231. sort($collections);
  232. return $collections;
  233. }
  234. /**
  235. * Helper function for getAllCollectionNames().
  236. *
  237. * If the file storage has the following subdirectory structure:
  238. * ./another_collection/one
  239. * ./another_collection/two
  240. * ./collection/sub/one
  241. * ./collection/sub/two
  242. * this function will return:
  243. * @code
  244. * array(
  245. * 'another_collection.one',
  246. * 'another_collection.two',
  247. * 'collection.sub.one',
  248. * 'collection.sub.two',
  249. * );
  250. * @endcode
  251. *
  252. * @param string $directory
  253. * The directory to check for sub directories. This allows this
  254. * function to be used recursively to discover all the collections in the
  255. * storage.
  256. *
  257. * @return array
  258. * A list of collection names contained within the provided directory.
  259. */
  260. protected function getAllCollectionNamesHelper($directory) {
  261. $collections = array();
  262. $pattern = '/\.' . preg_quote($this->getFileExtension(), '/') . '$/';
  263. foreach (new \DirectoryIterator($directory) as $fileinfo) {
  264. if ($fileinfo->isDir() && !$fileinfo->isDot()) {
  265. $collection = $fileinfo->getFilename();
  266. // Recursively call getAllCollectionNamesHelper() to discover if there
  267. // are subdirectories. Subdirectories represent a dotted collection
  268. // name.
  269. $sub_collections = $this->getAllCollectionNamesHelper($directory . '/' . $collection);
  270. if (!empty($sub_collections)) {
  271. // Build up the collection name by concatenating the subdirectory
  272. // names with the current directory name.
  273. foreach ($sub_collections as $sub_collection) {
  274. $collections[] = $collection . '.' . $sub_collection;
  275. }
  276. }
  277. // Check that the collection is valid by searching it for configuration
  278. // objects. A directory without any configuration objects is not a valid
  279. // collection.
  280. // @see \Drupal\Core\Config\FileStorage::listAll()
  281. foreach (scandir($directory . '/' . $collection) as $file) {
  282. if ($file[0] !== '.' && preg_match($pattern, $file)) {
  283. $collections[] = $collection;
  284. break;
  285. }
  286. }
  287. }
  288. }
  289. return $collections;
  290. }
  291. /**
  292. * Gets the directory for the collection.
  293. *
  294. * @return string
  295. * The directory for the collection.
  296. */
  297. protected function getCollectionDirectory() {
  298. if ($this->collection == StorageInterface::DEFAULT_COLLECTION) {
  299. $dir = $this->directory;
  300. }
  301. else {
  302. $dir = $this->directory . '/' . str_replace('.', '/', $this->collection);
  303. }
  304. return $dir;
  305. }
  306. }