field_collection.test in Field collection 7
Tests for field_collections.
File
field_collection.testView source
<?php
/**
* @file
* Tests for field_collections.
*/
/**
* Test basics.
*/
class FieldCollectionBasicTestCase extends DrupalWebTestCase {
/**
*
*/
public static function getInfo() {
return array(
'name' => 'Field collection',
'description' => 'Tests creating and using field collections.',
'group' => 'Field types',
);
}
/**
*
*/
public function setUp() {
parent::setUp('field_collection', 'entity_crud_hook_test');
// Create a field_collection field to use for the tests.
$this->field_name = 'field_test_collection';
$this->field = array(
'field_name' => $this->field_name,
'type' => 'field_collection',
'cardinality' => 4,
);
$this->field = field_create_field($this->field);
$this->field_id = $this->field['id'];
$this->instance = array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'article',
'label' => self::randomName() . '_label',
'description' => self::randomName() . '_description',
'weight' => random_int(0, 127),
'settings' => array(),
'widget' => array(
'type' => 'hidden',
'label' => 'Test',
'settings' => array(),
),
);
$this->instance = field_create_instance($this->instance);
}
/**
* Pass if the message $text was set by one of the CRUD hooks in
* entity_crud_hook_test.module, i.e., if the $text is an element of
* $_SESSION['entity_crud_hook_test'].
*
* @see EntityCrudHookTestCase::assertHookMessage()
* @see FieldCollectionBasicTestCase::assertNoHookMessage()
* @see FieldCollectionBasicTestCase::clearHookMessages()
*
* @param $text
* Plain text to look for.
* @param $message
* Message to display.
* @param $group
* The group this message belongs to, defaults to 'Other'.
*
* @return
* TRUE on pass, FALSE on fail.
*/
protected function assertHookMessage($text, $message = NULL, $group = 'Other') {
if (!isset($message)) {
$message = $text;
}
return $this
->assertTrue(in_array($text, $_SESSION['entity_crud_hook_test']), $message, $group);
}
/**
* Fail if the message $text was set by one of the CRUD hooks in
* entity_crud_hook_test.module, i.e., if the $text is an element of
* $_SESSION['entity_crud_hook_test'].
*
* @see FieldCollectionBasicTestCase::assertHookMessage()
* @see FieldCollectionBasicTestCase::clearHookMessages()
*
* @param $text
* Plain text to look for.
* @param $message
* Message to display.
* @param $group
* The group this message belongs to, defaults to 'Other'.
*
* @return bool
* TRUE on pass, FALSE on fail.
*/
protected function assertNoHookMessage($text, $message = NULL, $group = 'Other') {
if (!isset($message)) {
$message = $text;
}
return $this
->assertFalse(in_array($text, $_SESSION['entity_crud_hook_test']), $message, $group);
}
/**
* Clear hook messages recorded by entity_crud_hook_test.
*
* @see FieldCollectionBasicTestCase::assertHookMessage()
* @see FieldCollectionBasicTestCase::assertNoHookMessage()
*/
protected function clearHookMessages() {
$_SESSION['entity_crud_hook_test'] = array();
}
/**
* Helper for creating a new node with a field collection item.
*/
protected function createNodeWithFieldCollection() {
$node = $this
->drupalCreateNode(array(
'type' => 'article',
));
// Manually create a field_collection.
$entity = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$entity
->setHostEntity('node', $node);
$entity
->save();
return array(
$node,
$entity,
);
}
/**
* Tests CRUD.
*/
public function testCRUD() {
list($node, $entity) = $this
->createNodeWithFieldCollection();
$node = node_load($node->nid, NULL, TRUE);
$this
->assertEqual($entity->item_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['value'], 'A field_collection has been successfully created and referenced.');
$this
->assertEqual($entity->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id'], 'A field_collection has been successfully created and referenced.');
// Test adding an additional field_collection during node edit.
$entity2 = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$node->{$this->field_name}[LANGUAGE_NONE][] = array(
'entity' => $entity2,
);
node_save($node);
$node = node_load($node->nid, NULL, TRUE);
$this
->assertTrue(!empty($entity2->item_id) && !empty($entity2->revision_id), 'Field_collection has been saved.');
$this
->assertEqual($entity->item_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['value'], 'Existing reference has been kept during update.');
$this
->assertEqual($entity->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id'], 'Existing reference has been kept during update (revision).');
$this
->assertEqual($entity2->item_id, $node->{$this->field_name}[LANGUAGE_NONE][1]['value'], 'New field_collection has been properly referenced');
$this
->assertEqual($entity2->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][1]['revision_id'], 'New field_collection has been properly referenced (revision)');
// Make sure deleting the field_collection removes the reference.
$this
->clearHookMessages();
$entity2
->delete();
$this
->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
$node = node_load($node->nid, NULL, TRUE);
$this
->assertTrue(!isset($node->{$this->field_name}[LANGUAGE_NONE][1]), 'Reference correctly deleted.');
// Make sure field_collections are removed during deletion of the host.
$this
->clearHookMessages();
node_delete($node->nid);
$this
->assertNoHookMessage('entity_crud_hook_test_entity_presave called for type node');
$this
->assertTrue(entity_load('field_collection_item') === array(), 'Field collections are deleted when the host is deleted.');
// Try deleting nodes with collections without any values.
$node = $this
->drupalCreateNode(array(
'type' => 'article',
));
node_delete($node->nid);
$this
->assertTrue(node_load($node->nid, NULL, TRUE) == FALSE, 'Node without collection values deleted.');
// Test creating a field collection entity with a not-yet saved host entity.
$node = entity_create('node', array(
'type' => 'article',
));
$entity = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$entity
->setHostEntity('node', $node);
$entity
->save();
// Now the node should have been saved with the collection and the link
// should have been established.
$this
->assertTrue(!empty($node->nid), 'Node has been saved with the collection.');
$this
->assertTrue(count($node->{$this->field_name}[LANGUAGE_NONE]) == 1 && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']) && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'Link has been established.');
// Again, test creating a field collection with a not-yet saved host entity,
// but this time save both entities via the host.
$node = entity_create('node', array(
'type' => 'article',
));
$entity = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$entity
->setHostEntity('node', $node);
node_save($node);
$this
->assertTrue(!empty($entity->item_id) && !empty($entity->revision_id), 'Collection has been saved with the host.');
$this
->assertTrue(count($node->{$this->field_name}[LANGUAGE_NONE]) == 1 && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']) && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'Link has been established.');
// Test Revisions.
list($node, $item) = $this
->createNodeWithFieldCollection();
$entity2 = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$node->{$this->field_name}[LANGUAGE_NONE][] = array(
'entity' => $entity2,
);
node_save($node);
$this
->assertEqual($entity2->archived, FALSE, 'New field collection item with new content revision is not archived.');
// Test saving a new revision of a node.
$node->revision = TRUE;
node_save($node);
$item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
$this
->assertNotEqual($item->revision_id, $item_updated->revision_id, 'Creating a new host entity revision creates a new field collection revision.');
// Test saving a new revision with a new field collection item.
$node->revision = TRUE;
// Test saving the node without creating a new revision.
$item = $item_updated;
$node->revision = FALSE;
node_save($node);
$item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
$this
->assertEqual($item->revision_id, $item_updated->revision_id, 'Updating a new host entity without creating a new revision does not create a new field collection revision.');
// Create a new revision of the node, such we have a non default node and
// field collection revision. Then test using it.
$vid = $node->vid;
$item_revision_id = $item_updated->revision_id;
$node->revision = TRUE;
node_save($node);
$item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
$this
->assertNotEqual($item_revision_id, $item_updated->revision_id, 'Creating a new host entity revision creates a new field collection revision.');
$this
->assertTrue($item_updated
->isDefaultRevision(), 'Field collection of default host entity revision is default too.');
$this
->assertEqual($item_updated
->hostEntityId(), $node->nid, 'Can access host entity ID of default field collection revision.');
$this
->assertEqual($item_updated
->hostEntity()->vid, $node->vid, 'Loaded default host entity revision.');
$item = entity_revision_load('field_collection_item', $item_revision_id);
$this
->assertFalse($item
->isDefaultRevision(), 'Field collection of non-default host entity is non-default too.');
$this
->assertEqual($item
->hostEntityId(), $node->nid, 'Can access host entity ID of non-default field collection revision.');
$this
->assertEqual($item
->hostEntity()->vid, $vid, 'Loaded non-default host entity revision.');
// Delete the non-default revision and make sure the field collection item
// revision has been deleted too.
entity_revision_delete('node', $vid);
$this
->assertFalse(entity_revision_load('node', $vid), 'Host entity revision deleted.');
$this
->assertFalse(entity_revision_load('field_collection_item', $item_revision_id), 'Field collection item revision deleted.');
// Test having archived field collections, i.e. collections referenced only
// in non-default revisions.
list($node, $item) = $this
->createNodeWithFieldCollection();
// Create two revisions.
$node_vid = $node->vid;
$node->revision = TRUE;
node_save($node);
$node_vid2 = $node->vid;
$node->revision = TRUE;
node_save($node);
// Now delete the field collection item for the default revision.
$item = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
$item_revision_id = $item->revision_id;
$item
->deleteRevision();
$node = node_load($node->nid);
$this
->assertTrue(!isset($node->{$this->field_name}[LANGUAGE_NONE][0]), 'Field collection item revision removed from host.');
$this
->assertFalse(field_collection_item_revision_load($item->revision_id), 'Field collection item default revision deleted.');
$item = field_collection_item_load($item->item_id);
$this
->assertNotEqual($item->revision_id, $item_revision_id, 'Field collection default revision has been updated.');
$this
->assertTrue($item->archived, 'Field collection item has been archived.');
$this
->assertFalse($item
->isInUse(), 'Field collection item specified as not in use.');
$this
->assertTrue($item
->isDefaultRevision(), 'Field collection of non-default host entity is default (but archived).');
$this
->assertEqual($item
->hostEntityId(), $node->nid, 'Can access host entity ID of non-default field collection revision.');
$this
->assertEqual($item
->hostEntity()->nid, $node->nid, 'Loaded non-default host entity revision.');
// Test deleting a revision of an archived field collection.
$node_revision2 = node_load($node->nid, $node_vid2);
$item = field_collection_item_revision_load($node_revision2->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']);
$item
->deleteRevision();
// There should be one revision left, so the item should still exist.
$item = field_collection_item_load($item->item_id);
$this
->assertTrue($item->archived, 'Field collection item is still archived.');
$this
->assertFalse($item
->isInUse(), 'Field collection item specified as not in use.');
// Test that deleting the first node revision deletes the whole field
// collection item as it contains its last revision.
node_revision_delete($node_vid);
$this
->assertFalse(field_collection_item_load($item->item_id), 'Archived field collection deleted when last revision deleted.');
// Test that removing a field-collection item also deletes it.
list($node, $item) = $this
->createNodeWithFieldCollection();
$node->{$this->field_name}[LANGUAGE_NONE] = array();
$node->revision = FALSE;
node_save($node);
$this
->assertFalse(field_collection_item_load($item->item_id), 'Removed field collection item has been deleted.');
// Test removing a field-collection item while creating a new host revision.
list($node, $item) = $this
->createNodeWithFieldCollection();
$node->{$this->field_name}[LANGUAGE_NONE] = array();
$node->revision = TRUE;
node_save($node);
// Item should not be deleted but archived now.
$item = field_collection_item_load($item->item_id);
$this
->assertTrue($item, 'Removed field collection item still exists.');
$this
->assertTrue($item->archived, 'Removed field collection item is archived.');
// Test removing an old node revision. Make sure that the field collection
// is not removed.
list($node, $item) = $this
->createNodeWithFieldCollection();
$node_vid = $node->vid;
$node->revision = TRUE;
node_save($node);
$node_vid2 = $node->vid;
$item_vid2 = $node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id'];
node_revision_delete($node_vid);
$item2 = field_collection_item_revision_load($item_vid2);
$item_id2 = isset($item2->item_id) ? $item2->item_id : -1;
$this
->assertEqual($item_id2, $item->item_id, 'Removing an old node revision does not delete newer field collection revisions');
}
/**
* Make sure the basic UI and access checks are working.
*/
public function testBasicUI() {
// Add a field to the collection.
$field = array(
'field_name' => 'field_text',
'type' => 'text',
'cardinality' => 1,
'translatable' => FALSE,
);
field_create_field($field);
$instance = array(
'entity_type' => 'field_collection_item',
'field_name' => 'field_text',
'bundle' => $this->field_name,
'label' => 'Test text field',
'widget' => array(
'type' => 'text_textfield',
),
);
field_create_instance($instance);
$user = $this
->drupalCreateUser();
$node = $this
->drupalCreateNode(array(
'type' => 'article',
));
$this
->drupalLogin($user);
// Make sure access is denied.
$path = 'field-collection/field-test-collection/add/node/' . $node->nid;
$this
->drupalGet($path);
$this
->assertText(t('Access denied'), 'Access has been denied.');
$user_privileged = $this
->drupalCreateUser(array(
'access content',
'edit any article content',
));
$this
->drupalLogin($user_privileged);
$this
->drupalGet("node/{$node->nid}");
$this
->assertLinkByHref($path, 0, 'Add link is shown.');
$this
->drupalGet($path);
$this
->assertText(t('Test text field'), 'Add form is shown.');
$edit['field_text[und][0][value]'] = self::randomName();
$this
->drupalPost($path, $edit, t('Save'));
$this
->assertText(t('The changes have been saved.'), 'Field collection saved.');
$this
->assertText($edit['field_text[und][0][value]'], 'Added field value is shown.');
$edit['field_text[und][0][value]'] = self::randomName();
$this
->drupalPost('field-collection/field-test-collection/1/edit', $edit, t('Save'));
$this
->assertText(t('The changes have been saved.'), 'Field collection saved.');
$this
->assertText($edit['field_text[und][0][value]'], 'Field collection has been edited.');
$this
->drupalGet('field-collection/field-test-collection/1');
$this
->assertText($edit['field_text[und][0][value]'], 'Field collection can be viewed.');
// Add further 3 items, so we have reached 4 == maxium cardinality.
$this
->drupalPost($path, $edit, t('Save'));
$this
->drupalPost($path, $edit, t('Save'));
$this
->drupalPost($path, $edit, t('Save'));
// Make sure adding doesn't work any more as we have restricted cardinality
// to 1.
$this
->drupalGet($path);
$this
->assertResponse(403);
$this
->drupalPost('field-collection/field-test-collection/1/delete', array(), t('Delete'));
$this
->drupalGet($path);
// Add form is shown again.
$this
->assertText(t('Test text field'), 'Field collection item has been deleted.');
// Test the viewing a revision. There should be no links to change it.
$vid = $node->vid;
$node = node_load($node->nid, NULL, TRUE);
$node->revision = TRUE;
node_save($node);
$this
->drupalGet("node/{$node->nid}/revisions/{$vid}/view");
$this
->assertResponse(403, 'Access to view revision denied');
// Login in as admin and try again.
$user = $this
->drupalCreateUser(array(
'administer nodes',
'bypass node access',
));
$this
->drupalLogin($user);
$this
->drupalGet("node/{$node->nid}/revisions/{$vid}/view");
$this
->assertNoResponse(403, 'Access to view revision granted');
$this
->assertNoLinkByHref($path, 'No links on revision view.');
$this
->assertNoLinkByHref('field-collection/field-test-collection/2/edit', 'No links on revision view.');
$this
->assertNoLinkByHref('field-collection/field-test-collection/2/delete', 'No links on revision view.');
$this
->drupalGet("node/{$node->nid}/revisions");
}
/**
* Make sure that field_collection-entities are copied when host-entities do.
*/
public function testCopyingEntities() {
list($node, $entity) = $this
->createNodeWithFieldCollection();
// Create a copy of that node.
$node->nid = NULL;
$node->vid = NULL;
$node->is_new = TRUE;
node_save($node);
$item = $node->{$this->field_name}[LANGUAGE_NONE][0];
$this
->assertNotEqual($entity->item_id, $item['value']);
// Do a php clone to the $node object and save it.
$node2 = clone $node;
$node2->nid = NULL;
$node2->is_new = TRUE;
$node2->vid = NULL;
node_save($node2);
$item2 = $node2->{$this->field_name}[LANGUAGE_NONE][0];
$this
->assertNotEqual($item2['value'], $item['value']);
// Create another copy this time (needlessly) forcing a new revision.
$node->nid = NULL;
$node->vid = NULL;
$node->is_new = TRUE;
$node->revision = TRUE;
node_save($node);
$item3 = $node->{$this->field_name}[LANGUAGE_NONE][0];
$this
->assertNotEqual($item['value'], $item3['value']);
}
}
/**
* Test using field collection with Rules.
*/
class FieldCollectionRulesIntegrationTestCase extends DrupalWebTestCase {
/**
*
*/
public static function getInfo() {
return array(
'name' => 'Field collection Rules integration',
'description' => 'Tests using field collections with rules.',
'group' => 'Field types',
'dependencies' => array(
'rules',
),
);
}
/**
*
*/
public function setUp() {
parent::setUp(array(
'field_collection',
'rules',
));
variable_set('rules_debug_log', 1);
}
/**
*
*/
protected function createFields($cardinality = 4) {
// Create a field_collection field to use for the tests.
$this->field_name = 'field_test_collection';
$this->field = array(
'field_name' => $this->field_name,
'type' => 'field_collection',
'cardinality' => $cardinality,
);
$this->field = field_create_field($this->field);
$this->field_id = $this->field['id'];
$this->instance = array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'article',
'label' => self::randomName() . '_label',
'description' => self::randomName() . '_description',
'weight' => random_int(0, 127),
'settings' => array(),
'widget' => array(
'type' => 'hidden',
'label' => 'Test',
'settings' => array(),
),
);
$this->instance = field_create_instance($this->instance);
// Add a field to the collection.
$field = array(
'field_name' => 'field_text',
'type' => 'text',
'cardinality' => 1,
'translatable' => FALSE,
);
field_create_field($field);
$instance = array(
'entity_type' => 'field_collection_item',
'field_name' => 'field_text',
'bundle' => $this->field_name,
'label' => 'Test text field',
'widget' => array(
'type' => 'text_textfield',
),
);
field_create_instance($instance);
}
/**
* Test creation field collection items.
*/
public function testCreation() {
$this
->createFields();
$node = $this
->drupalCreateNode(array(
'type' => 'article',
));
// Create a field collection.
$action_set = rules_action_set(array(
'node' => array(
'type' => 'node',
'bundle' => 'article',
),
));
$action_set
->action('entity_create', array(
'type' => 'field_collection_item',
'param_field_name' => $this->field_name,
'param_host_entity:select' => 'node',
));
$action_set
->action('data_set', array(
'data:select' => 'entity-created:field-text',
'value' => 'foo',
));
$action_set
->execute($node);
$node = node_load($node->nid, NULL, TRUE);
$this
->assertTrue(!empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']), 'A field_collection has been successfully created.');
$this
->assertTrue(!empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'A field_collection has been successfully created (revision).');
// Now try making use of the field collection in rules.
$action_set = rules_action_set(array(
'node' => array(
'type' => 'node',
'bundle' => 'article',
),
));
$action_set
->action('drupal_message', array(
'message:select' => 'node:field-test-collection:0:field-text',
));
$action_set
->execute($node);
$msg = drupal_get_messages();
$this
->assertEqual(array_pop($msg['status']), 'foo', 'Field collection can be used.');
RulesLog::logger()
->checkLog();
}
/**
* Test using field collection items via the host while they are being created.
*/
public function testUsageDuringCreation() {
// Test using a single-cardinality field collection.
$this
->createFields(1);
$node = $this
->drupalCreateNode(array(
'type' => 'article',
));
$entity = entity_create('field_collection_item', array(
'field_name' => $this->field_name,
));
$entity
->setHostEntity('node', $node);
// Now the field collection is linked to the host, but not yet saved.
// Test using the wrapper on it.
$wrapper = entity_metadata_wrapper('node', $node);
$wrapper
->get($this->field_name)->field_text
->set('foo');
$this
->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'foo', 'Field collection item used during creation via the wrapper.');
// Now test it via Rules, which should save our changes.
$set = rules_action_set(array(
'node' => array(
'type' => 'node',
'bundle' => 'article',
),
));
$set
->action('data_set', array(
'data:select' => 'node:' . $this->field_name . ':field-text',
'value' => 'bar',
));
$set
->execute($node);
$this
->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'bar', 'Field collection item used during creation via Rules.');
$this
->assertTrue(!empty($entity->item_id) && !empty($entity->revision_id), 'Field collection item has been saved by Rules and the host entity.');
RulesLog::logger()
->checkLog();
}
}
/**
* Test using field collection with content that gets translated.
*/
class FieldCollectionContentTranslationTestCase extends DrupalWebTestCase {
/**
*
*/
public static function getInfo() {
return array(
'name' => 'Field collection content translation',
'description' => 'Tests using content under translation.',
'group' => 'Field types',
'dependencies' => array(
'translation',
),
);
}
/**
*
*/
public function setUp() {
parent::setUp(array(
'field_collection',
'translation',
));
// Create a field_collection field to use for the tests.
$this->field_name = 'field_test_collection';
$this->field = array(
'field_name' => $this->field_name,
'type' => 'field_collection',
'cardinality' => 4,
);
$this->field = field_create_field($this->field);
$this->field_id = $this->field['id'];
$this->instance = array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'article',
'label' => self::randomName() . '_label',
'description' => self::randomName() . '_description',
'weight' => random_int(0, 127),
'settings' => array(),
'widget' => array(
'type' => 'field_collection_embed',
'label' => 'Test',
'settings' => array(),
),
);
$this->instance = field_create_instance($this->instance);
// Add a field to the collection.
$field = array(
'field_name' => 'field_text',
'type' => 'text',
'cardinality' => 1,
'translatable' => FALSE,
);
field_create_field($field);
$instance = array(
'entity_type' => 'field_collection_item',
'field_name' => 'field_text',
'bundle' => $this->field_name,
'label' => 'Test text field',
'widget' => array(
'type' => 'text_textfield',
),
);
field_create_instance($instance);
$admin_user = $this
->drupalCreateUser(array(
'administer languages',
'administer content types',
'access administration pages',
'create article content',
'edit any article content',
'translate content',
));
$this
->drupalLogin($admin_user);
// Add German language.
locale_add_language('de');
// Set "Article" content type to use multilingual support.
variable_set('language_content_type_article', TRANSLATION_ENABLED);
}
/**
* Ensure field collections are cloned to new entities on content translation.
*/
public function testContentTranslation() {
// Create "Article" content.
$edit['title'] = self::randomName();
$edit['body[' . LANGUAGE_NONE . '][0][value]'] = self::randomName();
$edit['language'] = 'en';
$field_collection_name = 'field_test_collection[' . LANGUAGE_NONE . '][0][field_text][' . LANGUAGE_NONE . '][0][value]';
$edit[$field_collection_name] = self::randomName();
$this
->drupalPost('node/add/article', $edit, t('Save'));
$this
->assertRaw(t('Article %title has been created.', array(
'%title' => $edit['title'],
)), 'Article created.');
$node1 = $this
->drupalGetNodeByTitle($edit['title']);
$this
->drupalGet('node/' . $node1->nid . '/edit');
$this
->drupalGet('node/' . $node1->nid . '/translate');
$this
->drupalGet('node/add/article', array(
'query' => array(
'translation' => $node1->nid,
'target' => 'de',
),
));
// Suffix translations with the langcode.
unset($edit['language']);
$edit['title'] .= 'DE';
$edit[$field_collection_name] .= 'DE';
$this
->drupalPost('node/add/article', $edit, t('Save'), array(
'query' => array(
'translation' => $node1->nid,
'target' => 'de',
),
));
$node2 = $this
->drupalGetNodeByTitle($edit['title']);
// Ensure that our new node is the translation of the first one.
$this
->assertEqual($node1->nid, $node2->tnid, 'Succesfully created translation.');
// And check to see that their field collections are different.
$this
->assertNotEqual($node1->field_test_collection, $node2->field_test_collection, 'Field collections between translation source and translation differ.');
}
}
/**
* Test using field collection with content that gets translated with Entity Translation.
*/
class FieldCollectionEntityTranslationTestCase extends DrupalWebTestCase {
const TRANS_FIELD_EN = 'Translatable EN';
const TRANS_FIELD_DE = 'Translatable DE';
const TRANS_FIELD_DE_MOD = 'Translatable DE Mod';
const UNTRANS_FIELD_EN = 'Untranslatable EN';
const UNTRANS_FIELD_DE = 'Untranslatable DE';
const UNTRANS_FIELD_DE_MOD = 'Untranslatable DE Mod';
const NUM_VALUES = 4;
/**
*
*/
public static function getInfo() {
return array(
'name' => 'Field collection entity translation',
'description' => 'Tests using content under translation with Entity Translation.',
'group' => 'Field types',
'dependencies' => array(
'entity_translation',
),
);
}
/**
* Login the given user only if she has not changed.
*/
public function login($user) {
if (!isset($this->current_user) || $this->current_user->uid != $user->uid) {
$this->current_user = $user;
$this
->drupalLogin($user);
}
}
/**
* Returns a user with administration rights.
*
* @param $permissions
* Additional permissions for administrative user.
*/
public function getAdminUser(array $permissions = array()) {
if (!isset($this->admin_user)) {
$this->admin_user = $this
->drupalCreateUser(array_merge(array(
'bypass node access',
'administer nodes',
'administer languages',
'administer content types',
'administer blocks',
'access administration pages',
'administer site configuration',
'administer entity translation',
), $permissions));
}
return $this->admin_user;
}
/**
* Returns a user with minimal translation rights.
*
* @param $permissions
* Additional permissions for administrative user.
*/
public function getTranslatorUser(array $permissions = array()) {
if (!isset($this->translator_user)) {
$this->translator_user = $this
->drupalCreateUser(array_merge(array(
'create page content',
'edit own page content',
'delete own page content',
'translate any entity',
), $permissions));
}
return $this->translator_user;
}
/**
* Install a specified language if it has not been already, otherwise make
* sure that the language is enabled.
*
* @param string $langcode
* The language code to check.
*/
public function addLanguage($langcode) {
// Check to make sure that language has not already been installed.
$this
->drupalGet('admin/config/regional/language');
if (strpos($this
->drupalGetContent(), 'enabled[' . $langcode . ']') === FALSE) {
// Doesn't have language installed so add it.
$edit = array();
$edit['langcode'] = $langcode;
$this
->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
// Make sure we are not using a stale list.
drupal_static_reset('language_list');
$languages = language_list();
$this
->assertTrue(array_key_exists($langcode, $languages), t('Language was installed successfully.'));
if (array_key_exists($langcode, $languages)) {
$this
->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array(
'%language' => $languages[$langcode]->name,
'@locale-help' => url('admin/help/locale'),
)), t('Language has been created.'));
}
}
elseif ($this
->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(
':name' => 'enabled[' . $langcode . ']',
))) {
// It is installed and enabled. No need to do anything.
$this
->assertTrue(TRUE, 'Language [' . $langcode . '] already installed and enabled.');
}
else {
// It is installed but not enabled. Enable it.
$this
->assertTrue(TRUE, 'Language [' . $langcode . '] already installed.');
$this
->drupalPost(NULL, array(
'enabled[' . $langcode . ']' => TRUE,
), t('Save configuration'));
$this
->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
}
}
/**
*
*/
public function setUp() {
parent::setUp(array(
'field_collection',
'entity_translation',
));
$language_none = LANGUAGE_NONE;
// Login with an admin user.
$this
->login($this
->getAdminUser());
// Add English and German languages.
$this
->addLanguage('en');
$this
->addLanguage('de');
// Set "Article" content type to use multilingual support with translation.
$edit = array();
$edit['language_content_type'] = ENTITY_TRANSLATION_ENABLED;
$this
->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this
->assertRaw(t('The content type %type has been updated.', array(
'%type' => 'Basic page',
)), t('Basic page content type has been updated.'));
// Create a field collection field to use for the tests.
$this->field_name = 'field_test_collection';
$this->field_base = "{$this->field_name}[{$language_none}]";
$this->field = array(
'field_name' => $this->field_name,
'type' => 'field_collection',
'cardinality' => -1,
'translatable' => TRUE,
);
$this->field = field_create_field($this->field);
$this->field_id = $this->field['id'];
$this->instance = array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'page',
'label' => self::randomName() . '_label',
'description' => self::randomName() . '_description',
'weight' => random_int(0, 127),
'settings' => array(),
'widget' => array(
'type' => 'field_collection_embed',
'label' => 'Test',
'settings' => array(),
),
);
$this->instance = field_create_instance($this->instance);
// Enable entity translation of field collections.
$this
->drupalGet('admin/config/regional/entity_translation');
$this
->drupalPost('admin/config/regional/entity_translation', array(
'entity_translation_entity_types[field_collection_item]' => TRUE,
), t('Save configuration'));
$this
->assertRaw(t('The configuration options have been saved.'), t('Entity translation of field collections enabled.'));
// Add an untraslatable field to the collection.
$this->field_untrans_name = 'field_text_untrans';
$this->field_untrans_base = "[{$this->field_untrans_name}][{$language_none}][0][value]";
$field = array(
'field_name' => $this->field_untrans_name,
'type' => 'text',
'cardinality' => 1,
'translatable' => FALSE,
);
field_create_field($field);
$instance = array(
'entity_type' => 'field_collection_item',
'field_name' => $this->field_untrans_name,
'bundle' => $this->field_name,
'label' => 'Test untranslatable text field',
'widget' => array(
'type' => 'text_textfield',
),
);
field_create_instance($instance);
// Add a translatable field to the collection.
$this->field_trans_name = 'field_text_trans';
$this->field_trans_base = "[{$this->field_trans_name}][{$language_none}][0][value]";
$this->field_trans_dest = "[{$this->field_trans_name}][de][0][value]";
$field = array(
'field_name' => $this->field_trans_name,
'type' => 'text',
'cardinality' => 1,
'translatable' => TRUE,
);
field_create_field($field);
$instance = array(
'entity_type' => 'field_collection_item',
'field_name' => $this->field_trans_name,
'bundle' => $this->field_name,
'label' => 'Test translatable text field',
'widget' => array(
'type' => 'text_textfield',
),
);
field_create_instance($instance);
$this
->login($this
->getTranslatorUser());
}
/**
* Creates a basic page with a value in the field collection.
*
* @param int $num_values
* The number of values to include in the field collection.
* @param string $langcode
* Language for the node.
*/
protected function createPage($num_values, $langcode = 'en') {
// Check if num_values is greater than the field cardinality.
if ($num_values > self::NUM_VALUES) {
$num_values = self::NUM_VALUES;
}
$title = self::randomName();
$this
->drupalGet('node/add/page');
$edit = array();
$edit['title'] = $title;
for ($i = 0; $i < $num_values; $i++) {
if ($i != 0) {
$this
->drupalPost(NULL, array(), t('Add another item'));
}
$edit[$this->field_base . '[' . $i . ']' . $this->field_untrans_base] = self::UNTRANS_FIELD_EN . '_' . $i;
$edit[$this->field_base . '[' . $i . ']' . $this->field_trans_base] = self::TRANS_FIELD_EN . '_' . $i;
}
$edit['language'] = $langcode;
$this
->drupalPost(NULL, $edit, t('Save'));
$this
->assertRaw(t('Basic page %title has been created.', array(
'%title' => $title,
)), t('Basic page created.'));
// Check to make sure the node was created.
$node = $this
->drupalGetNodeByTitle($title);
$this
->assertTrue($node, t('Node found in database.'));
return $node;
}
/**
* Create a translation using the Entity Translation Form.
*
* @param mixed $node
* Node of the basic page to create translation for.
* @param string $langcode
* The language code of the translation.
* @param string $source_langcode
* The original language code.
*/
protected function createTranslationForm($node, $langcode, $source_langcode = 'en') {
$language_none = LANGUAGE_NONE;
$edit = array();
$this
->drupalGet('node/' . $node->nid . '/edit/add/' . $source_langcode . '/' . $langcode);
// Get the field collection in the original language.
$fc_values = $node->{$this->field_name}[$source_langcode];
// Check if all the fields were populated and fill it with the new value.
foreach ($fc_values as $delta => $fc_value) {
// Load the field collection item.
$fc_item_array = entity_load('field_collection_item', array(
$fc_value['value'],
));
$fc_item = reset($fc_item_array);
$fc_untrans_key = "{$this->field_name}[{$langcode}][{$delta}]{$this->field_untrans_base}";
$fc_trans_key = "{$this->field_name}[{$langcode}][{$delta}]{$this->field_trans_dest}";
$this
->assertFieldByXPath("//input[@name='{$fc_untrans_key}']", $fc_item->{$this->field_untrans_name}[LANGUAGE_NONE][0]['value'], 'Original value of untranslatable field correctly populated');
$this
->assertFieldByXPath("//input[@name='{$fc_trans_key}']", $fc_item->{$this->field_trans_name}['en'][0]['value'], 'Original value of translatable field correctly populated');
$edit[$fc_untrans_key] = self::UNTRANS_FIELD_DE . '_' . $delta;
$edit[$fc_trans_key] = self::TRANS_FIELD_DE . '_' . $delta;
}
// Save the translation.
$this
->drupalPost(NULL, $edit, t('Save'));
$this
->drupalGet('node/' . $node->nid . '/translate');
$this
->assertLinkByHref('node/' . $node->nid . '/edit/' . $langcode, 0, t('Translation edit link found. Translation created.'));
// Reload the node.
$node = node_load($node->nid, NULL, TRUE);
// Check the values of the translated field.
$this
->checkFieldCollectionContent($node, $langcode);
// Check the values of the field in the original language.
$this
->checkFieldCollectionContent($node, $source_langcode);
return $node;
}
/**
* Removes a translation using the entity translation form.
*
* @param mixed $node
* The node to remove the translation from.
* @param string $langcode
* The language of the translation to remove.
* @param string $source_langcode
* The source language of the node.
*/
protected function removeTranslationForm($node, $langcode, $source_langcode) {
// Number of field collection items in the source language.
$num_original_fc_items = count($node->{$this->field_name}[$source_langcode]);
// Fetch the translation edit form.
$this
->drupalGet('node/' . $node->nid . '/edit/' . $langcode);
// Remove the translation.
$this
->drupalPost(NULL, array(), t('Delete translation'));
// Confirm deletion.
$this
->drupalPost(NULL, array(), t('Delete'));
// Reload the node.
$node = node_load($node->nid, NULL, TRUE);
// Check that the translation is removed.
$this
->drupalGet('node/' . $node->nid . '/translate');
$this
->assertLinkByHref('node/' . $node->nid . '/edit/add/' . $source_langcode . '/' . $langcode, 0, 'The add translation link appears');
$this
->assert(empty($node->{$this->field_name}[$langcode]));
// Check that the field collection in the original language has not changed.
$num_fc_items = count($node->{$this->field_name}[$source_langcode]);
$this
->assertEqual($num_original_fc_items, $num_fc_items, 'The number of field collection items in the original language has not changed.');
$this
->checkFieldCollectionContent($node, $source_langcode);
}
/**
* Creates a translation programmatically using Entity Translation.
*
* @param mixed $node
* Node of the basic page to create translation for.
* @param string $langcode
* The language code of the translation.
*/
protected function createTranslation($node, $langcode) {
$source_langcode = $node->language;
// Get the Entity Translation Handler.
$handler = entity_translation_get_handler('node', $node, TRUE);
// Variable to hold the fields values.
$values = array();
// Translation settings.
$translation = array(
'translate' => 0,
'status' => 1,
'language' => $langcode,
'source' => $source_langcode,
'uid' => $node->uid,
);
// Copy field values.
foreach (field_info_instances('node', $node->type) as $instance) {
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
$field_value = array();
// Copy the value of the translated field if it's translatable.
if ($field['translatable'] && isset($node->{$field_name}[$node->language])) {
$field_value = $node->{$field_name}[$source_langcode];
$values[$field_name][$langcode] = $field_value;
$node->{$field_name}[$langcode] = $field_value;
}
}
$handler
->setTranslation($translation, $values);
$handler
->saveTranslations();
field_attach_update('node', $node);
// Reload an return the node.
$node = node_load($node->nid, NULL, TRUE);
return $node;
}
/**
* Removes a translation programmatically using the entity translation api.
*
* @param mixed $node
* The node to remove the translation from.
* @param string $langcode
* The language of the translation to remove.
*/
protected function removeTranslation($node, $langcode) {
// Get a translation entity handler.
$handler = entity_translation_get_handler('node', $node, TRUE);
// Remove the translation.
$handler
->removeTranslation($langcode);
node_save($node);
// Reload and return the node.
$node = node_load($node->nid, NULL, TRUE);
return $node;
}
/**
* Creates a new revision of the node and checks the result.
*
* @param mixed $node
* The node to remove the translation from.
* @param string $langcode
* The language of the translation to remove.
* @param string $source_langcode
* The source language of the node.
*
* @return mixed
* The new revision of the node.
*/
protected function createRevision($node, $langcode, $source_langcode) {
$node_original_revision = $node->vid;
// The original entries of the translated field.
$original_fc_item_ids = $node->{$this->field_name}[$langcode];
// Create the revision.
$node->revision = TRUE;
node_save($node);
// The new entries of the translated field.
$new_fc_item_ids = $node->{$this->field_name}[$langcode];
// Check that the field collection items are the same and a new revision of
// each one has been created.
foreach ($original_fc_item_ids as $delta => $value) {
$this
->assertEqual($value['value'], $new_fc_item_ids[$delta]['value'], t('We have the same field collection item'));
$this
->assertNotEqual($value['revision_id'], $new_fc_item_ids[$delta]['revision_id'], t('We have a new revision of the field collection item'));
}
return $node;
}
/**
* Check the content of the field collection for a specified language.
*
* @param mixed $node
* The node to check.
* @param string $langcode
* The language to check.
*/
protected function checkFieldCollectionContent($node, $langcode) {
switch ($langcode) {
case 'en':
$untrans_field = self::UNTRANS_FIELD_EN;
$trans_field = self::TRANS_FIELD_EN;
break;
case 'de':
$untrans_field = self::UNTRANS_FIELD_DE;
$trans_field = self::TRANS_FIELD_DE;
break;
}
// Get the field collection in the specified language.
$fc_values = $node->{$this->field_name}[$langcode];
foreach ($fc_values as $delta => $fc_value) {
// Load the field collection item.
$fc_item_array = entity_load('field_collection_item', array(
$fc_value['value'],
));
$fc_item = reset($fc_item_array);
$fc_untrans_key = "{$this->field_name}[{$langcode}][{$delta}]{$this->field_untrans_base}";
$fc_trans_key = "{$this->field_name}[{$langcode}][{$delta}]{$this->field_trans_base}";
$this
->assertEqual($untrans_field . '_' . $delta, $fc_item->{$this->field_untrans_name}[LANGUAGE_NONE][0]['value']);
$this
->assertEqual($trans_field . '_' . $delta, $fc_item->{$this->field_trans_name}[$langcode][0]['value']);
}
}
/**
* Returns the text field values of an specified node, language and delta.
*
* @param mixed $node
* @param string $langcode
* @param int $delta
*
* @return array
*/
protected function getFieldValues($node, $langcode, $delta) {
$return = array();
if (isset($node->{$this->field_name}[$langcode][$delta]['value'])) {
$fc_item_id = $node->{$this->field_name}[$langcode][$delta]['value'];
// Load the field collection.
$fc_item_array = entity_load('field_collection_item', array(
$fc_item_id,
));
$fc_item = reset($fc_item_array);
$return = array(
'field_untrans' => $fc_item->{$this->field_untrans_name}[LANGUAGE_NONE][0]['value'],
'field_trans' => $fc_item->{$this->field_trans_name}[$langcode][0]['value'],
);
}
return $return;
}
/**
* Ensures the right behaviour in all Entity Translation use cases.
*/
public function testEntityTranslation() {
$source_langcode = 'en';
$translation_langcode = 'de';
/*
* Test with a page with only one value in the field collection
*/
// Create an article in the original language with only one field collection
// value.
$node = $this
->createPage(1, $source_langcode);
// Create a traslation of the page through the entity translation form.
$node = $this
->createTranslationForm($node, $translation_langcode, $source_langcode);
/*
* Test with a page with multiple values in the field collection.
*/
$num_values = 4;
// Create a page in the original language with multiple field collection
// values.
$node = $this
->createPage($num_values, $source_langcode);
// Create a traslation of the page through the entity translation form.
$node = $this
->createTranslationForm($node, $translation_langcode, $source_langcode);
// Assign a new field collection item to an existing node.
$values = array();
$values['field_name'] = $this->field_name;
$fc_entity = entity_create('field_collection_item', $values);
$fc_entity
->setHostEntity('node', $node, $translation_langcode);
$fc_entity->{$this->field_untrans_name}[LANGUAGE_NONE][0]['value'] = self::UNTRANS_FIELD_DE_MOD;
$fc_entity->{$this->field_trans_name}['de'][0]['value'] = self::TRANS_FIELD_DE_MOD;
$fc_entity
->save(TRUE);
node_save($node);
// Reload the node to check it.
$node = node_load($node->nid, NULL, TRUE);
// Check that there is a new element in the translation.
$this
->assertEqual($num_values + 1, count($node->{$this->field_name}[$translation_langcode]), t('We have one item more in translation.'));
// Check that the new element is correctly saved.
$fc_item_values = $this
->getFieldValues($node, $translation_langcode, $num_values);
$this
->assertEqual($fc_item_values['field_untrans'], self::UNTRANS_FIELD_DE_MOD);
$this
->assertEqual($fc_item_values['field_trans'], self::TRANS_FIELD_DE_MOD);
// Check that we have the same items in the original language.
$this
->assertEqual($num_values, count($node->{$this->field_name}[$source_langcode]), t('We have same items in the original language.'));
// Remove a field collection item from the translation.
$fc_item_id = $node->{$this->field_name}[$translation_langcode][0]['value'];
unset($node->{$this->field_name}[$translation_langcode][0]);
node_save($node);
// Reload the node.
$node = node_load($node->nid, NULL, TRUE);
// Check that we have one item less in the translation.
// We should take into account that we added a field one step before.
$this
->assertEqual($num_values, count($node->{$this->field_name}[$translation_langcode]), t('We have one item less in translation.'));
// Check that we have the same items in the original language.
$this
->assertEqual($num_values, count($node->{$this->field_name}[$source_langcode]), t('We have same items in the original language.'));
// Check that the field collection is removed from the database.
$fc_items = entity_load('field_collection_item', array(
$fc_item_id,
));
$this
->assert(empty($fc_items), t('The field collection item has been removed from the database.'));
// Delete the translation.
$this
->removeTranslationForm($node, $translation_langcode, $source_langcode);
/*
* Check the revisioning of an entity with translations.
*/
$num_values = 4;
// Create a page in the original language with multiple field collection
// values.
$node_rev = $this
->createPage($num_values, $source_langcode);
// Create a traslation of the page.
$node_rev = $this
->createTranslationForm($node_rev, $translation_langcode, $source_langcode);
$original_revision = $node_rev->vid;
// Create a new revision of the node.
$node_rev = $this
->createRevision($node_rev, $translation_langcode, $source_langcode);
/*
* Test creating programmatically.
*/
$num_values = 4;
// Create a page in the original language.
$node_prog = $this
->createPage($num_values, $source_langcode);
// Create programmatically a translation of the page.
$node_prog = $this
->createTranslation($node_prog, $translation_langcode);
$orig_fc_items = $node_prog->{$this->field_name}[$source_langcode];
$trans_fc_items = $node_prog->{$this->field_name}[$translation_langcode];
$orig_fc_item_ids = array();
$trans_fc_item_ids = array();
// Check each item.
foreach ($orig_fc_items as $delta => $value) {
$orig_fc_item_ids[] = $value['value'];
$trans_fc_item_ids[] = $trans_fc_items[$delta]['value'];
// Check if we have new items for the translation.
$this
->assertNotEqual($value['value'], $trans_fc_items[$delta]['value'], t('New item generated for translation.'));
}
// Check that the original item still exists in the database.
$fc_items = entity_load('field_collection_item', $orig_fc_item_ids);
$this
->assert(!empty($fc_items), t('Field Collections in the source language still exist.'));
// Check that the translated item exists in the database.
$fc_items = entity_load('field_collection_item', $trans_fc_item_ids);
$this
->assert(!empty($fc_items), t('Translations for the Field Collection exist.'));
// Remove the translation and check that the original field collection items
// are still there.
$node_prog = $this
->removeTranslation($node, $translation_langcode);
// Check the content in the source language.
$this
->checkFieldCollectionContent($node_prog, $source_langcode);
// Check that the field translated content has been removed.
$this
->assert(empty($node->{$this->field_name}[$translation_langcode]), t('Translated content removed.'));
}
}
Classes
Name | Description |
---|---|
FieldCollectionBasicTestCase | Test basics. |
FieldCollectionContentTranslationTestCase | Test using field collection with content that gets translated. |
FieldCollectionEntityTranslationTestCase | Test using field collection with content that gets translated with Entity Translation. |
FieldCollectionRulesIntegrationTestCase | Test using field collection with Rules. |