Beispiel #1
0
/**
 * Additional columns and views need to be added to existing fields.
 * Below is an example using the addtional column and view defined above.
 * my_new_view_additional_data() is schema defined in
 * hook_recline_field_columns.
 */
function hook_update_N(&$sandbox)
{
    $ret = array();
    $fields = field_info_fields();
    foreach ($fields as $field_name => $field) {
        if ($field['type'] == 'recline_field' && $field['storage']['type'] == 'field_sql_storage') {
            foreach ($field['storage']['details']['sql'] as $type => $table_info) {
                foreach ($table_info as $table_name => $columns) {
                    $column_name = _field_sql_storage_columnname($field_name, 'my_new_view_additional_data');
                    // Adding my_new_view_additional_data.
                    if (!db_field_exists($table_name, $column_name)) {
                        // Calling schema defined in hook_recline_field_column().
                        $schema = my_new_view_additional_data();
                        db_add_field($table_name, $column_name, $schema);
                    }
                    // Adding my_new_view.
                    $column_name = _field_sql_storage_columnname($field_name, 'my_new_view');
                    $schema = recline_field_schema();
                    if (!db_field_exists($table_name, $column_name)) {
                        db_add_field($table_name, $column_name, $schema['columns']['my_new_view']);
                    }
                    field_cache_clear();
                }
            }
        }
    }
    return $ret;
}
/**
 * Execute an EntityFieldQuery.
 *
 * This hook is called to find the entities having certain entity and field
 * conditions and sort them in the given field order. If the field storage
 * engine also handles property sorts and orders, it should unset those
 * properties in the called object to signal that those have been handled.
 *
 * @param EntityFieldQuery $query
 *   An EntityFieldQuery.
 *
 * @return
 *   See EntityFieldQuery::execute() for the return values.
 */
