FieldAttachStorageTest.php 16.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php

/**
 * @file
 * Definition of Drupal\field\Tests\FieldAttachStorageTest.
 */

namespace Drupal\field\Tests;

/**
webchick's avatar
webchick committed
11
 * Unit test class for storage-related field behavior.
12
 */
13
class FieldAttachStorageTest extends FieldUnitTestBase {
14 15 16 17

  /**
   * The field instance.
   *
18
   * @var \Drupal\field\Entity\FieldInstance
19 20 21 22 23 24 25 26 27 28
   */
  protected $instance;

  /**
   * Field name to use in the test.
   *
   * @var string
   */
  protected $field_name;

29 30 31 32 33 34 35 36
  public static function getInfo() {
    return array(
      'name' => 'Field attach tests (storage-related)',
      'description' => 'Test storage-related Field Attach API functions.',
      'group' => 'Field API',
    );
  }

37 38
  public function setUp() {
    parent::setUp();
39
    $this->installSchema('entity_test', array('entity_test_rev', 'entity_test_rev_revision'));
40 41
  }

42 43 44 45 46 47 48
  /**
   * Check field values insert, update and load.
   *
   * Works independently of the underlying field storage backend. Inserts or
   * updates random field data and then loads and verifies the data.
   */
  function testFieldAttachSaveLoad() {
49 50 51
    $entity_type = 'entity_test_rev';
    $this->createFieldWithInstance('', $entity_type);

52 53 54
    // Configure the instance so that we test hook_field_load() (see
    // field_test_field_load() in field_test.module).
    $this->instance['settings']['test_hook_field_load'] = TRUE;
55
    $this->instance->save();
56 57 58

    // TODO : test empty values filtering and "compression" (store consecutive deltas).
    // Preparation: create three revisions and store them in $revision array.
59
    $values = array();
60
    $entity = entity_create($entity_type, array());
61 62
    for ($revision_id = 0; $revision_id < 3; $revision_id++) {
      // Note: we try to insert one extra value.
63 64 65 66 67 68 69
      $current_values = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
      $entity->{$this->field_name}->setValue($current_values);
      $entity->setNewRevision();
      $entity->save();
      $entity_id = $entity->id();
      $current_revision = $entity->getRevisionId();
      $values[$current_revision] = $current_values;
70 71
    }

72
    $storage_controller =  $this->container->get('entity.manager')->getStorageController($entity_type);
73 74
    $storage_controller->resetCache();
    $entity = $storage_controller->load($entity_id);
75 76
    // Confirm current revision loads the correct data.
    // Number of values per field loaded equals the field cardinality.
77
    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], 'Current revision: expected number of values');
78 79
    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
      // The field value loaded matches the one inserted or updated.
80
      $this->assertEqual($entity->{$this->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
81
      // The value added in hook_field_load() is found.
82
      $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
83 84 85
    }

    // Confirm each revision loads the correct data.
86 87
    foreach (array_keys($values) as $revision_id) {
      $entity = $storage_controller->loadRevision($revision_id);
88
      // Number of values per field loaded equals the field cardinality.
89
      $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
90 91
      for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
        // The field value loaded matches the one inserted or updated.
92
        $this->assertEqual($entity->{$this->field_name}[$delta]->value, $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
93
        // The value added in hook_field_load() is found.
94
        $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
95 96 97 98 99 100 101 102
      }
    }
  }

  /**
   * Test the 'multiple' load feature.
   */
  function testFieldAttachLoadMultiple() {
103
    $entity_type = 'entity_test';
104 105 106 107 108 109

    // Define 2 bundles.
    $bundles = array(
      1 => 'test_bundle_1',
      2 => 'test_bundle_2',
    );
110 111
    entity_test_create_bundle($bundles[1]);
    entity_test_create_bundle($bundles[2]);
112 113 114 115 116 117 118 119 120 121 122
    // Define 3 fields:
    // - field_1 is in bundle_1 and bundle_2,
    // - field_2 is in bundle_1,
    // - field_3 is in bundle_2.
    $field_bundles_map = array(
      1 => array(1, 2),
      2 => array(1),
      3 => array(2),
    );
    for ($i = 1; $i <= 3; $i++) {
      $field_names[$i] = 'field_' . $i;
123 124 125 126 127
      $field = entity_create('field_entity', array(
        'name' => $field_names[$i],
        'entity_type' => $entity_type,
        'type' => 'test_field',
      ));
128
      $field->save();
129
      $field_ids[$i] = $field['uuid'];
130
      foreach ($field_bundles_map[$i] as $bundle) {
131
        entity_create('field_instance', array(
132
          'field_name' => $field_names[$i],
133
          'entity_type' => $entity_type,
134 135 136 137 138 139
          'bundle' => $bundles[$bundle],
          'settings' => array(
            // Configure the instance so that we test hook_field_load()
            // (see field_test_field_load() in field_test.module).
            'test_hook_field_load' => TRUE,
          ),
140
        ))->save();
141 142 143 144 145
      }
    }

    // Create one test entity per bundle, with random values.
    foreach ($bundles as $index => $bundle) {
146
      $entities[$index] = entity_create($entity_type, array('id' => $index, 'revision_id' => $index, 'type' => $bundle));
147
      $entity = clone($entities[$index]);
148
      $instances = field_info_instances($entity_type, $bundle);
149 150
      foreach ($instances as $field_name => $instance) {
        $values[$index][$field_name] = mt_rand(1, 127);
151
        $entity->$field_name->setValue(array('value' => $values[$index][$field_name]));
152
      }
153 154
      $entity->enforceIsnew();
      $entity->save();
155 156 157
    }

    // Check that a single load correctly loads field values for both entities.
158
    $controller = $this->container->get('entity.manager')->getStorageController($entity->entityType());
159 160
    $controller->resetCache();
    $entities = $controller->loadMultiple();
161 162 163 164
    foreach ($entities as $index => $entity) {
      $instances = field_info_instances($entity_type, $bundles[$index]);
      foreach ($instances as $field_name => $instance) {
        // The field value loaded matches the one inserted.
165
        $this->assertEqual($entity->{$field_name}->value, $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index)));
166
        // The value added in hook_field_load() is found.
167
        $this->assertEqual($entity->{$field_name}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
168 169 170 171 172
      }
    }
  }

  /**
173
   * Tests insert and update with empty or NULL fields.
174
   */
