You are here

class EntityFieldQueryExtraFields in EntityFieldQuery Extra Fields 7

Hierarchy

Expanded class hierarchy of EntityFieldQueryExtraFields

File

./efq_extra_field.module, line 3

View source
class EntityFieldQueryExtraFields extends EntityFieldQuery {

  /**
   * Finishes the query.
   *
   * Adds tags, metaData, range and returns the requested list or count.
   *
   * @param SelectQuery $select_query
   *   A SelectQuery which has entity_type, entity_id, revision_id and bundle
   *   fields added.
   * @param $id_key
   *   Which field's values to use as the returned array keys.
   *
   * @return
   *   See EntityFieldQuery::execute().
   */
  private $addedFields = array();
  function finishQuery($select_query, $id_key = 'entity_id') {

    // http://drupal.org/node/1226622#comment-6809826 - adds support for IS NULL
    // Iterate through all fields.  If the query is trying to fetch results
    // where a field is null, then alter the query to use a LEFT OUTER join.
    // Otherwise the query will always return 0 results.
    $tables =& $select_query
      ->getTables();
    foreach ($this->fieldConditions as $key => $fieldCondition) {
      if ($fieldCondition['operator'] == 'IS NULL' && isset($this->fields[$key]['storage']['details']['sql'][FIELD_LOAD_CURRENT])) {
        $keys = array_keys($this->fields[$key]['storage']['details']['sql'][FIELD_LOAD_CURRENT]);
        $sql_table = reset($keys);
        foreach ($tables as $table_id => $table) {
          if ($table['table'] == $sql_table) {
            $tables[$table_id]['join type'] = 'LEFT OUTER';
          }
        }
      }
    }
    foreach ($this->tags as $tag) {
      $select_query
        ->addTag($tag);
    }
    foreach ($this->metaData as $key => $object) {
      $select_query
        ->addMetaData($key, $object);
    }
    $select_query
      ->addMetaData('entity_field_query', $this);
    if ($this->range) {
      $select_query
        ->range($this->range['start'], $this->range['length']);
    }
    if ($this->count) {
      return $select_query
        ->countQuery()
        ->execute()
        ->fetchField();
    }
    $return = array();
    foreach ($this->addedFields as $addedField) {
      $fields = $select_query
        ->getFields();
      if (!empty($addedField['field_name'])) {
        $tables = $select_query
          ->getTables();
        $clean_tables = $this
          ->cleanTables($tables);

        // hardcoded as it is also hardcoded in the fields module
        $table = 'field_data_' . $addedField['field_name'];

        // Get our alias for the selected field
        if (isset($clean_tables[$table])) {
          $addedField['table'] = $clean_tables[$table]['alias'];
        }

        // Set our name and alias
        $column = $addedField['field_name'] . '_' . $addedField['column'];
        $column_alias = $addedField['field_name'] . '_' . $addedField['column_alias'];
      }
      else {

        // Not from a field, so probably a direct entity property
        $column = $addedField['column'];
        $column_alias = $addedField['column_alias'];
      }
      if (!empty($addedField['table'])) {

        // if we know the exact table, set it
        $select_query
          ->addField($addedField['table'], $column, $column_alias);
      }
      else {

        // If not, use the main selected table to fetch the extra field from
        $select_query
          ->addField($fields['entity_id']['table'], $column, $column_alias);
      }
    }
    foreach ($select_query
      ->execute() as $partial_entity) {
      $bundle = isset($partial_entity->bundle) ? $partial_entity->bundle : NULL;
      $entity = entity_create_stub_entity($partial_entity->entity_type, array(
        $partial_entity->entity_id,
        $partial_entity->revision_id,
        $bundle,
      ));
      $entity->extraFields = $partial_entity;

      // If the id already exists, merge the data in a smart way. This
      // is completely based on the assumption that we expect a similar entity.
      if (isset($return[$partial_entity->entity_type][$partial_entity->{$id_key}])) {
        $previous_entity = $return[$partial_entity->entity_type][$partial_entity->{$id_key}];
        foreach ($previous_entity->extraFields as $id => $child) {

          // Found a distinct value, make it into an array.
          if (!is_array($previous_entity->extraFields->{$id})) {
            if ($entity->extraFields->{$id} != $previous_entity->extraFields->{$id}) {
              $entity->extraFields->{$id} = array(
                $previous_entity->extraFields->{$id},
                $entity->extraFields->{$id},
              );
            }
          }
          else {
            if (!in_array($entity->extraFields->{$id}, $previous_entity->extraFields->{$id})) {
              $previous_entity->extraFields->{$id}[] = $entity->extraFields->{$id};
              $entity->extraFields->{$id} = $previous_entity->extraFields->{$id};
            }
          }
        }
      }

      // Add the entity to the result set to return.
      $return[$partial_entity->entity_type][$partial_entity->{$id_key}] = $entity;
      $this->ordered_results[] = $partial_entity;
    }
    return $return;
  }

