Newer
Older
catch
committed
<?php
/**
* @file
* Contains \Drupal\Core\Config\FileStorage.
*/
catch
committed
namespace Drupal\Core\Config;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
catch
committed
/**
* Defines the file storage.
catch
committed
*/
class FileStorage implements StorageInterface {
catch
committed
/**
* The storage collection.
*
* @var string
*/
protected $collection;
catch
committed
/**
catch
committed
* The filesystem path for configuration objects.
catch
committed
*
catch
committed
* @var string
catch
committed
protected $directory = '';
/**
* Constructs a new FileStorage.
catch
committed
*
* @param string $directory
* A directory path to use for reading and writing of configuration files.
* @param string $collection
* (optional) The collection to store configuration in. Defaults to the
* default collection.
catch
committed
*/
public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
catch
committed
$this->directory = $directory;
$this->collection = $collection;
catch
committed
}
/**
* Returns the path to the configuration file.
catch
committed
*
* @return string
* The path to the configuration file.
catch
committed
*/
public function getFilePath($name) {
return $this->getCollectionDirectory() . '/' . $name . '.' . static::getFileExtension();
}
/**
* Returns the file extension used by the file storage for all configuration files.
*
* @return string
* The file extension.
*/
public static function getFileExtension() {
return 'yml';
catch
committed
}
Dries Buytaert
committed
/**
* Check if the directory exists and create it if not.
*/
protected function ensureStorage() {
$dir = $this->getCollectionDirectory();
$success = file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
// Only create .htaccess file in root directory.
if ($dir == $this->directory) {
$success = $success && file_save_htaccess($this->directory, TRUE, TRUE);
}
Dries Buytaert
committed
if (!$success) {
throw new StorageException('Failed to create config directory ' . $dir);
Dries Buytaert
committed
}
return $this;
}
catch
committed
/**
* {@inheritdoc}
public function exists($name) {
return file_exists($this->getFilePath($name));
}
/**
* Implements Drupal\Core\Config\StorageInterface::read().
catch
committed
*
* @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException
catch
committed
*/
public function read($name) {
if (!$this->exists($name)) {
return FALSE;
}
$data = file_get_contents($this->getFilePath($name));
try {
$data = $this->decode($data);
}
catch (InvalidDataTypeException $e) {
catch
committed
throw new UnsupportedDataTypeConfigException("Invalid data type in config $name: {$e->getMessage()}");
}
return $data;
catch
committed
}
/**
* {@inheritdoc}
*/
public function readMultiple(array $names) {
$list = array();
foreach ($names as $name) {
if ($data = $this->read($name)) {
$list[$name] = $data;
}
}
return $list;
}
catch
committed
/**
Dries Buytaert
committed
* {@inheritdoc}
catch
committed
*/
public function write($name, array $data) {
try {
$data = $this->encode($data);
}
catch (InvalidDataTypeException $e) {
catch
committed
throw new StorageException("Invalid data type in config $name: {$e->getMessage()}");
$target = $this->getFilePath($name);
$status = @file_put_contents($target, $data);
Dries Buytaert
committed
if ($status === FALSE) {
// Try to make sure the directory exists and try writing again.
Dries Buytaert
committed
$this->ensureStorage();
$status = @file_put_contents($target, $data);
}
if ($status === FALSE) {
throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
}
else {
drupal_chmod($target);
}
return TRUE;
catch
committed
}
/**
* {@inheritdoc}
catch
committed
*/
public function delete($name) {
if (!$this->exists($name)) {
$dir = $this->getCollectionDirectory();
if (!file_exists($dir)) {
throw new StorageException($dir . '/ not found.');
}
return FALSE;
}
return drupal_unlink($this->getFilePath($name));
catch
committed
}
/**
* {@inheritdoc}
*/
public function rename($name, $new_name) {
$status = @rename($this->getFilePath($name), $this->getFilePath($new_name));
if ($status === FALSE) {
throw new StorageException('Failed to rename configuration file from: ' . $this->getFilePath($name) . ' to: ' . $this->getFilePath($new_name));
}
return TRUE;
}
* {@inheritdoc}
public function encode($data) {
return Yaml::encode($data);
}
/**
* {@inheritdoc}
public function decode($raw) {
$data = Yaml::decode($raw);
// A simple string is valid YAML for any reason.
if (!is_array($data)) {
return FALSE;
return $data;
}
/**
* {@inheritdoc}
*/
public function listAll($prefix = '') {
$dir = $this->getCollectionDirectory();
if (!is_dir($dir)) {
Dries Buytaert
committed
return array();
}
$extension = '.' . static::getFileExtension();
// glob() directly calls into libc glob(), which is not aware of PHP stream
// wrappers. Same for \GlobIterator (which additionally requires an absolute
// realpath() on Windows).
// @see https://github.com/mikey179/vfsStream/issues/2
$files = scandir($dir);
Angie Byron
committed
$names = array();
foreach ($files as $file) {
if ($file[0] !== '.' && fnmatch($prefix . '*' . $extension, $file)) {
$names[] = basename($file, $extension);
}
Angie Byron
committed
}
return $names;
catch
committed
/**
* {@inheritdoc}
catch
committed
*/
public function deleteAll($prefix = '') {
$success = TRUE;
$files = $this->listAll($prefix);
foreach ($files as $name) {
if (!$this->delete($name) && $success) {
$success = FALSE;
}
}
if ($success && $this->collection != StorageInterface::DEFAULT_COLLECTION) {
// Remove empty directories.
if (!(new \FilesystemIterator($this->getCollectionDirectory()))->valid()) {
drupal_rmdir($this->getCollectionDirectory());
}
}
catch
committed
return $success;
}
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/**
* {@inheritdoc}
*/
public function createCollection($collection) {
return new static(
$this->directory,
$collection
);
}
/**
* {@inheritdoc}
*/
public function getCollectionName() {
return $this->collection;
}
/**
* {@inheritdoc}
*/
public function getAllCollectionNames() {
$collections = $this->getAllCollectionNamesHelper($this->directory);
sort($collections);
return $collections;
}
/**
* Helper function for getAllCollectionNames().
*
* If the file storage has the following subdirectory structure:
* ./another_collection/one
* ./another_collection/two
* ./collection/sub/one
* ./collection/sub/two
* this function will return:
* @code
* array(
* 'another_collection.one',
* 'another_collection.two',
* 'collection.sub.one',
* 'collection.sub.two',
* );
* @endcode
*
* @param string $directory
* The directory to check for sub directories. This allows this
* function to be used recursively to discover all the collections in the
* storage.
*
* @return array
* A list of collection names contained within the provided directory.
*/
protected function getAllCollectionNamesHelper($directory) {
$collections = array();
foreach (new \DirectoryIterator($directory) as $fileinfo) {
if ($fileinfo->isDir() && !$fileinfo->isDot()) {
$collection = $fileinfo->getFilename();
// Recursively call getAllCollectionNamesHelper() to discover if there
// are subdirectories. Subdirectories represent a dotted collection
// name.
$sub_collections = $this->getAllCollectionNamesHelper($directory . '/' . $collection);
if (!empty($sub_collections)) {
// Build up the collection name by concatenating the subdirectory
// names with the current directory name.
foreach ($sub_collections as $sub_collection) {
$collections[] = $collection . '.' . $sub_collection;
}
}
// Check that the collection is valid by searching it for configuration
// objects. A directory without any configuration objects is not a valid
// collection.
// @see \Drupal\Core\Config\FileStorage::listAll()
foreach (scandir($directory . '/' . $collection) as $file) {
if ($file[0] !== '.' && fnmatch('*.' . $this->getFileExtension(), $file)) {
$collections[] = $collection;
break;
}
}
}
}
return $collections;
}
/**
* Gets the directory for the collection.
*
* @return string
* The directory for the collection.
*/
protected function getCollectionDirectory() {
if ($this->collection == StorageInterface::DEFAULT_COLLECTION) {
$dir = $this->directory;
}
else {
$dir = $this->directory . '/' . str_replace('.', '/', $this->collection);
}
return $dir;
}