field_sql_storage.test

Tests for field_sql_storage.module.

Field_sql_storage.module implements the default back-end storage plugin for the Field Strage API.

File

modules/field/modules/field_sql_storage/field_sql_storage.test

View source
<?php


/**
 * @file
 * Tests for field_sql_storage.module.
 *
 * Field_sql_storage.module implements the default back-end storage plugin
 * for the Field Strage API.
 */

/**
 * Tests field storage.
 */
class FieldSqlStorageTestCase extends DrupalWebTestCase {
    protected $field;
    protected $instance;
    protected $field_name;
    protected $table;
    protected $revision_table;
    public static function getInfo() {
        return array(
            'name' => 'Field SQL storage tests',
            'description' => "Test field SQL storage module.",
            'group' => 'Field API',
        );
    }
    function setUp() {
        parent::setUp('field_sql_storage', 'field', 'field_test', 'text');
        $this->field_name = strtolower($this->randomName());
        $this->field = array(
            'field_name' => $this->field_name,
            'type' => 'test_field',
            'cardinality' => 4,
        );
        $this->field = field_create_field($this->field);
        $this->instance = array(
            'field_name' => $this->field_name,
            'entity_type' => 'test_entity',
            'bundle' => 'test_bundle',
        );
        $this->instance = field_create_instance($this->instance);
        $this->table = _field_sql_storage_tablename($this->field);
        $this->revision_table = _field_sql_storage_revision_tablename($this->field);
    }
    