  /**
   * Add the given field with an INNER JOIN and add a select statement
   * for the requested field
   * @param type $field_name
   * @param type $column
   * @param type $column_alias
   * @param type $table
   * @return \EntityFieldQueryExtraFields
   */
  public function addExtraField($field_name, $column, $column_alias = NULL, $table = NULL) {
    if (!empty($field_name) && !$this
      ->checkFieldExists($field_name)) {

      // Add the field as a condition, so we generate the join
      $this
        ->fieldCondition($field_name);
    }
    $this->addedFields[] = array(
      'field_name' => $field_name,
      'column' => $column,
      'column_alias' => $column_alias,
      'table' => $table,
    );
    return $this;
  }

  /**
   * Give the values in the array the name of the real table instead of the
   * alias, so we can look up the alias quicker
   * @param type $tables
   * @return type
   */
  private function cleanTables($tables) {
    if (!is_array($tables)) {
      return array();
    }
    foreach ($tables as $table_id => $table) {
      if ($table['join type'] == 'INNER') {
        $tables[$table['table']] = $table;
        unset($tables[$table_id]);
      }
    }
    return $tables;
  }

  /**
   * Check if the field already has a table that does a join.
   * @param type $field_name
   * @return boolean
   */
  private function checkFieldExists($field_name) {
    $fields = $this->fields;
    foreach ($fields as $field) {
      if (isset($field['field_name']) && $field['field_name'] == $field_name) {
        return TRUE;
      }
    }
    return FALSE;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityFieldQuery::$age public property Flag indicating whether this is querying current or all revisions.
EntityFieldQuery::$altered public property TRUE if the query has already been altered, FALSE if it hasn't.
EntityFieldQuery::$count public property TRUE if this is a count query, FALSE if it isn't.
EntityFieldQuery::$deleted public property Query behavior for deleted data.
EntityFieldQuery::$entityConditions public property Associative array of entity-generic metadata conditions.
EntityFieldQuery::$executeCallback public property The method executing the query, if it is overriding the default.
EntityFieldQuery::$fieldConditions public property List of field conditions.
EntityFieldQuery::$fieldMetaConditions public property List of field meta conditions (language and delta).
EntityFieldQuery::$fields public property A list of field arrays used.
EntityFieldQuery::$metaData public property A list of metadata added to this query.
EntityFieldQuery::$order public property List of order clauses.
EntityFieldQuery::$orderedResults public property The ordered results.
EntityFieldQuery::$pager public property The query pager data.
EntityFieldQuery::$propertyConditions public property List of property conditions.
EntityFieldQuery::$range public property The query range.
EntityFieldQuery::$tags public property A list of the tags added to this query.
EntityFieldQuery::addCondition public function Adds a condition to an already built SelectQuery (internal function).
EntityFieldQuery::addFieldCondition protected function Adds the given condition to the proper condition array.
EntityFieldQuery::addMetaData public function Adds additional metadata to the query.
EntityFieldQuery::addTag public function Adds a tag to the query.
EntityFieldQuery::age public function Queries the current or every revision.
EntityFieldQuery::count public function Sets the query to be a count query only.
EntityFieldQuery::deleted public function Filters on the data being deleted.
EntityFieldQuery::entityCondition public function Adds a condition on entity-generic metadata.
EntityFieldQuery::entityOrderBy public function Orders the result set by entity-generic metadata.
EntityFieldQuery::execute public function Executes the query.
EntityFieldQuery::fieldCondition public function Adds a condition on field values.
EntityFieldQuery::fieldDeltaCondition public function Adds a condition on the field delta column.
EntityFieldQuery::fieldLanguageCondition public function Adds a condition on the field language column.
EntityFieldQuery::fieldOrderBy public function Orders the result set by a given field column.
EntityFieldQuery::initializePager function Gets the total number of results and initializes a pager for the query.
EntityFieldQuery::pager public function Enables a pager for the query.
EntityFieldQuery::propertyCondition public function Adds a condition on an entity-specific property.
EntityFieldQuery::propertyOrderBy public function Orders the result set by an entity-specific property.
EntityFieldQuery::propertyQuery protected function Queries entity tables in SQL for property conditions and sorts.
EntityFieldQuery::queryCallback public function Determines the query callback to use for this entity query.
EntityFieldQuery::range public function Restricts a query to a given range in the result set.
EntityFieldQuery::RETURN_ALL constant Indicates that both deleted and non-deleted fields should be returned.
EntityFieldQuery::tableSort public function Enables sortable tables for this query.
EntityFieldQueryExtraFields::$addedFields private property Finishes the query.
EntityFieldQueryExtraFields::addExtraField public function Add the given field with an INNER JOIN and add a select statement for the requested field
EntityFieldQueryExtraFields::checkFieldExists private function Check if the field already has a table that does a join.
EntityFieldQueryExtraFields::cleanTables private function Give the values in the array the name of the real table instead of the alias, so we can look up the alias quicker
EntityFieldQueryExtraFields::finishQuery function Finishes the query. Overrides EntityFieldQuery::finishQuery