diff --git a/core/core.services.yml b/core/core.services.yml index 7cfd0e8..f62ad64 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -126,13 +126,16 @@ services: tags: - { name: needs_destruction } arguments: ['@database'] + keyvalue.file: + class: Drupal\Core\KeyValueStore\KeyValueFileFactory + arguments: ['@settings'] settings: class: Drupal\Component\Utility\Settings factory_class: Drupal\Component\Utility\Settings factory_method: getSingleton state: class: Drupal\Core\KeyValueStore\State - arguments: ['@keyvalue'] + arguments: ['@keyvalue.file'] tags: - { name: persist } queue: diff --git a/core/lib/Drupal/Core/KeyValueStore/FileStorage.php b/core/lib/Drupal/Core/KeyValueStore/FileStorage.php new file mode 100644 index 0000000..fd1d37c --- /dev/null +++ b/core/lib/Drupal/Core/KeyValueStore/FileStorage.php @@ -0,0 +1,121 @@ +path = $path; + if ($this->collection !== '') { + // @todo What if $path is a stream wrapper base URI scheme? + $this->path .= '/' . $this->collection; + } + } + + /** + * {@inheritdoc} + */ + public function getMultiple(array $keys) { + $values = array(); + foreach ($keys as $key) { + // @todo Inject serialization/encoding format into key/value stores. + if (file_exists($this->path . "/$key")) { + // @todo DatabaseStorage, being the default implementation, introduced a + // questionable implicit assumption/expectation that it is possible + // to store entire objects (possibly contained in nested arrays even) + // in a key/value store by using serialize() instead of e.g., + // json_encode($value, TRUE). That aspect of the default implemenation + // pretty much prevents any other implementation to use a better + // serialization format. + $values[$key] = unserialize(file_get_contents($this->path . "/$key")); + } + } + return $values; + } + + /** + * {@inheritdoc} + */ + public function getAll() { + $values = array(); + foreach ($this->getIterator() as $key => $pathname) { + $values[$key] = unserialize(file_get_contents($pathname)); + } + return $values; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) { + file_put_contents($this->path . "/$key", serialize($value)); + } + + /** + * {@inheritdoc} + */ + public function setIfNotExists($key, $value) { + if (!file_exists($this->path . "/$key")) { + $this->set($key, $value); + return TRUE; + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple(array $keys) { + foreach ($keys as $key) { + if (file_exists($this->path . "/$key")) { + unlink($this->path . "/$key"); + } + } + } + + /** + * {@inheritdoc} + */ + public function deleteAll() { + foreach ($this->getIterator() as $key => $pathname) { + unlink($pathname); + } + } + + /** + * Returns an iterator for the file storage. + * + * @return \FilesystemIterator + * The filesystem iterator. + */ + protected function getIterator() { + $flags = \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_PATHNAME; + $flags |= \FilesystemIterator::SKIP_DOTS; + return new \FilesystemIterator($this->path, $flags); + } + +} diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueFileFactory.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueFileFactory.php new file mode 100644 index 0000000..4ed3e8f --- /dev/null +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueFileFactory.php @@ -0,0 +1,42 @@ +settings = $settings; + } + + /** + * {@inheritdoc} + */ + public function get($collection) { + // @todo Please disregard this automatic setup. Testing purposes only. + $path = $this->settings->get('file_public_path', conf_path() . '/files'); + $path .= '/keyvalue'; + if (!is_dir($path)) { + mkdir($path, 0777); + } + if (!is_dir("$path/$collection")) { + mkdir("$path/$collection", 0777); + } + return new FileStorage($collection, $path); + } + +}