class DataProviderDbQuery in RESTful 7.2
Hierarchy
- class \Drupal\restful\Plugin\resource\DataProvider\DataProvider implements DataProviderInterface
- class \Drupal\restful\Plugin\resource\DataProvider\DataProviderDbQuery implements DataProviderDbQueryInterface
Expanded class hierarchy of DataProviderDbQuery
File
- src/
Plugin/ resource/ DataProvider/ DataProviderDbQuery.php, line 23 - Contains \Drupal\restful\Plugin\resource\DataProvider\DataProviderDbQuery.
Namespace
Drupal\restful\Plugin\resource\DataProviderView source
class DataProviderDbQuery extends DataProvider implements DataProviderDbQueryInterface {
/**
* The name of the table to query.
*
* @var string
*/
protected $tableName;
/**
* The name of the column(s) in the table to be used as the unique key.
*
* @var array
*/
protected $idColumn;
/**
* The separator used to divide a key into its table columns when there is
* more than one column.
*/
const COLUMN_IDS_SEPARATOR = '::';
/**
* Holds the primary field.
*
* @var string
*/
protected $primary;
/**
* {@inheritdoc}
*/
public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path = NULL, array $options = array(), $langcode = NULL) {
parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);
// Validate keys exist in the plugin's "data provider options".
$required_keys = array(
'tableName',
'idColumn',
);
$required_callback = function ($required_key) {
if (!$this->options[$required_key]) {
throw new ServiceUnavailableException(sprintf('%s is missing "%s" property in the "dataProvider" key of the $plugin', get_class($this), $required_key));
}
};
array_walk($required_keys, $required_callback);
$this->tableName = $this->options['tableName'];
$this->idColumn = $this->options['idColumn'];
$this->primary = empty($this->options['primary']) ? NULL : ($this->primary = $this->options['primary']);
}
/**
* {@inheritdoc}
*/
public function getTableName() {
return $this->tableName;
}
/**
* {@inheritdoc}
*/
public function setTableName($table_name) {
$this->tableName = $table_name;
}
/**
* {@inheritdoc}
*/
public function getPrimary() {
return $this->primary;
}
/**
* {@inheritdoc}
*/
public function setPrimary($primary) {
$this->primary = $primary;
}
/**
* {@inheritdoc}
*/
public function getCacheFragments($identifier) {
if (is_array($identifier)) {
// Like in https://example.org/api/articles/1,2,3.
$identifier = implode(ResourceInterface::IDS_SEPARATOR, $identifier);
}
$fragments = new ArrayCollection(array(
'resource' => CacheDecoratedResource::serializeKeyValue($this->pluginId, $this
->canonicalPath($identifier)),
'table_name' => $this
->getTableName(),
'column' => implode(',', $this
->getIdColumn()),
));
$options = $this
->getOptions();
switch ($options['renderCache']['granularity']) {
case DRUPAL_CACHE_PER_USER:
if ($uid = $this
->getAccount()->uid) {
$fragments
->set('user_id', (int) $uid);
}
break;
case DRUPAL_CACHE_PER_ROLE:
$fragments
->set('user_role', implode(',', $this
->getAccount()->roles));
break;
}
return $fragments;
}
/**
* {@inheritdoc}
*/
public function count() {
return intval($this
->getQueryForList()
->countQuery()
->execute()
->fetchField());
}
/**
* {@inheritdoc}
*/
public function isPrimaryField($field_name) {
return $this->primary == $field_name;
}
/**
* Get ID column.
*
* @return array
* An array with the name of the column(s) in the table to be used as the
* unique key.
*/
protected function getIdColumn() {
return is_array($this->idColumn) ? $this->idColumn : array(
$this->idColumn,
);
}
/**
* {@inheritdoc}
*/
public function create($object) {
$save = FALSE;
$original_object = $object;
$id_columns = $this
->getIdColumn();
$record = array();
foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {
/* @var ResourceFieldDbColumnInterface $resource_field */
if (!$this
->methodAccess($resource_field)) {
// Allow passing the value in the request.
unset($original_object[$public_field_name]);
continue;
}
$property_name = $resource_field
->getProperty();
// If this is the primary field, skip.
if ($this
->isPrimaryField($property_name)) {
unset($original_object[$public_field_name]);
continue;
}
if (isset($object[$public_field_name])) {
$record[$property_name] = $object[$public_field_name];
}
unset($original_object[$public_field_name]);
$save = TRUE;
}
// No request was sent.
if (!$save) {
throw new BadRequestException('No values were sent with the request.');
}
// If the original request is not empty, then illegal values are present.
if (!empty($original_object)) {
$error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Property @names are invalid.', array(
'@names' => implode(', ', array_keys($original_object)),
));
throw new BadRequestException($error_message);
}
// Once the record is built, write it and view it.
if (drupal_write_record($this
->getTableName(), $record)) {
// Handle multiple id columns.
$id_values = array();
foreach ($id_columns as $id_column) {
$id_values[$id_column] = $record[$id_column];
}
$new_id = implode(self::COLUMN_IDS_SEPARATOR, $id_values);
return array(
$this
->view($new_id),
);
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function view($identifier) {
$query = $this
->getQuery();
foreach ($this
->getIdColumn() as $index => $column) {
$identifier = is_array($identifier) ? $identifier : array(
$identifier,
);
$query
->condition($this
->getTableName() . '.' . $column, current($this
->getColumnFromIds($identifier, $index)));
}
$this
->addExtraInfoToQuery($query);
$result = $query
->range(0, 1)
->execute()
->fetch(\PDO::FETCH_OBJ);
return $this
->mapDbRowToPublicFields($result);
}
/**
* {@inheritdoc}
*/
protected function mapDbRowToPublicFields($row) {
$resource_field_collection = $this
->initResourceFieldCollection($row);
// Loop over all the defined public fields.
foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {
$value = NULL;
/* @var ResourceFieldDbColumnInterface $resource_field */
if (!$this
->methodAccess($resource_field)) {
// Allow passing the value in the request.
continue;
}
$resource_field_collection
->set($resource_field
->id(), $resource_field);
}
return $resource_field_collection;
}
/**
* Adds query tags and metadata to the EntityFieldQuery.
*
* @param \SelectQuery $query
* The query to enhance.
*/
protected function addExtraInfoToQuery($query) {
$query
->addTag('restful');
$query
->addMetaData('account', $this
->getAccount());
$query
->addMetaData('restful_handler', $this);
}
/**
* {@inheritdoc}
*/
public function viewMultiple(array $identifiers) {
// Get a list query with all the sorting and pagination in place.
$query = $this
->getQueryForList();
if (empty($identifiers)) {
return array();
}
foreach ($this
->getIdColumn() as $index => $column) {
$query
->condition($this
->getTableName() . '.' . $column, $this
->getColumnFromIds($identifiers, $index), 'IN');
}
$results = $query
->execute();
$return = array();
foreach ($results as $result) {
$return[] = $this
->mapDbRowToPublicFields($result);
}
return $return;
}
/**
* {@inheritdoc}
*/
protected function getQueryForList() {
$query = $this
->getQuery();
$this
->queryForListSort($query);
$this
->queryForListFilter($query);
$this
->queryForListPagination($query);
$this
->addExtraInfoToQuery($query);
return $query;
}
/**
* {@inheritdoc}
*/
public function update($identifier, $object, $replace = FALSE) {
// Build the update array.
$save = FALSE;
$original_object = $object;
$id_columns = $this
->getIdColumn();
$record = array();
foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {
/* @var ResourceFieldDbColumnInterface $resource_field */
if (!$this
->methodAccess($resource_field)) {
// Allow passing the value in the request.
unset($original_object[$public_field_name]);
continue;
}
$property = $resource_field
->getProperty();
// If this is the primary field, skip.
if ($this
->isPrimaryField($property)) {
continue;
}
if (isset($object[$public_field_name])) {
$record[$property] = $object[$public_field_name];
}
elseif ($replace) {
$record[$property] = NULL;
}
unset($original_object[$public_field_name]);
$save = TRUE;
}
// No request was sent.
if (!$save) {
throw new BadRequestException('No values were sent with the request.');
}
// If the original request is not empty, then illegal values are present.
if (!empty($original_object)) {
$error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Property @names are invalid.', array(
'@names' => implode(', ', array_keys($original_object)),
));
throw new BadRequestException($error_message);
}
// Add the id column values into the record.
foreach ($this
->getIdColumn() as $index => $column) {
$record[$column] = current($this
->getColumnFromIds(array(
$identifier,
), $index));
}
// Once the record is built, write it.
if (!drupal_write_record($this
->getTableName(), $record, $id_columns)) {
throw new ServiceUnavailableException('Record could not be updated to the database.');
}
return array(
$this
->view($identifier),
);
}
/**
* {@inheritdoc}
*/
public function remove($identifier) {
// If it's a delete method we will want a 204 response code.
// Set the HTTP headers.
$this
->setHttpHeader('Status', 204);
$query = db_delete($this
->getTableName());
foreach ($this
->getIdColumn() as $index => $column) {
$query
->condition($column, current($this
->getColumnFromIds(array(
$identifier,
), $index)));
}
$query
->execute();
}
/**
* {@inheritdoc}
*/
public function getIndexIds() {
$results = $this
->getQueryForList()
->execute();
$ids = array();
foreach ($results as $result) {
$ids[] = array_map(function ($id_column) use ($result) {
return $result->{$id_column};
}, $this
->getIdColumn());
}
return $ids;
}
/**
* {@inheritdoc}
*/
public function index() {
$results = $this
->getQueryForList()
->execute();
$return = array();
foreach ($results as $result) {
$return[] = $this
->mapDbRowToPublicFields($result);
}
return $return;
}
/**
* Defines default sort columns if none are provided via the request URL.
*
* @return array
* Array keyed by the database column name, and the order ('ASC' or 'DESC')
* as value.
*/
protected function defaultSortInfo() {
$sorts = array();
foreach ($this
->getIdColumn() as $column) {
if (!$this->fieldDefinitions
->get($column)) {
// Sort by the first ID column that is a public field.
$sorts[$column] = 'ASC';
break;
}
}
return $sorts;
}
/**
* Sort the query for list.
*
* @param \SelectQuery $query
* The query object.
*
* @throws BadRequestException
*
* @see \RestfulEntityBase::getQueryForList
*/
protected function queryForListSort(\SelectQuery $query) {
// Get the sorting options from the request object.
$sorts = $this
->parseRequestForListSort();
$sorts = $sorts ? $sorts : $this
->defaultSortInfo();
foreach ($sorts as $sort => $direction) {
/* @var ResourceFieldDbColumnInterface $sort_field */
if ($sort_field = $this->fieldDefinitions
->get($sort)) {
$query
->orderBy($sort_field
->getColumnForQuery(), $direction);
}
}
}
/**
* Filter the query for list.
*
* @param \SelectQuery $query
* The query object.
*
* @throws BadRequestException
*
* @see \RestfulEntityBase::getQueryForList
*/
protected function queryForListFilter(\SelectQuery $query) {
foreach ($this
->parseRequestForListFilter() as $filter) {
/* @var ResourceFieldDbColumnInterface $filter_field */
if (!($filter_field = $this->fieldDefinitions
->get($filter['public_field']))) {
continue;
}
$column_name = $filter_field
->getColumnForQuery();
if (in_array(strtoupper($filter['operator'][0]), array(
'IN',
'NOT IN',
'BETWEEN',
))) {
$query
->condition($column_name, $filter['value'], $filter['operator'][0]);
continue;
}
$condition = db_condition($filter['conjunction']);
for ($index = 0; $index < count($filter['value']); $index++) {
$condition
->condition($column_name, $filter['value'][$index], $filter['operator'][$index]);
}
$query
->condition($condition);
}
}
/**
* Set correct page (i.e. range) for the query for list.
*
* Determine the page that should be seen. Page 1, is actually offset 0 in the
* query range.
*
* @param \SelectQuery $query
* The query object.
*
* @throws BadRequestException
*
* @see \RestfulEntityBase::getQueryForList
*/
protected function queryForListPagination(\SelectQuery $query) {
list($range, $offset) = $this
->parseRequestForListPagination();
$query
->range($range, $offset);
}
/**
* Get a basic query object.
*
* @return \SelectQuery
* A new SelectQuery object for this connection.
*/
protected function getQuery() {
$table = $this
->getTableName();
return db_select($table)
->fields($table);
}
/**
* Given an array of string ID's return a single column.
*
* Strings are divided by the delimiter self::COLUMN_IDS_SEPARATOR.
*
* @param array $identifiers
* An array of object IDs.
* @param int $column
* 0-N Zero indexed
*
* @return array
* Returns an array at index $column
*/
protected function getColumnFromIds(array $identifiers, $column = 0) {
// Get a single column.
$get_part = function ($identifier) use ($column) {
$parts = explode(static::COLUMN_IDS_SEPARATOR, $identifier);
if (!isset($parts[$column])) {
throw new ServerConfigurationException('Invalid ID provided.');
}
return $parts[$column];
};
return array_map($get_part, $identifiers);
}
/**
* {@inheritdoc}
*/
protected function initDataInterpreter($identifier) {
return new DataInterpreterArray($this
->getAccount(), new ArrayWrapper((array) $identifier));
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DataProvider:: |
protected | property | The account authenticated from the request for entity access checks. | |
DataProvider:: |
protected | property | The field definitions. | |
DataProvider:: |
protected | property | Determines the language of the items that should be returned. | |
DataProvider:: |
protected | property | Array of metadata. Use this as a mean to pass info to the render layer. | |
DataProvider:: |
protected | property | User defined options. | |
DataProvider:: |
protected | property | Resource identifier. | |
DataProvider:: |
protected | property | Determines the number of items that should be returned when viewing lists. | |
DataProvider:: |
protected | property | The request | |
DataProvider:: |
protected | property | The resource path. | |
DataProvider:: |
public | function |
Adds the options in the provided array to the data provider options. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Generates the canonical path for a given path. Overrides DataProviderInterface:: |
1 |
DataProvider:: |
public | function |
Return the discovery information for the given entity. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Gets the authenticated account. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Get the language code. Overrides DataProviderInterface:: |
|
DataProvider:: |
protected static | function | Gets the global language. | |
DataProvider:: |
public | function |
Returns the metadata collection. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Gets the data provider options. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Gets the range. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Gets the request. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Get the resource path. Overrides DataProviderInterface:: |
|
DataProvider:: |
protected | function | Initialize the empty resource field collection to bundle the output. | |
DataProvider:: |
public static | function |
Checks if the passed in string is a dot-nested field. Overrides DataProviderInterface:: |
|
DataProvider:: |
protected static | function | Check if a conjunction is valid for filtering. | 1 |
DataProvider:: |
protected static | function | Check if an operator is valid for filtering. | 1 |
DataProvider:: |
public | function |
Checks if the provided field can be used with the current method. Overrides DataProviderInterface:: |
|
DataProvider:: |
protected | function | Filter the query for list. | |
DataProvider:: |
protected | function | Parses the request object to get the pagination options. | |
DataProvider:: |
protected | function | Parses the request to get the sorting options. | |
DataProvider:: |
public static | function |
Processes the input for a filter and adds the appropriate defaults. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Sets the authenticated account. Overrides DataProviderInterface:: |
|
DataProvider:: |
protected | function | Sets an HTTP header. | |
DataProvider:: |
public | function |
Sets the language code. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Sets the options. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Sets the range. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Sets the request. Overrides DataProviderInterface:: |
|
DataProvider:: |
public | function |
Set the resource path. Overrides DataProviderInterface:: |
|
DataProviderDbQuery:: |
protected | property | The name of the column(s) in the table to be used as the unique key. | |
DataProviderDbQuery:: |
protected | property | Holds the primary field. | |
DataProviderDbQuery:: |
protected | property | The name of the table to query. | |
DataProviderDbQuery:: |
protected | function |
Adds query tags and metadata to the EntityFieldQuery. Overrides DataProvider:: |
|
DataProviderDbQuery:: |
constant | The separator used to divide a key into its table columns when there is more than one column. | ||
DataProviderDbQuery:: |
public | function |
Counts the total results for the index call. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
public | function |
Create operation. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
protected | function | Defines default sort columns if none are provided via the request URL. | |
DataProviderDbQuery:: |
public | function |
Gets the entity context. Overrides DataProvider:: |
|
DataProviderDbQuery:: |
protected | function | Given an array of string ID's return a single column. | |
DataProviderDbQuery:: |
protected | function | Get ID column. | |
DataProviderDbQuery:: |
public | function |
Returns the ID to render for the current index GET request. Overrides DataProviderInterface:: |
|
DataProviderDbQuery:: |
public | function |
Gets the primary field. Overrides DataProviderDbQueryInterface:: |
|
DataProviderDbQuery:: |
protected | function | Get a basic query object. | |
DataProviderDbQuery:: |
protected | function | ||
DataProviderDbQuery:: |
public | function |
Get the name of the table to query. Overrides DataProviderDbQueryInterface:: |
|
DataProviderDbQuery:: |
public | function |
List operation. Overrides DataProvider:: |
|
DataProviderDbQuery:: |
protected | function |
Get the data interpreter. Overrides DataProvider:: |
|
DataProviderDbQuery:: |
public | function |
Checks if the current field is the primary field. Overrides DataProviderDbQueryInterface:: |
|
DataProviderDbQuery:: |
protected | function | ||
DataProviderDbQuery:: |
protected | function | Filter the query for list. | |
DataProviderDbQuery:: |
protected | function | Set correct page (i.e. range) for the query for list. | |
DataProviderDbQuery:: |
protected | function | Sort the query for list. | |
DataProviderDbQuery:: |
public | function |
Delete operation. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
public | function |
Sets the primary field. Overrides DataProviderDbQueryInterface:: |
|
DataProviderDbQuery:: |
public | function |
Set the name of the table to query. Overrides DataProviderDbQueryInterface:: |
|
DataProviderDbQuery:: |
public | function |
Update operation. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
public | function |
Read operation. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
public | function |
Read operation. Overrides CrudInterface:: |
|
DataProviderDbQuery:: |
public | function |
Constructor. Overrides DataProvider:: |