FileStorage.php 5.8 KB
Newer Older
1 2
<?php

3 4 5 6 7
/**
 * @file
 * Definition of Drupal\Core\Config\FileStorage.
 */

8 9
namespace Drupal\Core\Config;

10 11
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\Yaml\Parser;
12

13
/**
14
 * Defines the file storage controller.
15
 */
16
class FileStorage implements StorageInterface {
17 18

  /**
19
   * The filesystem path for configuration objects.
20
   *
21
   * @var string
22
   */
23
  protected $directory = '';
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38
  /**
   * A shared YAML dumper instance.
   *
   * @var Symfony\Component\Yaml\Dumper
   */
  protected $dumper;

  /**
   * A shared YAML parser instance.
   *
   * @var Symfony\Component\Yaml\Parser
   */
  protected $parser;

39
  /**
40 41 42 43
   * Constructs a new FileStorage controller.
   *
   * @param string $directory
   *   A directory path to use for reading and writing of configuration files.
44
   */
45 46
  public function __construct($directory) {
    $this->directory = $directory;
47 48 49
  }

  /**
50
   * Returns the path to the configuration file.
51
   *
52 53
   * @return string
   *   The path to the configuration file.
54
   */
55
  public function getFilePath($name) {
56
    return $this->directory . '/' . $name . '.' . static::getFileExtension();
57 58 59 60 61 62 63 64 65 66
  }

  /**
   * Returns the file extension used by the file storage for all configuration files.
   *
   * @return string
   *   The file extension.
   */
  public static function getFileExtension() {
    return 'yml';
67 68 69
  }

  /**
70
   * Implements Drupal\Core\Config\StorageInterface::exists().
71
   */
72 73
  public function exists($name) {
    return file_exists($this->getFilePath($name));
74 75 76
  }

  /**
77
   * Implements Drupal\Core\Config\StorageInterface::read().
78
   *
79
   * @throws Symfony\Component\Yaml\Exception\ParseException
80
   */
81 82
  public function read($name) {
    if (!$this->exists($name)) {
83
      return FALSE;
84 85 86 87 88 89
    }
    $data = file_get_contents($this->getFilePath($name));
    // @todo Yaml throws a ParseException on invalid data. Is it expected to be
    //   caught or not?
    $data = $this->decode($data);
    return $data;
90 91
  }

92 93 94 95 96 97 98 99 100 101 102 103 104
  /**
   * {@inheritdoc}
   */
  public function readMultiple(array $names) {
    $list = array();
    foreach ($names as $name) {
      if ($data = $this->read($name)) {
        $list[$name] = $data;
      }
    }
    return $list;
  }

105
  /**
106
   * Implements Drupal\Core\Config\StorageInterface::write().
107
   *
108
   * @throws Symfony\Component\Yaml\Exception\DumpException
109
   * @throws \Drupal\Core\Config\StorageException
110
   */
111 112
  public function write($name, array $data) {
    $data = $this->encode($data);
113 114
    $target = $this->getFilePath($name);
    $status = @file_put_contents($target, $data);
115 116
    if ($status === FALSE) {
      throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
117
    }
118 119 120
    else {
      drupal_chmod($target);
    }
121
    return TRUE;
122 123 124
  }

  /**
125
   * Implements Drupal\Core\Config\StorageInterface::delete().
126
   */
127 128
  public function delete($name) {
    if (!$this->exists($name)) {
129 130
      if (!file_exists($this->directory)) {
        throw new StorageException($this->directory . '/ not found.');
131 132 133 134
      }
      return FALSE;
    }
    return drupal_unlink($this->getFilePath($name));
135
  }
136

137
  /**
138
   * Implements Drupal\Core\Config\StorageInterface::rename().
139 140 141 142 143 144 145 146 147
   */
  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;
  }

148 149 150 151 152 153 154 155
  /**
   * Gets the YAML dumper instance.
   *
   * @return Symfony\Component\Yaml\Dumper
   */
  protected function getDumper() {
    if (!isset($this->dumper)) {
      $this->dumper = new Dumper();
156 157 158
      // Set Yaml\Dumper's default indentation for nested nodes/collections to
      // 2 spaces for consistency with Drupal coding standards.
      $this->dumper->setIndentation(2);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    }
    return $this->dumper;
  }

  /**
   * Gets the YAML parser instance.
   *
   * @return Symfony\Component\Yaml\Parser
   */
  protected function getParser() {
    if (!isset($this->parser)) {
      $this->parser = new Parser();
    }
    return $this->parser;
  }

175
  /**
176 177 178
   * Implements Drupal\Core\Config\StorageInterface::encode().
   *
   * @throws Symfony\Component\Yaml\Exception\DumpException
179
   */
180
  public function encode($data) {
181
    // The level where you switch to inline YAML is set to PHP_INT_MAX to ensure
182 183 184
    // this does not occur. Also set the exceptionOnInvalidType parameter to
    // TRUE, so exceptions are thrown for an invalid data type.
    return $this->getDumper()->dump($data, PHP_INT_MAX, 0, TRUE);
185 186 187
  }

  /**
188 189 190
   * Implements Drupal\Core\Config\StorageInterface::decode().
   *
   * @throws Symfony\Component\Yaml\Exception\ParseException
191
   */
192 193
  public function decode($raw) {
    $data = $this->getParser()->parse($raw);
194 195 196
    // A simple string is valid YAML for any reason.
    if (!is_array($data)) {
      return FALSE;
197
    }
198
    return $data;
199 200 201
  }

  /**
202
   * Implements Drupal\Core\Config\StorageInterface::listAll().
203
   */
204 205 206
  public function listAll($prefix = '') {
    // glob() silently ignores the error of a non-existing search directory,
    // even with the GLOB_ERR flag.
207 208
    if (!file_exists($this->directory)) {
      throw new StorageException($this->directory . '/ not found.');
209
    }
210
    $extension = '.' . static::getFileExtension();
211
    $files = new \GlobIterator($this->directory . '/' . $prefix . '*' . $extension);
212 213 214 215 216 217 218

    $names = array();
    foreach ($files as $file) {
      $names[] = $file->getBasename($extension);
    }

    return $names;
219
  }
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234

  /**
   * Implements Drupal\Core\Config\StorageInterface::deleteAll().
   */
  public function deleteAll($prefix = '') {
    $success = TRUE;
    $files = $this->listAll($prefix);
    foreach ($files as $name) {
      if (!$this->delete($name) && $success) {
        $success = FALSE;
      }
    }

    return $success;
  }
235
}