Commit 7442dc06 authored by webchick's avatar webchick

#392494 by yched and bjaspan: Provide a query API for Field API. This is...

#392494 by yched and bjaspan: Provide a query API for Field API. This is necessary because we can't assume fields will be stored in a database, due to pluggable storage backends.
parent 1f9077ee
......@@ -238,6 +238,10 @@ function hook_field_load($obj_type, $objects, $field, $instances, &$items, $age)
* The type of $object.
* @param $object
* The object for the operation.
* Note that this might not be a full-fledged 'object'. When invoked through
* field_attach_query(), the $object will only include properties that the
* Field API knows about: bundle, id, revision id, and field values (no node
* title, user name...).
* @param $field
* The field structure for the operation.
* @param $instance
......@@ -503,12 +507,17 @@ function hook_field_attach_pre_load($obj_type, $objects, $age, &$skip_fields) {
* This hook is invoked after the field module has performed the operation.
*
* Unlike other field_attach hooks, this hook accounts for 'multiple loads'.
* It takes an array of objects indexed by object id as its first parameter.
* For performance reasons, information for all available objects should be
* loaded in a single query where possible.
* Instead of the usual $object parameter, it accepts an array of objects,
* indexed by object id. For performance reasons, information for all available
* objects should be loaded in a single query where possible.
*
* Note that the changes made to the objects' field values get cached by the
* field cache for subsequent loads.
* Note that $objects might not be full-fledged 'objects'. When invoked through
* field_attach_query(), each object only includes properties that the Field
* API knows about: bundle, id, revision id, and field values (no node title,
* user name...)
* The changes made to the objects' field values get cached by the field cache
* for subsequent loads.
*
* See field_attach_load() for details and arguments.
*/
......@@ -585,6 +594,38 @@ function hook_field_attach_pre_insert($obj_type, $object, &$skip_fields) {
function hook_field_attach_pre_update($obj_type, $object, &$skip_fields) {
}
/**
* Act on field_attach_pre_query.
*
* This hook should be implemented by modules that use
* hook_field_attach_pre_load(), hook_field_attach_pre_insert() and
* hook_field_attach_pre_update() to bypass the regular storage engine, to
* handle field queries.
*
* @param $field_name
* The name of the field to query.
* @param $conditions
* See field_attach_query().
* A storage module that doesn't support querying a given column should raise
* a FieldQueryException. Incompatibilities should be mentioned on the module
* project page.
* @param $result_format
* See field_attach_query().
* @param $age
* - FIELD_LOAD_CURRENT: query the most recent revisions for all
* objects. The results will be keyed by object type and object id.
* - FIELD_LOAD_REVISION: query all revisions. The results will be keyed by
* object type and object revision id.
* @param $skip_field
* Boolean, always coming as FALSE.
* @return
* See field_attach_query().
* The $skip_field parameter should be set to TRUE if the query has been
* handled.
*/
function hook_field_attach_pre_query($field_name, $conditions, $result_format, $age, &$skip_field) {
}
/**
* Act on field_attach_delete.
*
......@@ -736,6 +777,26 @@ function hook_field_storage_delete($obj_type, $object) {
function hook_field_storage_delete_revision($obj_type, $object) {
}
/**
* Handle a field query.
*
* @param $field_name
* The name of the field to query.
* @param $conditions
* See field_attach_query().
* A storage module that doesn't support querying a given column should raise
* a FieldQueryException. Incompatibilities should be mentioned on the module
* project page.
* @param $result_format
* See field_attach_query().
* @param $age
* See field_attach_query().
* @return
* See field_attach_query().
*/
function hook_field_storage_query($field_name, $conditions, $result_format, $age) {
}
/**
* Act on creation of a new bundle.
*
......
This diff is collapsed.
......@@ -87,6 +87,25 @@
*/
define('FIELD_LOAD_REVISION', 'FIELD_LOAD_REVISION');
/**
* @name Field query flags
* @{
* Flags for use in the $result_format parameter in field_attach_query().
*/
/**
* Result format argument for field_attach_query().
*/
define('FIELD_QUERY_RETURN_VALUES', 'FIELD_QUERY_RETURN_VALUES');
/**
* Result format argument for field_attach_query().
*/
define('FIELD_QUERY_RETURN_IDS', 'FIELD_QUERY_RETURN_IDS');
/**
* @} End of "Field query flags".
*/
/**
* Base class for all exceptions thrown by Field API functions.
......
This diff is collapsed.
......@@ -238,7 +238,8 @@ function field_sql_storage_field_storage_load($obj_type, &$objects, $age, $skip_
// For each column declared by the field, populate the item
// from the prefixed database column.
foreach ($field['columns'] as $column => $attributes) {
$item[$column] = $row->{_field_sql_storage_columnname($field_name, $column)};
$column_name = _field_sql_storage_columnname($field_name, $column);
$item[$column] = $row->$column_name;
}
// Add the item to the field values for the entity.
......@@ -350,6 +351,108 @@ function field_sql_storage_field_storage_delete($obj_type, $object) {
}
}
/**
* Implement hook_field_storage_query().
*/
function field_sql_storage_field_storage_query($field_name, $conditions, $result_format, $age) {
$load_values = $result_format == FIELD_QUERY_RETURN_VALUES;
$load_current = $age == FIELD_LOAD_CURRENT;
$field = field_info_field($field_name);
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
$field_columns = array_keys($field['columns']);
// Build the query.
$query = db_select($table, 't');
$query->join('field_config_entity_type', 'e', 't.etid = e.etid');
$query
->fields('e', array('type'))
->condition('deleted', 0)
->orderBy('delta');
// Add fields, depending on the return format.
if ($load_values) {
$query->fields('t');
}
else {
$query->fields('t', array('entity_id', 'revision_id'));
}
// Add conditions.
foreach ($conditions as $condition) {
// A condition is either a (column, value, operator) triple, or a
// (column, value) pair with implied operator.
@list($column, $value, $operator) = $condition;
// Translate operator and value if needed.
switch ($operator) {
case NULL:
$operator = is_array($value) ? 'IN' : '=';
break;
case 'STARTS_WITH':
$operator = 'LIKE';
$value .= '%';
break;
case 'ENDS_WITH':
$operator = 'LIKE';
$value = "$value%";
break;
case 'CONTAINS':
$operator = 'LIKE';
$value = "%$value%";
break;
}
// Translate field columns into prefixed db columns.
if (in_array($column, $field_columns)) {
$column = _field_sql_storage_columnname($field_name, $column);
}
$query->condition($column, $value, $operator);
}
$results = $query->execute();
// Build results.
$return = array();
$delta_count = array();
foreach ($results as $row) {
// If querying all revisions and the entity type has revisions, we need to
// key the results by revision_ids.
$entity_type = field_info_fieldable_types($row->type);
$id = ($load_current || empty($entity_type['revision key'])) ? $row->entity_id : $row->revision_id;
if ($load_values) {
// Populate actual field values.
if (!isset($delta_count[$row->type][$id])) {
$delta_count[$row->type][$id] = 0;
}
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->type][$id] < $field['cardinality']) {
$item = array();
// For each column declared by the field, populate the item
// from the prefixed database column.
foreach ($field['columns'] as $column => $attributes) {
$column_name = _field_sql_storage_columnname($field_name, $column);
$item[$column] = $row->$column_name;
}
// Initialize the 'pseudo object' if needed.
if (!isset($return[$row->type][$id])) {
$return[$row->type][$id] = field_attach_create_stub_object($row->type, array($row->entity_id, $row->revision_id, $row->bundle));
}
// Add the item to the field values for the entity.
$return[$row->type][$id]->{$field_name}[] = $item;
$delta_count[$row->type][$id]++;
}
}
else {
// Simply return the list of selected ids.
$return[$row->type][$id] = $row->entity_id;
}
}
return $return;
}
/**
* Implement hook_field_storage_delete_revision().
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment