Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
CRAP | |
0.00% |
0 / 83 |
DatabaseStorage | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
992 | |
0.00% |
0 / 83 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
exists | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
read | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
readMultiple | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
write | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
doWrite | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
ensureTableExists | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 8 |
|||
schemaDefinition | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
delete | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
rename | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
encode | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
decode | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
listAll | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
deleteAll | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
createCollection | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
getCollectionName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getAllCollectionNames | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Config\DatabaseStorage. | |
*/ | |
namespace Drupal\Core\Config; | |
use Drupal\Core\Database\Database; | |
use Drupal\Core\Database\Connection; | |
use Drupal\Core\Database\SchemaObjectExistsException; | |
use Drupal\Core\DependencyInjection\DependencySerializationTrait; | |
/** | |
* Defines the Database storage. | |
*/ | |
class DatabaseStorage implements StorageInterface { | |
use DependencySerializationTrait; | |
/** | |
* The database connection. | |
* | |
* @var \Drupal\Core\Database\Connection | |
*/ | |
protected $connection; | |
/** | |
* The database table name. | |
* | |
* @var string | |
*/ | |
protected $table; | |
/** | |
* Additional database connection options to use in queries. | |
* | |
* @var array | |
*/ | |
protected $options = array(); | |
/** | |
* The storage collection. | |
* | |
* @var string | |
*/ | |
protected $collection = StorageInterface::DEFAULT_COLLECTION; | |
/** | |
* Constructs a new DatabaseStorage. | |
* | |
* @param \Drupal\Core\Database\Connection $connection | |
* A Database connection to use for reading and writing configuration data. | |
* @param string $table | |
* A database table name to store configuration data in. | |
* @param array $options | |
* (optional) Any additional database connection options to use in queries. | |
* @param string $collection | |
* (optional) The collection to store configuration in. Defaults to the | |
* default collection. | |
*/ | |
public function __construct(Connection $connection, $table, array $options = array(), $collection = StorageInterface::DEFAULT_COLLECTION) { | |
$this->connection = $connection; | |
$this->table = $table; | |
$this->options = $options; | |
$this->collection = $collection; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function exists($name) { | |
try { | |
return (bool) $this->connection->queryRange('SELECT 1 FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name = :name', 0, 1, array( | |
':collection' => $this->collection, | |
':name' => $name, | |
), $this->options)->fetchField(); | |
} | |
catch (\Exception $e) { | |
// If we attempt a read without actually having the database or the table | |
// available, just return FALSE so the caller can handle it. | |
return FALSE; | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function read($name) { | |
$data = FALSE; | |
try { | |
$raw = $this->connection->query('SELECT data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name = :name', array(':collection' => $this->collection, ':name' => $name), $this->options)->fetchField(); | |
if ($raw !== FALSE) { | |
$data = $this->decode($raw); | |
} | |
} | |
catch (\Exception $e) { | |
// If we attempt a read without actually having the database or the table | |
// available, just return FALSE so the caller can handle it. | |
} | |
return $data; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function readMultiple(array $names) { | |
$list = array(); | |
try { | |
$list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN ( :names[] )', array(':collection' => $this->collection, ':names[]' => $names), $this->options)->fetchAllKeyed(); | |
foreach ($list as &$data) { | |
$data = $this->decode($data); | |
} | |
} | |
catch (\Exception $e) { | |
// If we attempt a read without actually having the database or the table | |
// available, just return an empty array so the caller can handle it. | |
} | |
return $list; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function write($name, array $data) { | |
$data = $this->encode($data); | |
try { | |
return $this->doWrite($name, $data); | |
} | |
catch (\Exception $e) { | |
// If there was an exception, try to create the table. | |
if ($this->ensureTableExists()) { | |
return $this->doWrite($name, $data); | |
} | |
// Some other failure that we can not recover from. | |
throw $e; | |
} | |
} | |
/** | |
* Helper method so we can re-try a write. | |
* | |
* @param string $name | |
* The config name. | |
* @param string $data | |
* The config data, already dumped to a string. | |
* | |
* @return bool | |
*/ | |
protected function doWrite($name, $data) { | |
$options = array('return' => Database::RETURN_AFFECTED) + $this->options; | |
return (bool) $this->connection->merge($this->table, $options) | |
->keys(array('collection', 'name'), array($this->collection, $name)) | |
->fields(array('data' => $data)) | |
->execute(); | |
} | |
/** | |
* Check if the config table exists and create it if not. | |
* | |
* @return bool | |
* TRUE if the table was created, FALSE otherwise. | |
* | |
* @throws \Drupal\Core\Config\StorageException | |
* If a database error occurs. | |
*/ | |
protected function ensureTableExists() { | |
try { | |
if (!$this->connection->schema()->tableExists($this->table)) { | |
$this->connection->schema()->createTable($this->table, static::schemaDefinition()); | |
return TRUE; | |
} | |
} | |
// If another process has already created the config table, attempting to | |
// recreate it will throw an exception. In this case just catch the | |
// exception and do nothing. | |
catch (SchemaObjectExistsException $e) { | |
return TRUE; | |
} | |
catch (\Exception $e) { | |
throw new StorageException($e->getMessage(), NULL, $e); | |
} | |
return FALSE; | |
} | |
/** | |
* Defines the schema for the configuration table. | |
*/ | |
protected static function schemaDefinition() { | |
$schema = array( | |
'description' => 'The base table for configuration data.', | |
'fields' => array( | |
'collection' => array( | |
'description' => 'Primary Key: Config object collection.', | |
'type' => 'varchar_ascii', | |
'length' => 255, | |
'not null' => TRUE, | |
'default' => '', | |
), | |
'name' => array( | |
'description' => 'Primary Key: Config object name.', | |
'type' => 'varchar_ascii', | |
'length' => 255, | |
'not null' => TRUE, | |
'default' => '', | |
), | |
'data' => array( | |
'description' => 'A serialized configuration object data.', | |
'type' => 'blob', | |
'not null' => FALSE, | |
'size' => 'big', | |
), | |
), | |
'primary key' => array('collection', 'name'), | |
); | |
return $schema; | |
} | |
/** | |
* Implements Drupal\Core\Config\StorageInterface::delete(). | |
* | |
* @throws PDOException | |
* | |
* @todo Ignore replica targets for data manipulation operations. | |
*/ | |
public function delete($name) { | |
$options = array('return' => Database::RETURN_AFFECTED) + $this->options; | |
return (bool) $this->connection->delete($this->table, $options) | |
->condition('collection', $this->collection) | |
->condition('name', $name) | |
->execute(); | |
} | |
/** | |
* Implements Drupal\Core\Config\StorageInterface::rename(). | |
* | |
* @throws PDOException | |
*/ | |
public function rename($name, $new_name) { | |
$options = array('return' => Database::RETURN_AFFECTED) + $this->options; | |
return (bool) $this->connection->update($this->table, $options) | |
->fields(array('name' => $new_name)) | |
->condition('name', $name) | |
->condition('collection', $this->collection) | |
->execute(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function encode($data) { | |
return serialize($data); | |
} | |
/** | |
* Implements Drupal\Core\Config\StorageInterface::decode(). | |
* | |
* @throws ErrorException | |
* unserialize() triggers E_NOTICE if the string cannot be unserialized. | |
*/ | |
public function decode($raw) { | |
$data = @unserialize($raw); | |
return is_array($data) ? $data : FALSE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function listAll($prefix = '') { | |
try { | |
$query = $this->connection->select($this->table); | |
$query->fields($this->table, array('name')); | |
$query->condition('collection', $this->collection, '='); | |
$query->condition('name', $prefix . '%', 'LIKE'); | |
$query->orderBy('collection')->orderBy('name'); | |
return $query->execute()->fetchCol(); | |
} | |
catch (\Exception $e) { | |
return array(); | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function deleteAll($prefix = '') { | |
try { | |
$options = array('return' => Database::RETURN_AFFECTED) + $this->options; | |
return (bool) $this->connection->delete($this->table, $options) | |
->condition('name', $prefix . '%', 'LIKE') | |
->condition('collection', $this->collection) | |
->execute(); | |
} | |
catch (\Exception $e) { | |
return FALSE; | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function createCollection($collection) { | |
return new static( | |
$this->connection, | |
$this->table, | |
$this->options, | |
$collection | |
); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getCollectionName() { | |
return $this->collection; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getAllCollectionNames() { | |
try { | |
return $this->connection->query('SELECT DISTINCT collection FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection <> :collection ORDER by collection', array( | |
':collection' => StorageInterface::DEFAULT_COLLECTION) | |
)->fetchCol(); | |
} | |
catch (\Exception $e) { | |
return array(); | |
} | |
} | |
} |