175
  function testFieldAttachSaveEmptyData() {
176
    $entity_type = 'entity_test';
177
    $this->createFieldWithInstance('', $entity_type);
178

179
    $entity_init = entity_create($entity_type, array('id' => 1));
180 181

    // Insert: Field is NULL.
182
    $entity = clone $entity_init;
183
    $entity->{$this->field_name} = NULL;
184 185
    $entity->enforceIsNew();
    $entity = $this->entitySaveReload($entity);
186
    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
187 188 189 190

    // Add some real data.
    $entity = clone($entity_init);
    $values = $this->_generateTestFieldValues(1);
191
    $entity->{$this->field_name} = $values;
192
    $entity = $this->entitySaveReload($entity);
193
    $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
194 195 196 197

    // Update: Field is NULL. Data should be wiped.
    $entity = clone($entity_init);
    $entity->{$this->field_name} = NULL;
198
    $entity = $this->entitySaveReload($entity);
199
    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: NULL field removes existing values');
200 201 202 203

    // Re-add some data.
    $entity = clone($entity_init);
    $values = $this->_generateTestFieldValues(1);
204
    $entity->{$this->field_name} = $values;
205
    $entity = $this->entitySaveReload($entity);
206
    $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
207 208 209 210

    // Update: Field is empty array. Data should be wiped.
    $entity = clone($entity_init);
    $entity->{$this->field_name} = array();
211
    $entity = $this->entitySaveReload($entity);
212
    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: empty array removes existing values');
213 214 215
  }

  /**
216
   * Test insert with empty or NULL fields, with default value.
217
   */
218 219 220 221
  function testFieldAttachSaveEmptyDataDefaultValue() {
    $entity_type = 'entity_test_rev';
    $this->createFieldWithInstance('', $entity_type);

222 223
    // Add a default value function.
    $this->instance['default_value_function'] = 'field_test_default_value';
224
    $this->instance->save();
225

226
    // Verify that fields are populated with default values.
227
    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
228
    $default = field_test_default_value($entity_init, $this->field, $this->instance);
229
    $this->assertEqual($entity_init->{$this->field_name}->getValue(), $default, 'Default field value correctly populated.');
230 231 232

    // Insert: Field is NULL.
    $entity = clone($entity_init);
233
    $entity->getBCEntity()->{$this->field_name} = NULL;
234 235
    $entity->enforceIsNew();
    $entity = $this->entitySaveReload($entity);
236
    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
237 238 239

    // Verify that prepopulated field values are not overwritten by defaults.
    $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127)));
240 241
    $entity = entity_create($entity_type, array('type' => $entity_init->bundle(), $this->field_name => $value));
    $this->assertEqual($entity->{$this->field_name}->getValue(), $value, 'Prepopulated field value correctly maintained.');