    /**
     * Uses the mysql tables and records to verify
     * field_load_revision works correctly.
     */
    function testFieldAttachLoad() {
        $entity_type = 'test_entity';
        $eid = 0;
        $langcode = LANGUAGE_NONE;
        $columns = array(
            'entity_type',
            'entity_id',
            'revision_id',
            'delta',
            'language',
            $this->field_name . '_value',
        );
        // Insert data for four revisions to the field revisions table
        $query = db_insert($this->revision_table)
            ->fields($columns);
        for ($evid = 0; $evid < 4; ++$evid) {
            $values[$evid] = array();
            // Note: we insert one extra value ('<=' instead of '<').
            for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
                $value = mt_rand(1, 127);
                $values[$evid][] = $value;
                $query->values(array(
                    $entity_type,
                    $eid,
                    $evid,
                    $delta,
                    $langcode,
                    $value,
                ));
            }
        }
        $query->execute();
        // Insert data for the "most current revision" into the field table
        $query = db_insert($this->table)
            ->fields($columns);
        foreach ($values[0] as $delta => $value) {
            $query->values(array(
                $entity_type,
                $eid,
                0,
                $delta,
                $langcode,
                $value,
            ));
        }
        $query->execute();
        // Load the "most current revision"
        $entity = field_test_create_stub_entity($eid, 0, $this->instance['bundle']);
        field_attach_load($entity_type, array(
            $eid => $entity,
        ));
        foreach ($values[0] as $delta => $value) {
            if ($delta < $this->field['cardinality']) {
                $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value {$delta} is loaded correctly for current revision");
            }
            else {
                $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for current revision.");
            }
        }
        // Load every revision
        for ($evid = 0; $evid < 4; ++$evid) {
            $entity = field_test_create_stub_entity($eid, $evid, $this->instance['bundle']);
            field_attach_load_revision($entity_type, array(
                $eid => $entity,
            ));
            foreach ($values[$evid] as $delta => $value) {
                if ($delta < $this->field['cardinality']) {
                    $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value {$delta} for revision {$evid} is loaded correctly");
                }
                else {
                    $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for revision {$evid}.");
                }
            }
        }
        // Add a translation in an unavailable language and verify it is not loaded.
        $eid = $evid = 1;
        $unavailable_language = 'xx';
        $entity = field_test_create_stub_entity($eid, $evid, $this->instance['bundle']);
        $values = array(
            $entity_type,
            $eid,
            $evid,
            0,
            $unavailable_language,
            mt_rand(1, 127),
        );
        db_insert($this->table)
            ->fields($columns)
            ->values($values)
            ->execute();
        db_insert($this->revision_table)
            ->fields($columns)
            ->values($values)
            ->execute();
        field_attach_load($entity_type, array(
            $eid => $entity,
        ));
        $this->assertFalse(array_key_exists($unavailable_language, $entity->{$this->field_name}), 'Field translation in an unavailable language ignored');
    }
    
    /**
     * Tests adding a field with an entity ID type of string.
     */
    function testFieldSqlSchemaForEntityWithStringIdentifier() {
        // Test programmatically adding field with string ID.
        $field_name = 'string_id_example';
        $field = array(
            'field_name' => $field_name,
            'type' => 'text',
            'settings' => array(
                'max_length' => 255,
            ),
            'entity_id_type' => 'string',
        );
        field_create_field($field);
        $schema = drupal_get_schema('field_data_' . $field_name);
        $this->assertEqual($schema['fields']['entity_id']['type'], 'varchar');
        $this->assertEqual($schema['fields']['revision_id']['type'], 'varchar');
        // Test programmatically adding field with default ID(int).
        $field_name = 'default_id_example';
        $field = array(
            'field_name' => $field_name,
            'type' => 'text',
            'settings' => array(
                'max_length' => 255,
            ),
        );
        field_create_field($field);
        $schema = drupal_get_schema('field_data_' . $field_name);
        $this->assertEqual($schema['fields']['entity_id']['type'], 'int');
        $this->assertEqual($schema['fields']['revision_id']['type'], 'int');
    }
    
    /**
     * Reads mysql to verify correct data is
     * written when using insert and update.
     */
    function testFieldAttachInsertAndUpdate() {
        $entity_type = 'test_entity';
        $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
        $langcode = LANGUAGE_NONE;
        // Test insert.
        $values = array();
        // Note: we try to insert one extra value ('<=' instead of '<').
        // TODO : test empty values filtering and "compression" (store consecutive deltas).
        for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
            $values[$delta]['value'] = mt_rand(1, 127);
        }
        $entity->{$this->field_name}[$langcode] = $rev_values[0] = $values;
        field_attach_insert($entity_type, $entity);
        $rows = db_select($this->table, 't')
            ->fields('t')
            ->execute()
            ->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
        foreach ($values as $delta => $value) {
            if ($delta < $this->field['cardinality']) {
                $this->assertEqual($rows[$delta][$this->field_name . '_value'], $value['value'], format_string("Value %delta is inserted correctly", array(
                    '%delta' => $delta,
                )));
            }
            else {
                $this->assertFalse(array_key_exists($delta, $rows), "No extraneous value gets inserted.");
            }
        }
        // Test update.
        $entity = field_test_create_stub_entity(0, 1, $this->instance['bundle']);
        $values = array();
        // Note: we try to update one extra value ('<=' instead of '<').
        for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
            $values[$delta]['value'] = mt_rand(1, 127);
        }
        $entity->{$this->field_name}[$langcode] = $rev_values[1] = $values;
        field_attach_update($entity_type, $entity);
        $rows = db_select($this->table, 't')
            ->fields('t')
            ->execute()
            ->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
        foreach ($values as $delta => $value) {
            if ($delta < $this->field['cardinality']) {
                $this->assertEqual($rows[$delta][$this->field_name . '_value'], $value['value'], format_string("Value %delta is updated correctly", array(
                    '%delta' => $delta,
                )));
            }
            else {
                $this->assertFalse(array_key_exists($delta, $rows), "No extraneous value gets updated.");
            }
        }
        // Check that data for both revisions are in the revision table.
        // We make sure each value is stored correctly, then unset it.
        // When an entire revision's values are unset (remembering that we
        // put one extra value in $values per revision), unset the entire
        // revision. Then, if $rev_values is empty at the end, all
        // revision data was found.
        $results = db_select($this->revision_table, 't')
            ->fields('t')
            ->execute();
        foreach ($results as $row) {
            $this->assertEqual($row->{$this->field_name . '_value'}, $rev_values[$row->revision_id][$row->delta]['value'], "Value {$row->delta} for revision {$row->revision_id} stored correctly");
            unset($rev_values[$row->revision_id][$row->delta]);
            if (count($rev_values[$row->revision_id]) == 1) {
                unset($rev_values[$row->revision_id]);
            }
        }
        $this->assertTrue(empty($rev_values), "All values for all revisions are stored in revision table {$this->revision_table}");
        // Check that update leaves the field data untouched if
        // $entity->{$field_name} is absent.
        unset($entity->{$this->field_name});
        field_attach_update($entity_type, $entity);
        $rows = db_select($this->table, 't')
            ->fields('t')
            ->execute()
            ->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
        foreach ($values as $delta => $value) {
            if ($delta < $this->field['cardinality']) {
                $this->assertEqual($rows[$delta][$this->field_name . '_value'], $value['value'], format_string("Update with no field_name entry leaves value %delta untouched", array(
                    '%delta' => $delta,
                )));
            }
        }
        // Check that update with an empty $entity->$field_name empties the field.
        $entity->{$this->field_name} = NULL;
        field_attach_update($entity_type, $entity);
        $rows = db_select($this->table, 't')
            ->fields('t')
            ->execute()
            ->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
        $this->assertEqual(count($rows), 0, "Update with an empty field_name entry empties the field.");
    }
    
    /**
     * Tests insert and update with missing or NULL fields.
     */
    function testFieldAttachSaveMissingData() {
        $entity_type = 'test_entity';
        $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
        $langcode = LANGUAGE_NONE;
        // Insert: Field is missing
        field_attach_insert($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 0, 'Missing field results in no inserts');
        // Insert: Field is NULL
        $entity->{$this->field_name} = NULL;
        field_attach_insert($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 0, 'NULL field results in no inserts');
        // Add some real data
        $entity->{$this->field_name}[$langcode] = array(
            0 => array(
                'value' => 1,
            ),
        );
        field_attach_insert($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 1, 'Field data saved');
        // Update: Field is missing. Data should survive.
        unset($entity->{$this->field_name});
        field_attach_update($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 1, 'Missing field leaves data in table');
        // Update: Field is NULL. Data should be wiped.
        $entity->{$this->field_name} = NULL;
        field_attach_update($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 0, 'NULL field leaves no data in table');
        // Add a translation in an unavailable language.
        $unavailable_language = 'xx';
        db_insert($this->table)
            ->fields(array(
            'entity_type',
            'bundle',
            'deleted',
            'entity_id',
            'revision_id',
            'delta',
            'language',
        ))
            ->values(array(
            $entity_type,
            $this->instance['bundle'],
            0,
            0,
            0,
            0,
            $unavailable_language,
        ))
            ->execute();
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 1, 'Field translation in an unavailable language saved.');
        // Again add some real data.
        $entity->{$this->field_name}[$langcode] = array(
            0 => array(
                'value' => 1,
            ),
        );
        field_attach_insert($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 2, 'Field data saved.');
        // Update: Field translation is missing but field is not empty. Translation
        // data should survive.
        $entity->{$this->field_name}[$unavailable_language] = array(
            mt_rand(1, 127),
        );
        unset($entity->{$this->field_name}[$langcode]);
        field_attach_update($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 2, 'Missing field translation leaves data in table.');
        // Update: Field translation is NULL but field is not empty. Translation
        // data should be wiped.
        $entity->{$this->field_name}[$langcode] = NULL;
        field_attach_update($entity_type, $entity);
        $count = db_select($this->table)
            ->countQuery()
            ->execute()
            ->fetchField();
        $this->assertEqual($count, 1, 'NULL field translation is wiped.');
    }
    
    /**
     * Tests the expected return values of _field_sql_storage_write_compare().
     */
    public function testFieldCompareDataModification() {
        $langcode = LANGUAGE_NONE;
        $field_info = field_info_field($this->field_name);
        // Make sure we have 2 sample field values that are unique.
        $value1 = 0;
        $value2 = 0;
        while ($value1 == $value2) {
            $value1 = mt_rand();
            $value2 = (string) mt_rand();
        }
        // Create the 2 entities to compare.
        $entity = field_test_create_stub_entity();
        $entity->{$this->field_name}[$langcode][]['value'] = $value1;
        $entity1 = clone $entity;
        $entity2 = clone $entity;
        // Make sure that it correctly compares identical entities.
        $this->assert(!_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'The entities are identical.');
        // Compare to an empty object.
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, new stdClass()), 'The entity is not the same as an empty object.');
        // Change one of the values.
        $entity2->{$this->field_name}[$langcode][0]['value'] = $value2;
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'The values are not the same.');
        // Reset $entity2.
        $entity2 = clone $entity;
        // Duplicate the value on one of the entities.
        $entity1->{$this->field_name}[$langcode][]['value'] = $value1;
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'The fields do not have the same number of values.');
        // Add a second value to both entities.
        $entity2->{$this->field_name}[$langcode][]['value'] = $value2;
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'The values are not the same.');
        // Replace the array containing the value with the actual value.
        $entity2->{$this->field_name}[$langcode] = $entity2->{$this->field_name}[$langcode][0];
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'The array to hold field values is replaced by the value.');
        // Null one value.
        $entity2->{$this->field_name}[$langcode] = NULL;
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'One field is NULL and the other is not.');
        // Null both values.
        $entity1->{$this->field_name}[$langcode] = NULL;
        $this->assert(!_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'Both fields are NULL.');
        // Unset one of the fields.
        unset($entity2->{$this->field_name});
        $this->assert(_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'One field structure is unset.');
        // Unset both of the fields.
        unset($entity1->{$this->field_name});
        $this->assert(!_field_sql_storage_write_compare($field_info, $entity1, $entity2), 'Both field structures are unset.');
    }
    
    /**
     * Test trying to update a field with data.
     */
    function testUpdateFieldSchemaWithData() {
        // Create a decimal 5.2 field and add some data.
        $field = array(
            'field_name' => 'decimal52',
            'type' => 'number_decimal',
            'settings' => array(
                'precision' => 5,
                'scale' => 2,
            ),
        );
        $field = field_create_field($field);
        $instance = array(
            'field_name' => 'decimal52',
            'entity_type' => 'test_entity',
            'bundle' => 'test_bundle',
        );
        $instance = field_create_instance($instance);
        $entity = field_test_create_stub_entity(0, 0, $instance['bundle']);
        $entity->decimal52[LANGUAGE_NONE][0]['value'] = '1.235';
        field_attach_insert('test_entity', $entity);
        // Attempt to update the field in a way that would work without data.
        $field['settings']['scale'] = 3;
        try {
            field_update_field($field);
            $this->fail(t('Cannot update field schema with data.'));
        } catch (FieldException $e) {
            $this->pass(t('Cannot update field schema with data.'));
        }
    }
    
    /**
     * Test that failure to create fields is handled gracefully.
     */
    function testFieldUpdateFailure() {
        // Create a text field.
        $field = array(
            'field_name' => 'test_text',
            'type' => 'text',
            'settings' => array(
                'max_length' => 255,
            ),
        );
        $field = field_create_field($field);
        // Attempt to update the field in a way that would break the storage. The
        // parenthesis suffix is needed because SQLite has *very* relaxed rules for
        // data types, so we actually need to provide an invalid SQL syntax in order
        // to break it.
        // @see https://www.sqlite.org/datatype3.html
        $prior_field = $field;
        $field['settings']['max_length'] = '-1)';
        try {
            field_update_field($field);
            $this->fail(t('Update succeeded.'));
        } catch (Exception $e) {
            $this->pass(t('Update properly failed.'));
        }
        // Ensure that the field tables are still there.
        foreach (_field_sql_storage_schema($prior_field) as $table_name => $table_info) {
            $this->assertTrue(db_table_exists($table_name), format_string('Table %table exists.', array(
                '%table' => $table_name,
            )));
        }
    }
    
    /**
     * Test adding and removing indexes while data is present.
     */
    function testFieldUpdateIndexesWithData() {
        // Create a decimal field.
        $field_name = 'testfield';
        $field = array(
            'field_name' => $field_name,
            'type' => 'text',
        );
        $field = field_create_field($field);
        $instance = array(
            'field_name' => $field_name,
            'entity_type' => 'test_entity',
            'bundle' => 'test_bundle',
        );
        $instance = field_create_instance($instance);
        $tables = array(
            _field_sql_storage_tablename($field),
            _field_sql_storage_revision_tablename($field),
        );
        // Verify the indexes we will create do not exist yet.
        foreach ($tables as $table) {
            $this->assertFalse(Database::getConnection()->schema()
                ->indexExists($table, 'value'), format_string("No index named value exists in %table", array(
                '%table' => $table,
            )));
            $this->assertFalse(Database::getConnection()->schema()
                ->indexExists($table, 'value_format'), format_string("No index named value_format exists in %table", array(
                '%table' => $table,
            )));
        }
        // Add data so the table cannot be dropped.
        $entity = field_test_create_stub_entity(0, 0, $instance['bundle']);
        $entity->{$field_name}[LANGUAGE_NONE][0]['value'] = 'field data';
        field_attach_insert('test_entity', $entity);
        // Add an index
        $field = array(
            'field_name' => $field_name,
            'indexes' => array(
                'value' => array(
                    array(
                        'value',
                        255,
                    ),
                ),
            ),
        );
        field_update_field($field);
        foreach ($tables as $table) {
            $this->assertTrue(Database::getConnection()->schema()
                ->indexExists($table, "{$field_name}_value"), format_string("Index on value created in %table", array(
                '%table' => $table,
            )));
        }
        // Add a different index, removing the existing custom one.
        $field = array(
            'field_name' => $field_name,
            'indexes' => array(
                'value_format' => array(
                    array(
                        'value',
                        127,
                    ),
                    array(
                        'format',
                        127,
                    ),
                ),
            ),
        );
        field_update_field($field);
        foreach ($tables as $table) {
            $this->assertTrue(Database::getConnection()->schema()
                ->indexExists($table, "{$field_name}_value_format"), format_string("Index on value_format created in %table", array(
                '%table' => $table,
            )));
            $this->assertFalse(Database::getConnection()->schema()
                ->indexExists($table, "{$field_name}_value"), format_string("Index on value removed in %table", array(
                '%table' => $table,
            )));
        }
        // Verify that the tables were not dropped.
        $entity = field_test_create_stub_entity(0, 0, $instance['bundle']);
        field_attach_load('test_entity', array(
            0 => $entity,
        ));
        $this->assertEqual($entity->{$field_name}[LANGUAGE_NONE][0]['value'], 'field data', "Index changes performed without dropping the tables");
    }
    
    /**
     * Test the storage details.
     */
    function testFieldStorageDetails() {
        $current = _field_sql_storage_tablename($this->field);
        $revision = _field_sql_storage_revision_tablename($this->field);
        // Retrieve the field and instance with field_info so the storage details are attached.
        $field = field_info_field($this->field['field_name']);
        $instance = field_info_instance($this->instance['entity_type'], $this->instance['field_name'], $this->instance['bundle']);
        // The storage details are indexed by a storage engine type.
        $this->assertTrue(array_key_exists('sql', $field['storage']['details']), 'The storage type is SQL.');
        // The SQL details are indexed by table name.
        $details = $field['storage']['details']['sql'];
        $this->assertTrue(array_key_exists($current, $details[FIELD_LOAD_CURRENT]), 'Table name is available in the instance array.');
        $this->assertTrue(array_key_exists($revision, $details[FIELD_LOAD_REVISION]), 'Revision table name is available in the instance array.');
        // Test current and revision storage details together because the columns
        // are the same.
        foreach ((array) $this->field['columns'] as $column_name => $attributes) {
            $storage_column_name = _field_sql_storage_columnname($this->field['field_name'], $column_name);
            $this->assertEqual($details[FIELD_LOAD_CURRENT][$current][$column_name], $storage_column_name, format_string('Column name %value matches the definition in %bin.', array(
                '%value' => $column_name,
                '%bin' => $current,
            )));
            $this->assertEqual($details[FIELD_LOAD_REVISION][$revision][$column_name], $storage_column_name, format_string('Column name %value matches the definition in %bin.', array(
                '%value' => $column_name,
                '%bin' => $revision,
            )));
        }
    }
    
    /**
     * Test foreign key support.
     */
    function testFieldSqlStorageForeignKeys() {
        // Create a 'shape' field, with a configurable foreign key (see
        // field_test_field_schema()).
        $field_name = 'testfield';
        $foreign_key_name = 'shape';
        $field = array(
            'field_name' => $field_name,
            'type' => 'shape',
            'settings' => array(
                'foreign_key_name' => $foreign_key_name,
            ),
        );
        field_create_field($field);
        // Retrieve the field definition and check that the foreign key is in place.
        $field = field_info_field($field_name);
        $this->assertEqual($field['foreign keys'][$foreign_key_name]['table'], $foreign_key_name, 'Foreign key table name preserved through CRUD');
        $this->assertEqual($field['foreign keys'][$foreign_key_name]['columns'][$foreign_key_name], 'id', 'Foreign key column name preserved through CRUD');
        // Update the field settings, it should update the foreign key definition
        // too.
        $foreign_key_name = 'color';
        $field['settings']['foreign_key_name'] = $foreign_key_name;
        field_update_field($field);
        // Retrieve the field definition and check that the foreign key is in place.
        $field = field_info_field($field_name);
        $this->assertEqual($field['foreign keys'][$foreign_key_name]['table'], $foreign_key_name, 'Foreign key table name modified after update');
        $this->assertEqual($field['foreign keys'][$foreign_key_name]['columns'][$foreign_key_name], 'id', 'Foreign key column name modified after update');
        // Now grab the SQL schema and verify that too.
        $schema = drupal_get_schema(_field_sql_storage_tablename($field), TRUE);
        $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema');
        $foreign_key = reset($schema['foreign keys']);
        $foreign_key_column = _field_sql_storage_columnname($field['field_name'], $foreign_key_name);
        $this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema');
        $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema');
    }
    
    /**
     * Test handling multiple conditions on one column of a field.
     *
     * Tests both the result and the complexity of the query.
     */
    function testFieldSqlStorageMultipleConditionsSameColumn() {
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$this->field_name}[LANGUAGE_NONE][0] = array(
            'value' => 1,
        );
        field_test_entity_save($entity);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$this->field_name}[LANGUAGE_NONE][0] = array(
            'value' => 2,
        );
        field_test_entity_save($entity);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$this->field_name}[LANGUAGE_NONE][0] = array(
            'value' => 3,
        );
        field_test_entity_save($entity);
        $query = new EntityFieldQuery();
        // This tag causes field_test_query_store_global_test_query_alter() to be
        // invoked so that the query can be tested.
        $query->addTag('store_global_test_query');
        $query->entityCondition('entity_type', 'test_entity');
        $query->entityCondition('bundle', 'test_bundle');
        $query->fieldCondition($this->field_name, 'value', 1, '<>', 0, LANGUAGE_NONE);
        $query->fieldCondition($this->field_name, 'value', 2, '<>', 0, LANGUAGE_NONE);
        $result = field_sql_storage_field_storage_query($query);
        // Test the results.
        $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array(
            '@count' => count($result),
        )));
        // Test the complexity of the query.
        $query = $GLOBALS['test_query'];
        $this->assertNotNull($query, 'Precondition: the query should be available');
        $tables = $query->getTables();
        $this->assertEqual(1, count($tables), 'The query contains just one table.');
        // Clean up.
        unset($GLOBALS['test_query']);
    }
    
    /**
     * Test handling multiple conditions on multiple columns of one field.
     *
     * Tests both the result and the complexity of the query.
     */
    function testFieldSqlStorageMultipleConditionsDifferentColumns() {
        // Create the multi-column shape field
        $field_name = strtolower($this->randomName());
        $field = array(
            'field_name' => $field_name,
            'type' => 'shape',
            'cardinality' => 4,
        );
        $field = field_create_field($field);
        $instance = array(
            'field_name' => $field_name,
            'entity_type' => 'test_entity',
            'bundle' => 'test_bundle',
        );
        $instance = field_create_instance($instance);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$field_name}[LANGUAGE_NONE][0] = array(
            'shape' => 'A',
            'color' => 'X',
        );
        field_test_entity_save($entity);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$field_name}[LANGUAGE_NONE][0] = array(
            'shape' => 'B',
            'color' => 'X',
        );
        field_test_entity_save($entity);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$field_name}[LANGUAGE_NONE][0] = array(
            'shape' => 'A',
            'color' => 'Y',
        );
        field_test_entity_save($entity);
        $query = new EntityFieldQuery();
        // This tag causes field_test_query_store_global_test_query_alter() to be
        // invoked so that the query can be tested.
        $query->addTag('store_global_test_query');
        $query->entityCondition('entity_type', 'test_entity');
        $query->entityCondition('bundle', 'test_bundle');
        $query->fieldCondition($field_name, 'shape', 'B', '=', 'something', LANGUAGE_NONE);
        $query->fieldCondition($field_name, 'color', 'X', '=', 'something', LANGUAGE_NONE);
        $result = field_sql_storage_field_storage_query($query);
        // Test the results.
        $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array(
            '@count' => count($result),
        )));
        // Test the complexity of the query.
        $query = $GLOBALS['test_query'];
        $this->assertNotNull($query, 'Precondition: the query should be available');
        $tables = $query->getTables();
        $this->assertEqual(1, count($tables), 'The query contains just one table.');
        // Clean up.
        unset($GLOBALS['test_query']);
    }
    
    /**
     * Test handling multiple conditions on multiple columns of one field for multiple languages.
     *
     * Tests both the result and the complexity of the query.
     */
    function testFieldSqlStorageMultipleConditionsDifferentColumnsMultipleLanguages() {
        field_test_entity_info_translatable('test_entity', TRUE);
        // Create the multi-column shape field
        $field_name = strtolower($this->randomName());
        $field = array(
            'field_name' => $field_name,
            'type' => 'shape',
            'cardinality' => 4,
            'translatable' => TRUE,
        );
        $field = field_create_field($field);
        $instance = array(
            'field_name' => $field_name,
            'entity_type' => 'test_entity',
            'bundle' => 'test_bundle',
            'settings' => array(
                // Prevent warning from field_test_field_load().
'test_hook_field_load' => FALSE,
            ),
        );
        $instance = field_create_instance($instance);
        $entity = field_test_create_stub_entity(NULL, NULL);
        $entity->{$field_name}[LANGUAGE_NONE][0] = array(
            'shape' => 'A',
            'color' => 'X',
        );
        $entity->{$field_name}['en'][0] = array(
            'shape' => 'B',
            'color' => 'Y',
        );
        field_test_entity_save($entity);
        $entity = field_test_entity_test_load($entity->ftid);
        $query = new EntityFieldQuery();
        // This tag causes field_test_query_store_global_test_query_alter() to be
        // invoked so that the query can be tested.
        $query->addTag('store_global_test_query');
        $query->entityCondition('entity_type', 'test_entity');
        $query->entityCondition('bundle', 'test_bundle');
        $query->fieldCondition($field_name, 'color', 'X', '=', NULL, LANGUAGE_NONE);
        $query->fieldCondition($field_name, 'shape', 'B', '=', NULL, 'en');
        $result = field_sql_storage_field_storage_query($query);
        // Test the results.
        $this->assertEqual(1, count($result), format_string('One result should be returned, got @count', array(
            '@count' => count($result),
        )));
        // Test the complexity of the query.
        $query = $GLOBALS['test_query'];
        $this->assertNotNull($query, 'Precondition: the query should be available');
        $tables = $query->getTables();
        $this->assertEqual(2, count($tables), 'The query contains two tables.');
        // Clean up.
        unset($GLOBALS['test_query']);
    }

}

Classes

Title Deprecated Summary
FieldSqlStorageTestCase Tests field storage.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.