function tripal_chado_field_storage_query
3.x tripal_chado.field_storage.inc | tripal_chado_field_storage_query($query) |
Implements hook_field_storage_query().
File
- tripal_chado/
includes/ tripal_chado.field_storage.inc, line 462
Code
function tripal_chado_field_storage_query($query) {
// Initialize the result array.
$result = array(
'TripalEntity' => array()
);
// There must always be an entity filter that includes the bundle. Otherwise
// it would be too overwhelming to search every table of every content type
// for a matching field.
if (!array_key_exists('bundle', $query->entityConditions)) {
return $result;
}
$bundle = tripal_load_bundle_entity(array('name' => $query->entityConditions['bundle']));
if (!$bundle) {
return;
}
$data_table = $bundle->data_table;
$type_column = $bundle->type_column;
$type_id = $bundle->type_id;
$schema = chado_get_schema($data_table);
$pkey = $schema['primary key'][0];
// Initialize the Query object.
$cquery = chado_db_select($data_table, 'base');
$cquery->fields('base', array($pkey));
// Iterate through all the conditions and add to the filters array
// a chado_select_record compatible set of filters.
foreach ($query->fieldConditions as $index => $condition) {
$field = $condition['field'];
$field_name = $field['field_name'];
$field_type = $field['type'];
// Skip conditions that don't belong to this storage type.
if ($field['storage']['type'] != 'field_chado_storage') {
continue;
}
// The Chado settings for a field are part of the instance and each bundle
// can have the same field but with different Chado mappings. Therefore,
// we need to iterate through the bundles to get the field instances.
foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
// If there is a bundle filter for the entity and if the field is not
// associated with the bundle then skip it.
if (array_key_exists('bundle', $query->entityConditions)) {
if (strtolower($query->entityConditions['bundle']['operator']) == 'in' and
!array_key_exists($bundle_name, $query->entityConditions['bundle']['value'])) {
continue;
}
else if ($query->entityConditions['bundle']['value'] != $bundle_name) {
continue;
}
}
// Allow the field to update the query object.
$instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
if (tripal_load_include_field_class($field_type)) {
$field_obj = new $field_type($field, $instance);
$field_obj->query($cquery, $condition);
}
// If there is not a ChadoField class for this field then add the
// condition as is.
else {
$alias = $field['field_name'];
$chado_table = $instance['settings']['chado_table'];
$base_table = $instance['settings']['base_table'];
$bschema = chado_get_schema($base_table);
$bpkey = $bschema['primary key'][0];
if ($chado_table == $base_table) {
// Get the base table column that is associated with the term
// passed as $condition['column'].
$base_field = chado_get_semweb_column($chado_table, $condition['column']);
$matches = array();
$key = $condition['value'];
$op = '=';
if (preg_match('/^(.+);(.+)$/', $key, $matches)) {
$key = $matches[1];
$op = $matches[2];
}
switch ($op) {
case 'eq':
$op = '=';
break;
case 'gt':
$op = '>';
break;
case 'gte':
$op = '>=';
break;
case 'lt':
$op = '<';
break;
case 'lte':
$op = '<=';
break;
case 'ne':
$op = '<>';
break;
case 'contains':
$op = 'LIKE';
$key = '%' . $key . '%';
break;
case 'starts':
$op = 'LIKE';
$key = $key . '%';
break;
default:
$op = '=';
}
$cquery->condition('base.' . $base_field, $key, $op);
}
if ($chado_table != $base_table) {
// TODO: I don't think we'll get here because linker fields will
// always have a custom field that should implement a query()
// function. But just in case here's a note to handle it.
}
}
}
} // end foreach ($query->fieldConditions as $index => $condition) {
// Now join with the chado entity table to get published records only.
$chado_entity_table = chado_get_bundle_entity_table($bundle);
$cquery->join($chado_entity_table, 'CE', "CE.record_id = base.$pkey");
$cquery->join('tripal_entity', 'TE', "CE.entity_id = TE.id");
$cquery->fields('CE', array('entity_id'));
$cquery->fields('TE', array('bundle'));
if (array_key_exists('start', $query->range)) {
$cquery->range($query->range['start'], $query->range['length']);
}
// Make sure we only get records of the correct entity type
$cquery->condition('TE.bundle', $query->entityConditions['bundle']['value']);
// Iterate through all the property conditions. These will be filters
// on the tripal_entity table.
foreach ($query->propertyConditions as $index => $condition) {
$cquery->condition('TE.' . $condition['column'], $condition['value']);
}
// If there is an entity_id filter then apply that.
if (array_key_exists('entity_id', $query->entityConditions)) {
$value = $query->entityConditions['entity_id']['value'];
$op = '';
if (array_key_exists('op', $query->entityConditions['entity_id'])) {
$op = $query->entityConditions['entity_id']['op'];
}
// Handle a single entity_id
if (!is_array($value)) {
switch ($op) {
case 'CONTAINS':
$op = 'LIKE';
$value = '%' . $value . '%';
break;
case 'STARTS_WITH':
$op = 'LIKE';
$value = $value . '%';
break;
case 'BETWEEN':
// This case doesn't make sense for a single value. So, just set it
// equal to the end.
$op = '=';
default:
$op = $op ? $op : '=';
}
}
// Handle multiple entitie IDs.
else {
switch ($op) {
case 'CONTAINS':
$op = 'IN';
break;
case 'STARTS_WITH':
$op = 'IN';
break;
case 'BETWEEN':
$op = 'BETWEEN';
default:
$op = 'IN';
}
}
if ($op == 'BETWEEN') {
$cquery->condition('TE.id', $value[0], '>');
$cquery->condition('TE.id', $value[1], '<');
}
else {
$cquery->condition('TE.id', $value, $op);
}
}
// Now set any ordering.
foreach ($query->order as $index => $sort) {
// Add in property ordering.
if ($sort['type'] == 'property') {
// TODO: support ordering by bundle properties.
}
// Add in filter ordering
if ($sort['type'] == 'field') {
$field = $sort['specifier']['field'];
$field_type = $field['type'];
$field_name = $field['field_name'];
// Skip sorts that don't belong to this storage type.
if ($field['storage']['type'] != 'field_chado_storage') {
continue;
}
$column = $sort['specifier']['column'];
$direction = $sort['direction'];
// The Chado settings for a field are part of the instance and each bundle
// can have the same field but with different Chado mappings. Therefore,
// we need to iterate through the bundles to get the field instances.
foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
// If there is a bundle filter for the entity and if the field is not
// associated with the bundle then skip it.
if (array_key_exists('bundle', $query->entityConditions)) {
if (strtolower($query->entityConditions['bundle']['operator']) == 'in' and
!array_key_exists($bundle_name, $query->entityConditions['bundle']['value'])) {
continue;
}
else if ($query->entityConditions['bundle']['value'] != $bundle_name) {
continue;
}
}
// See if there is a ChadoField class for this instance. If not then do
// our best to order the field.
$instance = field_info_instance('TripalEntity', $field_name, $bundle_name);
if (tripal_load_include_field_class($field_type)) {
$field_obj = new $field_type($field, $instance);
$field_obj->queryOrder($cquery, array('column' => $column, 'direction' => $direction));
}
// There is no class so do our best to order the data by this field
else {
$base_table = $instance['settings']['base_table'];
$chado_table = $instance['settings']['chado_table'];
$table_column = chado_get_semweb_column($chado_table, $column);
if ($table_column) {
if ($chado_table == $base_table) {
$cquery->orderBy('base.' . $table_column, $direction);
}
else {
// TODO: how do we handle a field that doesn't map to the base table.
// We would expect that all of these would be custom field and
// the ChadoField::queryOrder() function would be implemented.
}
}
else {
// TODO: handle when the name can't be matched to a table column.
}
}
} // end foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
} // end if ($sort['type'] == 'field') {
} // end foreach ($query->order as $index => $sort) {
// dpm($cquery->__toString());
// dpm($cquery->getArguments());
$records = $cquery->execute();
// If the query is a count query then just return the total count.
if ($query->count) {
return $records->rowCount();
}
// If this is not a count query then return the results.
$result = array();
while ($record = $records->fetchObject()) {
$ids = array($record->entity_id, 0, $record->bundle);
$result['TripalEntity'][$record->entity_id] = entity_create_stub_entity('TripalEntity', $ids);
}
return $result;
}