242 243 244
  }

  /**
245
   * Test entity deletion.
246 247
   */
  function testFieldAttachDelete() {
248 249
    $entity_type = 'entity_test_rev';
    $this->createFieldWithInstance('', $entity_type);
250 251
    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
    $vids = array();
252 253 254

    // Create revision 0
    $values = $this->_generateTestFieldValues($this->field['cardinality']);
255 256 257
    $entity->{$this->field_name} = $values;
    $entity->save();
    $vids[] = $entity->getRevisionId();
258 259

    // Create revision 1
260 261 262
    $entity->setNewRevision();
    $entity->save();
    $vids[] = $entity->getRevisionId();
263 264

    // Create revision 2
265 266 267
    $entity->setNewRevision();
    $entity->save();
    $vids[] = $entity->getRevisionId();
268
    $controller = $this->container->get('entity.manager')->getStorageController($entity->entityType());
269
    $controller->resetCache();
270 271

    // Confirm each revision loads
272 273 274
    foreach ($vids as $vid) {
      $revision = $controller->loadRevision($vid);
      $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
275 276 277
    }

    // Delete revision 1, confirm the other two still load.
278 279 280 281 282 283
    $controller->deleteRevision($vids[1]);
    $controller->resetCache();
    foreach (array(0, 2) as $key) {
      $vid = $vids[$key];
      $revision = $controller->loadRevision($vid);
      $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
284 285 286
    }

    // Confirm the current revision still loads
287 288 289
    $controller->resetCache();
    $current = $controller->load($entity->id());
    $this->assertEqual(count($current->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
290 291

    // Delete all field data, confirm nothing loads
292 293
    $entity->delete();
    $controller->resetCache();
294
    foreach (array(0, 1, 2) as $vid) {
295 296
      $revision = $controller->loadRevision($vid);
      $this->assertFalse($revision);
297
    }
298
    $this->assertFalse($controller->load($entity->id()));
299 300 301
  }

  /**
302
   * Test entity_bundle_create() and entity_bundle_rename().
303
   */
304
  function testEntityCreateRenameBundle() {
305 306 307
    $entity_type = 'entity_test_rev';
    $this->createFieldWithInstance('', $entity_type);

308
    // Create a new bundle.
309
    $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
310
    entity_test_create_bundle($new_bundle, NULL, $entity_type);
311 312

    // Add an instance to that bundle.
313 314
    $this->instance_definition['bundle'] = $new_bundle;
    entity_create('field_instance', $this->instance_definition)->save();
315 316

    // Save an entity with data in the field.
317
    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
318
    $values = $this->_generateTestFieldValues($this->field['cardinality']);
319
    $entity->{$this->field_name} = $values;
320 321

    // Verify the field data is present on load.
322
    $entity = $this->entitySaveReload($entity);
323
    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Data is retrieved for the new bundle");
324

325
    // Rename the bundle.
326
    $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
327
    entity_test_rename_bundle($this->instance_definition['bundle'], $new_bundle, $entity_type);
328 329 330 331 332 333

    // Check that the instance definition has been updated.
    $this->instance = field_info_instance($entity_type, $this->field_name, $new_bundle);
    $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance.");

    // Verify the field data is present on load.
334
    $controller = $this->container->get('entity.manager')->getStorageController($entity->entityType());
335 336
    $controller->resetCache();
    $entity = $controller->load($entity->id());
337
    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Bundle name has been updated in the field storage");
338 339 340
  }

  /**
341
   * Test entity_bundle_delete().
342
   */
343
  function testEntityDeleteBundle() {
344 345 346
    $entity_type = 'entity_test_rev';
    $this->createFieldWithInstance('', $entity_type);

347
    // Create a new bundle.
348
    $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
349
    entity_test_create_bundle($new_bundle, NULL, $entity_type);
350 351

    // Add an instance to that bundle.
352 353
    $this->instance_definition['bundle'] = $new_bundle;
    entity_create('field_instance', $this->instance_definition)->save();
354 355 356

    // Create a second field for the test bundle
    $field_name = drupal_strtolower($this->randomName() . '_field_name');
357 358 359 360 361 362
    $field = array(
      'name' => $field_name,
      'entity_type' => $entity_type,
      'type' => 'test_field',
      'cardinality' => 1,
    );
363
    entity_create('field_entity', $field)->save();
364 365
    $instance = array(
      'field_name' => $field_name,
366
      'entity_type' => $entity_type,
367 368 369 370
      'bundle' => $this->instance['bundle'],
      'label' => $this->randomName() . '_label',
      'description' => $this->randomName() . '_description',
      'weight' => mt_rand(0, 127),
371
    );
372
    entity_create('field_instance', $instance)->save();
373 374

    // Save an entity with data for both fields
375
    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
376
    $values = $this->_generateTestFieldValues($this->field['cardinality']);
377 378
    $entity->{$this->field_name} = $values;
    $entity->{$field_name} = $this->_generateTestFieldValues(1);
379
    $entity = $this->entitySaveReload($entity);
380 381

    // Verify the fields are present on load
382 383
    $this->assertEqual(count($entity->{$this->field_name}), 4, 'First field got loaded');
    $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded');
384

385
    // Delete the bundle.
386
    entity_test_delete_bundle($this->instance['bundle'], $entity_type);
387 388

    // Verify no data gets loaded
389
    $controller = $this->container->get('entity.manager')->getStorageController($entity->entityType());
390 391 392
    $controller->resetCache();
    $entity= $controller->load($entity->id());

393 394
    $this->assertTrue(empty($entity->{$this->field_name}), 'No data for first field');
    $this->assertTrue(empty($entity->{$field_name}), 'No data for second field');
395 396

    // Verify that the instances are gone
397 398
    $this->assertFalse(field_read_instance('entity_test', $this->field_name, $this->instance['bundle']), "First field is deleted");
    $this->assertFalse(field_read_instance('entity_test', $field_name, $instance['bundle']), "Second field is deleted");
399
  }
400

401
}