function hook_field_storage_query($query)
{
    $groups = array();
    if ($query->age == FIELD_LOAD_CURRENT) {
        $tablename_function = '_field_sql_storage_tablename';
        $id_key = 'entity_id';
    } else {
        $tablename_function = '_field_sql_storage_revision_tablename';
        $id_key = 'revision_id';
    }
    $table_aliases = array();
    // Add tables for the fields used.
    foreach ($query->fields as $key => $field) {
        $tablename = $tablename_function($field);
        // Every field needs a new table.
        $table_alias = $tablename . $key;
        $table_aliases[$key] = $table_alias;
        if ($key) {
            $select_query->join($tablename, $table_alias, "{$table_alias}.entity_type = {$field_base_table}.entity_type AND {$table_alias}.{$id_key} = {$field_base_table}.{$id_key}");
        } else {
            $select_query = db_select($tablename, $table_alias);
            $select_query->addTag('entity_field_access');
            $select_query->addMetaData('base_table', $tablename);
            $select_query->fields($table_alias, array('entity_type', 'entity_id', 'revision_id', 'bundle'));
            $field_base_table = $table_alias;
        }
        if ($field['cardinality'] != 1) {
            $select_query->distinct();
        }
    }
    // Add field conditions.
    foreach ($query->fieldConditions as $key => $condition) {
        $table_alias = $table_aliases[$key];
        $field = $condition['field'];
        // Add the specified condition.
        $sql_field = "{$table_alias}." . _field_sql_storage_columnname($field['field_name'], $condition['column']);
        $query->addCondition($select_query, $sql_field, $condition);
        // Add delta / language group conditions.
        foreach (array('delta', 'language') as $column) {
            if (isset($condition[$column . '_group'])) {
                $group_name = $condition[$column . '_group'];
                if (!isset($groups[$column][$group_name])) {
                    $groups[$column][$group_name] = $table_alias;
                } else {
                    $select_query->where("{$table_alias}.{$column} = " . $groups[$column][$group_name] . ".{$column}");
                }
            }
        }
    }
    if (isset($query->deleted)) {
        $select_query->condition("{$field_base_table}.deleted", (int) $query->deleted);
    }
    // Is there a need to sort the query by property?
    $has_property_order = FALSE;
    foreach ($query->order as $order) {
        if ($order['type'] == 'property') {
            $has_property_order = TRUE;
        }
    }
    if ($query->propertyConditions || $has_property_order) {
        if (empty($query->entityConditions['entity_type']['value'])) {
            throw new EntityFieldQueryException('Property conditions and orders must have an entity type defined.');
        }
        $entity_type = $query->entityConditions['entity_type']['value'];
        $entity_base_table = _field_sql_storage_query_join_entity($select_query, $entity_type, $field_base_table);
        $query->entityConditions['entity_type']['operator'] = '=';
        foreach ($query->propertyConditions as $property_condition) {
            $query->addCondition($select_query, "{$entity_base_table}." . $property_condition['column'], $property_condition);
        }
    }
    foreach ($query->entityConditions as $key => $condition) {
        $query->addCondition($select_query, "{$field_base_table}.{$key}", $condition);
    }
    // Order the query.
    foreach ($query->order as $order) {
        if ($order['type'] == 'entity') {
            $key = $order['specifier'];
            $select_query->orderBy("{$field_base_table}.{$key}", $order['direction']);
        } elseif ($order['type'] == 'field') {
            $specifier = $order['specifier'];
            $field = $specifier['field'];
            $table_alias = $table_aliases[$specifier['index']];
            $sql_field = "{$table_alias}." . _field_sql_storage_columnname($field['field_name'], $specifier['column']);
            $select_query->orderBy($sql_field, $order['direction']);
        } elseif ($order['type'] == 'property') {
            $select_query->orderBy("{$entity_base_table}." . $order['specifier'], $order['direction']);
        }
    }
    return $query->finishQuery($select_query, $id_key);
}
 /**
  * Called to determine what to tell the clicksorter.
  */
 function click_sort($order)
 {
     // No column selected, can't continue.
     if (empty($this->options['click_sort_column'])) {
         return;
     }
     $this->ensure_my_table();
     $column = _field_sql_storage_columnname($this->definition['field_name'], _field_sql_storage_columnname($this->definition['subfield_name'], $this->options['click_sort_column']));
     if (!isset($this->aliases[$column])) {
         // Column is not in query; add a sort on it (without adding the column).
         $this->aliases[$column] = $this->table_alias . '.' . $column;
     }
     $this->query->add_orderby(NULL, NULL, $order, $this->aliases[$column]);
 }
 public static function changeSchema(array &$field, array $column_renames = array())
 {
     // Update the field schema
     $old_schema = array_intersect_key($field, array('columns' => '', 'indexes' => '', 'foreign keys' => ''));
     module_load_install($field['module']);
     $new_schema = (array) module_invoke($field['module'], 'field_schema', $field);
     $new_schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array());
     $field['data']['columns'] = $new_schema['columns'];
     $field['data']['indexes'] = $new_schema['indexes'];
     $field['data']['foreign keys'] = $new_schema['foreign keys'];
     $data_table = _field_sql_storage_tablename($field);
     $revision_table = _field_sql_storage_revision_tablename($field);
     // Validate that all the columns described in the existing schema actually exist.
     foreach (array_keys($old_schema['columns']) as $old_column) {
         $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
         if (!db_field_exists($data_table, $old_column_name)) {
             throw new Exception();
         }
         if (!db_field_exists($revision_table, $old_column_name)) {
             throw new Exception();
         }
         // Attempt to re-use any columns that have the same name.
         // This can be skipped by setting $column_renames['column-name'] = FALSE;
         if (!empty($new_schema['columns'][$old_column]) && !isset($column_renames[$old_column])) {
             $column_renames[$old_column] = $old_column;
         }
     }
     // Validate that any columns to be renamed actually exist.
     foreach ($column_renames as $old_column => $new_column) {
         if (!isset($old_schema['columns'][$old_column])) {
             throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} because it does not exist in the old schema.");
         }
         if (!isset($new_schema['columns'][$new_column])) {
             throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} to {$new_column} because it does not exist in the new schema.");
         }
     }
     // Remove all existing indexes.
     foreach ($old_schema['indexes'] as $index => $index_fields) {
         $index_name = _field_sql_storage_indexname($field['field_name'], $index);
         if (db_index_exists($data_table, $index_name)) {
             watchdog('helper', "Dropped index {$data_table}.{$index_name}");
             db_drop_index($data_table, $index_name);
         }
         if (db_index_exists($revision_table, $index_name)) {
             watchdog('helper', "Dropped index {$revision_table}.{$index_name}");
             db_drop_index($revision_table, $index_name);
         }
     }
     // Rename any columns.
     foreach ($column_renames as $old_column => $new_column) {
         $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
         if ($new_column === FALSE) {
             db_drop_field($data_table, $old_column_name);
             watchdog('helper', "Dropped column {$data_table}.{$old_column_name}");
             db_drop_field($revision_table, $old_column_name);
             watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}");
             unset($old_schema['columns'][$old_column]);
         } else {
             $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column);
             db_change_field($data_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]);
             watchdog('helper', "Changed column {$data_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>');
             db_change_field($revision_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]);
             watchdog('helper', "Changed column {$revision_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>');
             // Remove these fields so they aren't removed or added in the code below.
             unset($new_schema['columns'][$new_column]);
             unset($old_schema['columns'][$old_column]);
         }
     }
     // Remove any old columns.
     $old_columns = array_diff_key($old_schema['columns'], $new_schema['columns']);
     foreach (array_keys($old_columns) as $old_column) {
         $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
         db_drop_field($data_table, $old_column_name);
         watchdog('helper', "Dropped column {$data_table}.{$old_column_name}");
         db_drop_field($revision_table, $old_column_name);
         watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}");
     }
     // Add any new columns.
     $new_columns = array_diff_key($new_schema['columns'], $old_schema['columns']);
     foreach (array_keys($new_columns) as $new_column) {
         $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column);
         db_add_field($data_table, $new_column_name, $new_schema['columns'][$new_column]);
         watchdog('helper', "Added column {$data_table}.{$new_column_name}");
         db_add_field($revision_table, $new_column_name, $new_schema['columns'][$new_column]);
         watchdog('helper', "Added column {$revision_table}.{$new_column_name}");
     }
     // Re-add indexes.
     foreach ($new_schema['indexes'] as $index => $index_fields) {
         foreach ($index_fields as &$index_field) {
             if (is_array($index_field)) {
                 $index_field[0] = _field_sql_storage_columnname($field['field_name'], $index_field[0]);
             } else {
                 $index_field = _field_sql_storage_columnname($field['field_name'], $index_field);
             }
         }
         $index_name = _field_sql_storage_indexname($field['field_name'], $index);
         db_add_index($data_table, $index_name, $index_fields);
         watchdog('helper', "Added index {$data_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>');
         db_add_index($revision_table, $index_name, $index_fields);
         watchdog('helper', "Added index {$revision_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>');
     }
 }
/**
 * Execute an EntityFieldQuery.
 *
 * This hook is called to find the entities having certain entity and field
 * conditions and sort them in the given field order. If the field storage
 * engine also handles property sorts and orders, it should unset those
 * properties in the called object to signal that those have been handled.
 *
 * @param EntityFieldQuery $query
 *   An EntityFieldQuery.
 *
 * @return
 *   See EntityFieldQuery::execute() for the return values.
 */
function hook_field_storage_query($query)
{
    $load_current = $options['age'] == FIELD_LOAD_CURRENT;
    $field = field_info_field_by_id($field_id);
    $field_name = $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');
    // 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 'STARTS_WITH':
                $operator = 'LIKE';
                $value = db_like($value) . '%';
                break;
            case 'ENDS_WITH':
                $operator = 'LIKE';
                $value = '%' . db_like($value);
                break;
            case 'CONTAINS':
                $operator = 'LIKE';
                $value = '%' . db_like($value) . '%';
                break;
        }
        // Translate field columns into prefixed db columns.
        if (in_array($column, $field_columns)) {
            $column = _field_sql_storage_columnname($field_name, $column);
        }
        // Translate entity types into numeric ids. Expressing the condition on the
        // local 'etid' column rather than the JOINed 'type' column avoids a
        // filesort.
        if ($column == 'type') {
            $column = 't.etid';
            if (is_array($value)) {
                foreach (array_keys($value) as $key) {
                    $value[$key] = _field_sql_storage_etid($value[$key]);
                }
            } else {
                $value = _field_sql_storage_etid($value);
            }
        }
        // Track condition on 'deleted'.
        if ($column == 'deleted') {
            $condition_deleted = TRUE;
        }
        $query->condition($column, $value, $operator);
    }
    // Exclude deleted data unless we have a condition on it.
    if (!isset($condition_deleted)) {
        $query->condition('deleted', 0);
    }
    // For a count query, return the count now.
    if ($options['count']) {
        return $query->fields('t', array('etid', 'entity_id', 'revision_id'))->distinct()->countQuery()->execute()->fetchField();
    }
    // For a data query, add fields.
    $query->fields('t', array('bundle', 'entity_id', 'revision_id'))->fields('e', array('type'))->orderBy('t.etid')->orderBy('t.entity_id');
    // Initialize results array
    $return = array();
    // Getting $count entities possibly requires reading more than $count rows
    // since fields with multiple values span over several rows. We query for
    // batches of $count rows until we've either read $count entities or received
    // less rows than asked for.
    $entity_count = 0;
    do {
        if ($options['limit'] != FIELD_QUERY_NO_LIMIT) {
            $query->range($options['cursor'], $options['limit']);
        }
        $results = $query->execute();
        $row_count = 0;
        foreach ($results as $row) {
            $row_count++;
            $options['cursor']++;
            // If querying all revisions and the entity type has revisions, we need
            // to key the results by revision_ids.
            $entity_type = entity_get_info($row->type);
            $id = $load_current || empty($entity_type['entity keys']['revision']) ? $row->entity_id : $row->revision_id;
            if (!isset($return[$row->type][$id])) {
                $return[$row->type][$id] = entity_create_stub_entity($row->type, array($row->entity_id, $row->revision_id, $row->bundle));
                $entity_count++;
            }
        }
    } while ($options['limit'] != FIELD_QUERY_NO_LIMIT && $row_count == $options['limit'] && $entity_count < $options['limit']);
    // The query is complete when the last batch returns less rows than asked
    // for.
    if ($row_count < $options['limit']) {
        $options['cursor'] = FIELD_QUERY_COMPLETE;
    }
    return $return;
}
 /**
  * Copies field_sql_storage_field_storage_query() using left joins some times.
  *
  * @see field_sql_storage_field_storage_query()
  */
 protected function fieldStorageQuery(SelectQuery $select_query)
 {
     if ($this->age == FIELD_LOAD_CURRENT) {
         $tablename_function = '_field_sql_storage_tablename';
         $id_key = 'entity_id';
     } else {
         $tablename_function = '_field_sql_storage_revision_tablename';
         $id_key = 'revision_id';
     }
     $table_aliases = array();
     $query_tables = NULL;
     $base_table = $this->metaData['base_table'];
     // Add tables for the fields used.
     $field_base_table = NULL;
     foreach ($this->fields as $key => $field) {
         $tablename = $tablename_function($field);
         $table_alias = _field_sql_storage_tablealias($tablename, $key, $this);
         $table_aliases[$key] = $table_alias;
         $select_query->addMetaData('base_table', $base_table);
         $entity_id_key = $this->metaData['entity_id_key'];
         if ($field_base_table) {
             if (!isset($query_tables[$table_alias])) {
                 $this->addFieldJoin($select_query, $field['field_name'], $tablename, $table_alias, "{$table_alias}.entity_type = {$field_base_table}.entity_type AND {$table_alias}.{$id_key} = {$field_base_table}.{$id_key}");
             }
         } else {
             // By executing prePropertyQuery() we made sure that the base table is
             // the entity table.
             $this->addFieldJoin($select_query, $field['field_name'], $tablename, $table_alias, "{$base_table}.{$entity_id_key} = {$table_alias}.{$id_key}");
             // Store a reference to the list of joined tables.
             $query_tables =& $select_query->getTables();
             // Allow queries internal to the Field API to opt out of the access
             // check, for situations where the query's results should not depend on
             // the access grants for the current user.
             if (!isset($this->tags['DANGEROUS_ACCESS_CHECK_OPT_OUT'])) {
                 $select_query->addTag('entity_field_access');
             }
             if (!$this->containsLeftJoinOperator($this->fields[$key]['field_name'])) {
                 $field_base_table = $table_alias;
             }
         }
         if ($field['cardinality'] != 1 || $field['translatable']) {
             $select_query->distinct();
         }
     }
     // Add field conditions. We need a fresh grouping cache.
     drupal_static_reset('_field_sql_storage_query_field_conditions');
     _field_sql_storage_query_field_conditions($this, $select_query, $this->fieldConditions, $table_aliases, '_field_sql_storage_columnname');
     // Add field meta conditions.
     _field_sql_storage_query_field_conditions($this, $select_query, $this->fieldMetaConditions, $table_aliases, '_field_sql_storage_query_columnname');
     // If there was no field condition that created an INNER JOIN, that means
     // that additional JOINs need to carry the OR condition. For the base table
     // we'll use the table for the first field.
     $needs_or = FALSE;
     if (!isset($field_base_table)) {
         $needs_or = TRUE;
         // Get the table name for the first field.
         $field_table_name = key($this->fields[0]['storage']['details']['sql'][$this->age]);
         $field_base_table = _field_sql_storage_tablealias($field_table_name, 0, $this);
     }
     if (isset($this->deleted)) {
         $delete_condition = array('value' => (int) $this->deleted, 'operator' => '=', 'or' => $needs_or);
         $this->addCondition($select_query, "{$field_base_table}.deleted", $delete_condition);
     }
     foreach ($this->entityConditions as $key => $condition) {
         $condition['or'] = $needs_or;
         $this->addCondition($select_query, "{$field_base_table}.{$key}", $condition);
     }
     // Order the query.
     foreach ($this->order as $order) {
         if ($order['type'] == 'entity') {
             $key = $order['specifier'];
             $select_query->orderBy("{$field_base_table}.{$key}", $order['direction']);
         } elseif ($order['type'] == 'field') {
             $specifier = $order['specifier'];
             $field = $specifier['field'];
             $table_alias = $table_aliases[$specifier['index']];
             $sql_field = "{$table_alias}." . _field_sql_storage_columnname($field['field_name'], $specifier['column']);
             $select_query->orderBy($sql_field, $order['direction']);
         } elseif ($order['type'] == 'property') {
             $select_query->orderBy("{$base_table}." . $order['specifier'], $order['direction']);
         }
     }
     return array($select_query, $id_key);
 }