diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php index 10a7a77..eb03a68 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php @@ -9,6 +9,7 @@ use PDO; +use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityStorageException; @@ -37,6 +38,13 @@ class DatabaseStorageControllerNG extends DatabaseStorageController { protected $bundleKey; /** + * The table that stores properties, if the entity has multilingual support. + * + * @var string + */ + protected $dataTable; + + /** * Overrides DatabaseStorageController::__construct(). */ public function __construct($entityType) { @@ -44,6 +52,11 @@ public function __construct($entityType) { $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE; $this->entityClass = $this->entityInfo['class']; + // Check if the entity type has a dedicated table for properties. + if (!empty($this->entityInfo['data_table'])) { + $this->dataTable = $this->entityInfo['data_table']; + } + // Work-a-round to let load() get stdClass storage records without having to // override it. We map storage records to entities in // DatabaseStorageControllerNG:: mapFromStorageRecords(). @@ -98,6 +111,121 @@ public function create(array $values) { } /** + * Builds an entity query. + * + * @param \Drupal\Core\Entity\Query\QueryInterface $entity_query + * EntityQuery instance. + * @param array $values + * An associative array of properties of the entity, where the keys are the + * property names and the values are the values those properties must have. + */ + protected function buildPropertyQuery(QueryInterface $entity_query, array $values) { + if ($this->dataTable) { + // @todo We should not be using a condition to specify whether conditions + // apply to the default language or not. We need to move this to a + // separate parameter during the following API refactoring. + // Default to the original entity language if not explicitly specified + // otherwise. + if (!array_key_exists('default_langcode', $values)) { + $values['default_langcode'] = 1; + } + // If the 'default_langcode' flag is explicitly not set, we do not care + // whether the queried values are in the original entity language or not. + elseif ($values['default_langcode'] === NULL) { + unset($values['default_langcode']); + } + } + + parent::buildPropertyQuery($entity_query, $values); + } + + /** + * Builds the query to load the entity. + * + * This has full revision support. For entities requiring special queries, + * the class can be extended, and the default query can be constructed by + * calling parent::buildQuery(). This is usually necessary when the object + * being loaded needs to be augmented with additional data from another + * table, such as loading node type into comments or vocabulary machine name + * into terms, however it can also support $conditions on different tables. + * See Drupal\comment\CommentStorageController::buildQuery() or + * Drupal\taxonomy\TermStorageController::buildQuery() for examples. + * + * @param array|null $ids + * An array of entity IDs, or NULL to load all entities. + * @param integer|FALSE $revision_id + * The ID of the revision to load, or FALSE if this query is asking for the + * most current revision(s). + * + * @return \Drupal\Core\Database\Query\Select + * A Select query object for loading the entity. + */ + protected function buildQuery($ids, $revision_id = FALSE) { + $query = db_select($this->entityInfo['base_table'], 'base'); + + $query->addTag($this->entityType . '_load_multiple'); + + if ($revision_id) { + $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id)); + } + elseif ($this->revisionKey) { + $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); + } + + if (!empty($this->dataTable)) { + $query->join($this->dataTable, 'data', "data.{$this->idKey} = base.{$this->idKey}"); + } + + // Add fields from the {entity} table. + $entity_fields = $this->entityInfo['schema_fields_sql']['base_table']; + + if ($this->revisionKey) { + // Add all fields from the {entity_revision} table. + $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision_table']); + // The id field is provided by entity, so remove it. + unset($entity_revision_fields[$this->idKey]); + + // Remove all fields from the base table that are also fields by the same + // name in the revision table. + $entity_field_keys = array_flip($entity_fields); + foreach ($entity_revision_fields as $key => $name) { + if (isset($entity_field_keys[$name])) { + unset($entity_fields[$entity_field_keys[$name]]); + } + } + $query->fields('revision', $entity_revision_fields); + + // Compare revision id of the base and revision table, if equal then this + // is the default revision. + $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision'); + } + + // Add fields from the entity data_table. + if (!empty($this->dataTable)) { + // Add all fields from the {entity_data} table. + $entity_data_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['data_table']); + // The id field is provided by entity, so remove it. + unset($entity_data_fields[$this->idKey]); + + if (!isset($entity_revision_fields)) { + $entity_revision_fields = array(); + } + + // Only add fields not covered by the base or the revision. + $entity_data_fields = array_diff($entity_data_fields, $entity_fields, $entity_revision_fields); + $query->fields('data', $entity_data_fields); + } + + $query->fields('base', $entity_fields); + + if ($ids) { + $query->condition("base.{$this->idKey}", $ids, 'IN'); + } + + return $query; + } + + /** * Overrides DatabaseStorageController::attachLoad(). * * Added mapping from storage records to entities. @@ -158,10 +286,51 @@ protected function mapFromStorageRecords(array $records, $load_revision = FALSE) } $records[$id] = $entity; } + + // Load data of translatable properties. + $this->attachPropertyData($records, $load_revision); + return $records; } /** + * Attaches property data in all languages for translatable properties. + * + * @param array $queried_entities + * Associative array of entities, keyed on the entity ID. + * @param boolean $load_revision + * (optional) TRUE if the revision should be loaded, defaults to FALSE. + */ + protected function attachPropertyData(&$queried_entities, $load_revision = FALSE) { + if ($this->dataTable) { + $query = db_select($this->dataTable, 'data', array('fetch' => PDO::FETCH_ASSOC)) + ->fields('data') + ->condition($this->idKey, array_keys($queried_entities)) + ->orderBy('data.' . $this->idKey); + if ($load_revision) { + // Get revision id's. + $revision_ids = array(); + foreach ($queried_entities as $id => $entity) { + $revision_ids[] = $entity->get($this->revisionKey)->value; + } + $query->condition($this->revisionKey, $revision_ids); + } + $data = $query->execute(); + + foreach ($data as $values) { + $id = $values[$this->idKey]; + // Field values in default language are stored with + // LANGUAGE_DEFAULT as key. + $langcode = empty($values['default_langcode']) ? $values['langcode'] : LANGUAGE_DEFAULT; + + foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) { + $queried_entities[$id]->{$name}[$langcode][0]['value'] = $values[$name]; + } + } + } + } + + /** * Overrides DatabaseStorageController::save(). * * Added mapping from entities to storage records before saving. @@ -197,6 +366,9 @@ public function save(EntityInterface $entity) { if ($this->revisionKey) { $record->{$this->revisionKey} = $this->saveRevision($entity); } + if ($this->dataTable) { + $this->saveData($entity); + } $this->resetCache(array($entity->id())); $this->postSave($entity, TRUE); $this->invokeHook('update', $entity); @@ -207,14 +379,19 @@ public function save(EntityInterface $entity) { $entity->{$this->idKey}->value = $record->{$this->idKey}; $record->{$this->revisionKey} = $this->saveRevision($entity); } + $entity->{$this->idKey}->value = $record->{$this->idKey}; + if ($this->dataTable) { + $this->saveData($entity); + } + // Reset general caches, but keep caches specific to certain entities. $this->resetCache(array()); - $entity->{$this->idKey}->value = $record->{$this->idKey}; $entity->enforceIsNew(FALSE); $this->postSave($entity, FALSE); $this->invokeHook('insert', $entity); } + $entity->updateOriginalValues(); // Ignore slave server temporarily. db_ignore_slave(); @@ -268,6 +445,32 @@ protected function saveRevision(EntityInterface $entity) { } /** + * Saves the entity property data language aware. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + */ + protected function saveData(EntityInterface $entity) { + // Delete and insert to handle removed values. + db_delete($this->dataTable) + ->condition($this->idKey, $entity->id()) + ->execute(); + + $query = db_insert($this->dataTable); + + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + $record = $this->mapToDataStorageRecord($entity, $langcode); + + $values = (array) $record; + $query + ->fields(array_keys($values)) + ->values($values); + } + + $query->execute(); + } + + /** * Overrides DatabaseStorageController::invokeHook(). * * Invokes field API attachers in compatibility mode and disables it @@ -294,6 +497,12 @@ protected function invokeHook($hook, EntityInterface $entity) { /** * Maps from an entity object to the storage record of the base table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @return \stdClass + * The record to store. */ protected function mapToStorageRecord(EntityInterface $entity) { $record = new \stdClass(); @@ -305,6 +514,12 @@ protected function mapToStorageRecord(EntityInterface $entity) { /** * Maps from an entity object to the storage record of the revision table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @return \stdClass + * The record to store. */ protected function mapToRevisionStorageRecord(EntityInterface $entity) { $record = new \stdClass(); @@ -314,4 +529,80 @@ protected function mapToRevisionStorageRecord(EntityInterface $entity) { return $record; } + + /** + * Maps from an entity object to the storage record of the data table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * @param $langcode + * The language code of the translation to get. + * + * @return \stdClass + * The record to store. + */ + protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) { + $default_langcode = $entity->language()->langcode; + // Don't use strict mode, that way there's no need to do checks here. + $translation = $entity->getTranslation($langcode, FALSE); + + $record = new \stdClass(); + foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) { + $record->$name = $translation->$name->value; + } + $record->langcode = $langcode; + $record->default_langcode = intval($default_langcode == $langcode); + + return $record; + } + + /** + * Overwrites Drupal\Core\Entity\DatabaseStorageController::delete(). + */ + public function delete(array $entities) { + if (!$entities) { + // If no IDs or invalid IDs were passed, do nothing. + return; + } + $transaction = db_transaction(); + + try { + $this->preDelete($entities); + foreach ($entities as $id => $entity) { + $this->invokeHook('predelete', $entity); + } + $ids = array_keys($entities); + + db_delete($this->entityInfo['base_table']) + ->condition($this->idKey, $ids, 'IN') + ->execute(); + + if ($this->revisionKey) { + db_delete($this->revisionTable) + ->condition($this->idKey, $ids, 'IN') + ->execute(); + } + + if ($this->dataTable) { + db_delete($this->dataTable) + ->condition($this->idKey, $ids) + ->execute(); + } + + // Reset the cache as soon as the changes have been applied. + $this->resetCache($ids); + + $this->postDelete($entities); + foreach ($entities as $id => $entity) { + $this->invokeHook('delete', $entity); + } + // Ignore slave server temporarily. + db_ignore_slave(); + } + catch (Exception $e) { + $transaction->rollback(); + watchdog_exception($this->entityType, $e); + throw new EntityStorageException($e->getMessage, $e->getCode, $e); + } + } } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 34feb10..581f511 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -295,6 +295,9 @@ public function processDefinition(&$definition, $plugin_id) { // Drupal\Core\Entity\DatabaseStorageControllerInterface::buildQuery(). if (isset($definition['base_table'])) { $definition['schema_fields_sql']['base_table'] = drupal_schema_fields_sql($definition['base_table']); + if (isset($definition['data_table'])) { + $definition['schema_fields_sql']['data_table'] = drupal_schema_fields_sql($definition['data_table']); + } if (isset($definition['revision_table'])) { $definition['schema_fields_sql']['revision_table'] = drupal_schema_fields_sql($definition['revision_table']); } diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 35ef89d..99e66df 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -60,6 +60,28 @@ class EntityNG extends Entity { */ protected $compatibilityMode = FALSE; + /** + * Overrides Entity::__construct(). + */ + public function __construct(array $values, $entity_type, $bundle = FALSE) { + parent::__construct($values, $entity_type, $bundle); + $this->init(); + } + + /** + * Initialize the object. Invoked upon construction and wake up. + */ + protected function init() { + // We unset all defined properties, so magic getters apply. + unset($this->langcode); + } + + /** + * Magic __wakeup() implementation. + */ + public function __wakeup() { + $this->init(); + } /** * Overrides Entity::id(). @@ -258,10 +280,16 @@ public function getTranslationLanguages($include_default = TRUE) { $translations = array(); // Build an array with the translation langcodes set as keys. foreach ($this->getProperties() as $name => $property) { - if (isset($this->values[$name])) { - $translations += $this->values[$name]; + // @todo Figure out why we get localized non-translatable properties here + // and thus have to filter them! + $definition = $property->getDefinition(); + if (!empty($definition['translatable'])) { + if (isset($this->values[$name])) { + $translations += $this->values[$name]; + } + $translations += $this->fields[$name]; } - $translations += $this->fields[$name]; + } unset($translations[LANGUAGE_DEFAULT]); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php index 7cf3403..6c3b546 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php @@ -35,40 +35,43 @@ public static function getInfo() { function testCRUD() { $user1 = $this->drupalCreateUser(); - // Create some test entities. - $entity = entity_create('entity_test', array('name' => 'test', 'user_id' => $user1->uid)); - $entity->save(); - $entity = entity_create('entity_test', array('name' => 'test2', 'user_id' => $user1->uid)); - $entity->save(); - $entity = entity_create('entity_test', array('name' => 'test', 'user_id' => NULL)); - $entity->save(); + // All entity variations have to have the same results. + foreach (_entity_test_entity_types() as $entity_type) { + // Create some test entities. + $entity = entity_create($entity_type, array('name' => 'test', 'user_id' => $user1->uid)); + $entity->save(); + $entity = entity_create($entity_type, array('name' => 'test2', 'user_id' => $user1->uid)); + $entity->save(); + $entity = entity_create($entity_type, array('name' => 'test', 'user_id' => NULL)); + $entity->save(); - $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test'))); - $this->assertEqual($entities[0]->name->value, 'test', 'Created and loaded entity.'); - $this->assertEqual($entities[1]->name->value, 'test', 'Created and loaded entity.'); + $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test'))); + $this->assertEqual($entities[0]->name->value, 'test', $entity_type . ': Created and loaded entity.'); + $this->assertEqual($entities[1]->name->value, 'test', $entity_type . ': Created and loaded entity.'); - // Test loading a single entity. - $loaded_entity = entity_test_load($entity->id()); - $this->assertEqual($loaded_entity->id(), $entity->id(), 'Loaded a single entity by id.'); + // Test loading a single entity. + $loaded_entity = entity_load($entity_type, $entity->id()); + $this->assertEqual($loaded_entity->id(), $entity->id(), $entity_type . ': Loaded a single entity by id.'); - // Test deleting an entity. - $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test2'))); - $entities[0]->delete(); - $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test2'))); - $this->assertEqual($entities, array(), 'Entity deleted.'); + // Test deleting an entity. + $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test2'))); + $entities[0]->delete(); + $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test2'))); + $this->assertEqual($entities, array(), $entity_type . ': Entity deleted.'); - // Test updating an entity. - $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test'))); - $entities[0]->name->value = 'test3'; - $entities[0]->save(); - $entity = entity_test_load($entities[0]->id()); - $this->assertEqual($entity->name->value, 'test3', 'Entity updated.'); + // Test updating an entity. + $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test'))); + $entities[0]->name->value = 'test3'; + $entities[0]->save(); + $entity = entity_load($entity_type, $entities[0]->id()); + $this->assertEqual($entity->name->value, 'test3', $entity_type . ': Entity updated.'); - // Try deleting multiple test entities by deleting all. - $ids = array_keys(entity_test_load_multiple()); - entity_test_delete_multiple($ids); + // Try deleting multiple test entities by deleting all. + $ids = array_keys(entity_load_multiple($entity_type)); + entity_delete_multiple($entity_type, $ids); - $all = entity_test_load_multiple(); - $this->assertTrue(empty($all), 'Deleted all entities.'); + $all = entity_load_multiple($entity_type); + $this->assertTrue(empty($all), $entity_type . ': Deleted all entities.'); + } } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php index a152bfa..8c6b521 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php @@ -38,14 +38,14 @@ public static function getInfo() { * * @return \Drupal\Core\Entity\EntityInterface */ - protected function createTestEntity() { + protected function createTestEntity($entity_type) { $this->entity_name = $this->randomName(); $this->entity_user = $this->drupalCreateUser(); $this->entity_field_text = $this->randomName(); // Pass in the value of the name field when creating. With the user // field we test setting a field after creation. - $entity = entity_create('entity_test', array()); + $entity = entity_create($entity_type, array()); $entity->user_id->value = $this->entity_user->uid; $entity->name->value = $this->entity_name; @@ -59,286 +59,299 @@ protected function createTestEntity() { * Tests reading and writing properties and field items. */ public function testReadWrite() { - $entity = $this->createTestEntity(); - - // Access the name field. - $this->assertTrue($entity->name instanceof FieldInterface, 'Field implements interface'); - $this->assertTrue($entity->name[0] instanceof FieldItemInterface, 'Field item implements interface'); - - $this->assertEqual($this->entity_name, $entity->name->value, 'Name value can be read.'); - $this->assertEqual($this->entity_name, $entity->name[0]->value, 'Name value can be read through list access.'); - $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $this->entity_name)), 'Plain field value returned.'); - - // Change the name. - $new_name = $this->randomName(); - $entity->name->value = $new_name; - $this->assertEqual($new_name, $entity->name->value, 'Name can be updated and read.'); - $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $new_name)), 'Plain field value reflects the update.'); - - $new_name = $this->randomName(); - $entity->name[0]->value = $new_name; - $this->assertEqual($new_name, $entity->name->value, 'Name can be updated and read through list access.'); - - // Access the user field. - $this->assertTrue($entity->user_id instanceof FieldInterface, 'Field implements interface'); - $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, 'Field item implements interface'); - - $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.'); - $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.'); - - // Change the assigned user by entity. - $new_user = $this->drupalCreateUser(); - $entity->user_id->entity = $new_user; - $this->assertEqual($new_user->uid, $entity->user_id->value, 'Updated user id can be read.'); - $this->assertEqual($new_user->name, $entity->user_id->entity->name, 'Updated user name value can be read.'); - - // Change the assigned user by id. - $new_user = $this->drupalCreateUser(); - $entity->user_id->value = $new_user->uid; - $this->assertEqual($new_user->uid, $entity->user_id->value, 'Updated user id can be read.'); - $this->assertEqual($new_user->name, $entity->user_id->entity->name, 'Updated user name value can be read.'); - - // Try unsetting a field. - $entity->name->value = NULL; - $entity->user_id->value = NULL; - $this->assertNull($entity->name->value, 'Name field is not set.'); - $this->assertNull($entity->user_id->value, 'User ID field is not set.'); - $this->assertNull($entity->user_id->entity, 'User entity field is not set.'); - - // Test using isset(), empty() and unset(). - $entity->name->value = 'test unset'; - unset($entity->name->value); - $this->assertFalse(isset($entity->name->value), 'Name is not set.'); - $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.'); - $this->assertTrue(empty($entity->name->value), 'Name is empty.'); - $this->assertTrue(empty($entity->name[0]->value), 'Name is empty.'); - - $entity->name->value = 'a value'; - $this->assertTrue(isset($entity->name->value), 'Name is set.'); - $this->assertTrue(isset($entity->name[0]->value), 'Name is set.'); - $this->assertFalse(empty($entity->name->value), 'Name is not empty.'); - $this->assertFalse(empty($entity->name[0]->value), 'Name is not empty.'); - $this->assertTrue(isset($entity->name[0]), 'Name string item is set.'); - $this->assertFalse(isset($entity->name[1]), 'Second name string item is not set as it does not exist'); - $this->assertTrue(isset($entity->name), 'Name field is set.'); - $this->assertFalse(isset($entity->nameInvalid), 'Not existing field is not set.'); - - unset($entity->name[0]); - $this->assertFalse(isset($entity->name[0]), 'Name field item is not set.'); - $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.'); - $this->assertFalse(isset($entity->name->value), 'Name is not set.'); - - $entity->name->value = 'a value'; - $this->assertTrue(isset($entity->name->value), 'Name is set.'); - unset($entity->name); - $this->assertFalse(isset($entity->name), 'Name field is not set.'); - $this->assertFalse(isset($entity->name[0]), 'Name field item is not set.'); - $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.'); - $this->assertFalse(isset($entity->name->value), 'Name is not set.'); - - // Access the language field. - $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, 'Language code can be read.'); - $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, 'Language object can be read.'); - - // Change the language by code. - $entity->langcode->value = language_default()->langcode; - $this->assertEqual(language_default()->langcode, $entity->langcode->value, 'Language code can be read.'); - $this->assertEqual(language_default(), $entity->langcode->language, 'Language object can be read.'); - - // Revert language by code then try setting it by language object. - $entity->langcode->value = LANGUAGE_NOT_SPECIFIED; - $entity->langcode->language = language_default(); - $this->assertEqual(language_default()->langcode, $entity->langcode->value, 'Language code can be read.'); - $this->assertEqual(language_default(), $entity->langcode->language, 'Language object can be read.'); - - // Access the text field and test updating. - $this->assertEqual($entity->field_test_text->value, $this->entity_field_text, 'Text field can be read.'); - $new_text = $this->randomName(); - $entity->field_test_text->value = $new_text; - $this->assertEqual($entity->field_test_text->value, $new_text, 'Updated text field can be read.'); - - // Test creating the entity by passing in plain values. - $this->entity_name = $this->randomName(); - $name_item[0]['value'] = $this->entity_name; - $this->entity_user = $this->drupalCreateUser(); - $user_item[0]['value'] = $this->entity_user->uid; - $this->entity_field_text = $this->randomName(); - $text_item[0]['value'] = $this->entity_field_text; - - $entity = entity_create('entity_test', array( - 'name' => $name_item, - 'user_id' => $user_item, - 'field_test_text' => $text_item, - )); - $this->assertEqual($this->entity_name, $entity->name->value, 'Name value can be read.'); - $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.'); - $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.'); - $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, 'Text field can be read.'); - - // Test copying field values. - $entity2 = $this->createTestEntity(); - $entity2->name = $entity->name; - $entity2->user_id = $entity->user_id; - $entity2->field_test_text = $entity->field_test_text; - - $this->assertTrue($entity->name !== $entity2->name, 'Copying properties results in a different field object.'); - $this->assertEqual($entity->name->value, $entity2->name->value, 'Name field copied.'); - $this->assertEqual($entity->user_id->value, $entity2->user_id->value, 'User id field copied.'); - $this->assertEqual($entity->field_test_text->value, $entity2->field_test_text->value, 'Text field copied.'); - - // Tests adding a value to a field item list. - $entity->name[] = 'Another name'; - $this->assertEqual($entity->name[1]->value == 'Another name', 'List item added via [].'); - $entity->name[2]->value = 'Third name'; - $this->assertEqual($entity->name[2]->value == 'Third name', 'List item added by a accessing not yet created item.'); - - // Test removing and empty-ing list items. - $this->assertEqual(count($entity->name), 3, 'List has 3 items.'); - unset($entity->name[1]); - $this->assertEqual(count($entity->name), 2, 'Second list item has been removed.'); - $entity->name[2] = NULL; - $this->assertEqual(count($entity->name), 2, 'Assigning NULL does not reduce array count.'); - $this->assertTrue($entity->name[2]->isEmpty(), 'Assigning NULL empties the item.'); - - // Test using isEmpty(). - unset($entity->name[2]); - $this->assertFalse($entity->name[0]->isEmpty(), 'Name item is not empty.'); - $entity->name->value = NULL; - $this->assertTrue($entity->name[0]->isEmpty(), 'Name item is empty.'); - $this->assertTrue($entity->name->isEmpty(), 'Name field is empty.'); - $this->assertEqual(count($entity->name), 1, 'Empty item is considered when counting.'); - $this->assertEqual(count(iterator_to_array($entity->name->getIterator())), count($entity->name), 'Count matches iterator count.'); - $this->assertTrue($entity->name->getValue() === array(0 => NULL), 'Name field value contains a NULL value.'); - - // Test removing all list items by assigning an empty array. - $entity->name = array(); - $this->assertIdentical(count($entity->name), 0, 'Name field contains no items.'); - $this->assertIdentical($entity->name->getValue(), array(), 'Name field value is an empty array.'); - - // Test removing all list items by setting it to NULL. - $entity->name = NULL; - $this->assertIdentical(count($entity->name), 0, 'Name field contains no items.'); - $this->assertIdentical($entity->name->getValue(), array(), 'Name field value is an empty array.'); - - // Test get and set field values. - $entity->name = 'foo'; - $this->assertEqual($entity->name[0]->getPropertyValues(), array('value' => 'foo'), 'Field value has been retrieved via getPropertyValue()'); - $entity->name[0]->setPropertyValues(array('value' => 'bar')); - $this->assertEqual($entity->name->value, 'bar', 'Field value has been set via setPropertyValue()'); - - $values = $entity->getPropertyValues(); - $this->assertEqual($values['name'], array(0 => array('value' => 'bar')), 'Field value has been retrieved via getPropertyValue() from an entity.'); - $entity->setPropertyValues(array('name' => 'foo')); - $this->assertEqual($entity->name->value, 'foo', 'Field value has been set via setPropertyValue() on an entity.'); - - // Make sure the user id can be set to zero. - $user_item[0]['value'] = 0; - $entity = entity_create('entity_test', array( - 'name' => $name_item, - 'user_id' => $user_item, - 'field_test_text' => $text_item, - )); - $this->assertNotNull($entity->user_id->value, 'User id is not NULL'); - $this->assertIdentical($entity->user_id->value, 0, 'User id has been set to 0'); - - // Test setting the ID with the value only. - $entity = entity_create('entity_test', array( - 'name' => $name_item, - 'user_id' => 0, - 'field_test_text' => $text_item, - )); - $this->assertNotNull($entity->user_id->value, 'User id is not NULL'); - $this->assertIdentical($entity->user_id->value, 0, 'User id has been set to 0'); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + + $entity = $this->createTestEntity($entity_type); + + // Access the name field. + $this->assertTrue($entity->name instanceof FieldInterface, $entity_type . ': Field implements interface'); + $this->assertTrue($entity->name[0] instanceof FieldItemInterface, $entity_type . ': Field item implements interface'); + + $this->assertEqual($this->entity_name, $entity->name->value, $entity_type . ': Name value can be read.'); + $this->assertEqual($this->entity_name, $entity->name[0]->value, $entity_type . ': Name value can be read through list access.'); + $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $this->entity_name)), $entity_type . ': Plain field value returned.'); + + // Change the name. + $new_name = $this->randomName(); + $entity->name->value = $new_name; + $this->assertEqual($new_name, $entity->name->value, $entity_type . ': Name can be updated and read.'); + $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $new_name)), $entity_type . ': Plain field value reflects the update.'); + + $new_name = $this->randomName(); + $entity->name[0]->value = $new_name; + $this->assertEqual($new_name, $entity->name->value, $entity_type . ': Name can be updated and read through list access.'); + + // Access the user field. + $this->assertTrue($entity->user_id instanceof FieldInterface, $entity_type . ': Field implements interface'); + $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, $entity_type . ': Field item implements interface'); + + $this->assertEqual($this->entity_user->uid, $entity->user_id->value, $entity_type . ': User id can be read.'); + $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, $entity_type . ': User name can be read.'); + + // Change the assigned user by entity. + $new_user = $this->drupalCreateUser(); + $entity->user_id->entity = $new_user; + $this->assertEqual($new_user->uid, $entity->user_id->value, $entity_type . ': Updated user id can be read.'); + $this->assertEqual($new_user->name, $entity->user_id->entity->name, $entity_type . ': Updated user name value can be read.'); + + // Change the assigned user by id. + $new_user = $this->drupalCreateUser(); + $entity->user_id->value = $new_user->uid; + $this->assertEqual($new_user->uid, $entity->user_id->value, $entity_type . ': Updated user id can be read.'); + $this->assertEqual($new_user->name, $entity->user_id->entity->name, $entity_type . ': Updated user name value can be read.'); + + // Try unsetting a field. + $entity->name->value = NULL; + $entity->user_id->value = NULL; + $this->assertNull($entity->name->value, $entity_type . ': Name field is not set.'); + $this->assertNull($entity->user_id->value, $entity_type . ': User ID field is not set.'); + $this->assertNull($entity->user_id->entity, $entity_type . ': User entity field is not set.'); + + // Test using isset(), empty() and unset(). + $entity->name->value = 'test unset'; + unset($entity->name->value); + $this->assertFalse(isset($entity->name->value), $entity_type . ': Name is not set.'); + $this->assertFalse(isset($entity->name[0]->value), $entity_type . ': Name is not set.'); + $this->assertTrue(empty($entity->name->value), $entity_type . ': Name is empty.'); + $this->assertTrue(empty($entity->name[0]->value), $entity_type . ': Name is empty.'); + + $entity->name->value = 'a value'; + $this->assertTrue(isset($entity->name->value), $entity_type . ': Name is set.'); + $this->assertTrue(isset($entity->name[0]->value), $entity_type . ': Name is set.'); + $this->assertFalse(empty($entity->name->value), $entity_type . ': Name is not empty.'); + $this->assertFalse(empty($entity->name[0]->value), $entity_type . ': Name is not empty.'); + $this->assertTrue(isset($entity->name[0]), $entity_type . ': Name string item is set.'); + $this->assertFalse(isset($entity->name[1]), $entity_type . ': Second name string item is not set as it does not exist'); + $this->assertTrue(isset($entity->name), $entity_type . ': Name field is set.'); + $this->assertFalse(isset($entity->nameInvalid), $entity_type . ': Not existing field is not set.'); + + unset($entity->name[0]); + $this->assertFalse(isset($entity->name[0]), $entity_type . ': Name field item is not set.'); + $this->assertFalse(isset($entity->name[0]->value), $entity_type . ': Name is not set.'); + $this->assertFalse(isset($entity->name->value), $entity_type . ': Name is not set.'); + + $entity->name->value = 'a value'; + $this->assertTrue(isset($entity->name->value), $entity_type . ': Name is set.'); + unset($entity->name); + $this->assertFalse(isset($entity->name), $entity_type . ': Name field is not set.'); + $this->assertFalse(isset($entity->name[0]), $entity_type . ': Name field item is not set.'); + $this->assertFalse(isset($entity->name[0]->value), $entity_type . ': Name is not set.'); + $this->assertFalse(isset($entity->name->value), $entity_type . ': Name is not set.'); + + // Access the language field. + $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, $entity_type . ': Language code can be read.'); + $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, $entity_type . ': Language object can be read.'); + + // Change the language by code. + $entity->langcode->value = language_default()->langcode; + $this->assertEqual(language_default()->langcode, $entity->langcode->value, $entity_type . ': Language code can be read.'); + $this->assertEqual(language_default(), $entity->langcode->language, $entity_type . ': Language object can be read.'); + + // Revert language by code then try setting it by language object. + $entity->langcode->value = LANGUAGE_NOT_SPECIFIED; + $entity->langcode->language = language_default(); + $this->assertEqual(language_default()->langcode, $entity->langcode->value, $entity_type . ': Language code can be read.'); + $this->assertEqual(language_default(), $entity->langcode->language, $entity_type . ': Language object can be read.'); + + // Access the text field and test updating. + $this->assertEqual($entity->field_test_text->value, $this->entity_field_text, $entity_type . ': Text field can be read.'); + $new_text = $this->randomName(); + $entity->field_test_text->value = $new_text; + $this->assertEqual($entity->field_test_text->value, $new_text, $entity_type . ': Updated text field can be read.'); + + // Test creating the entity by passing in plain values. + $this->entity_name = $this->randomName(); + $name_item[0]['value'] = $this->entity_name; + $this->entity_user = $this->drupalCreateUser(); + $user_item[0]['value'] = $this->entity_user->uid; + $this->entity_field_text = $this->randomName(); + $text_item[0]['value'] = $this->entity_field_text; + + $entity = entity_create($entity_type, array( + 'name' => $name_item, + 'user_id' => $user_item, + 'field_test_text' => $text_item, + )); + $this->assertEqual($this->entity_name, $entity->name->value, $entity_type . ': Name value can be read.'); + $this->assertEqual($this->entity_user->uid, $entity->user_id->value, $entity_type . ': User id can be read.'); + $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, $entity_type . ': User name can be read.'); + $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, $entity_type . ': Text field can be read.'); + + // Test copying field values. + $entity2 = $this->createTestEntity($entity_type); + $entity2->name = $entity->name; + $entity2->user_id = $entity->user_id; + $entity2->field_test_text = $entity->field_test_text; + + $this->assertTrue($entity->name !== $entity2->name, $entity_type . ': Copying properties results in a different field object.'); + $this->assertEqual($entity->name->value, $entity2->name->value, $entity_type . ': Name field copied.'); + $this->assertEqual($entity->user_id->value, $entity2->user_id->value, $entity_type . ': User id field copied.'); + $this->assertEqual($entity->field_test_text->value, $entity2->field_test_text->value, $entity_type . ': Text field copied.'); + + // Tests adding a value to a field item list. + $entity->name[] = 'Another name'; + $this->assertEqual($entity->name[1]->value == 'Another name', $entity_type . ': List item added via [].'); + $entity->name[2]->value = 'Third name'; + $this->assertEqual($entity->name[2]->value == 'Third name', $entity_type . ': List item added by a accessing not yet created item.'); + + // Test removing and empty-ing list items. + $this->assertEqual(count($entity->name), 3, $entity_type . ': List has 3 items.'); + unset($entity->name[1]); + $this->assertEqual(count($entity->name), 2, $entity_type . ': Second list item has been removed.'); + $entity->name[2] = NULL; + $this->assertEqual(count($entity->name), 2, $entity_type . ': Assigning NULL does not reduce array count.'); + $this->assertTrue($entity->name[2]->isEmpty(), $entity_type . ': Assigning NULL empties the item.'); + + // Test using isEmpty(). + unset($entity->name[2]); + $this->assertFalse($entity->name[0]->isEmpty(), $entity_type . ': Name item is not empty.'); + $entity->name->value = NULL; + $this->assertTrue($entity->name[0]->isEmpty(), $entity_type . ': Name item is empty.'); + $this->assertTrue($entity->name->isEmpty(), $entity_type . ': Name field is empty.'); + $this->assertEqual(count($entity->name), 1, $entity_type . ': Empty item is considered when counting.'); + $this->assertEqual(count(iterator_to_array($entity->name->getIterator())), count($entity->name), $entity_type . ': Count matches iterator count.'); + $this->assertTrue($entity->name->getValue() === array(0 => NULL), $entity_type . ': Name field value contains a NULL value.'); + + // Test removing all list items by assigning an empty array. + $entity->name = array(); + $this->assertIdentical(count($entity->name), 0, $entity_type . ': Name field contains no items.'); + $this->assertIdentical($entity->name->getValue(), array(), $entity_type . ': Name field value is an empty array.'); + + // Test removing all list items by setting it to NULL. + $entity->name = NULL; + $this->assertIdentical(count($entity->name), 0, $entity_type . ': Name field contains no items.'); + $this->assertIdentical($entity->name->getValue(), array(), $entity_type . ': Name field value is an empty array.'); + + // Test get and set field values. + $entity->name = 'foo'; + $this->assertEqual($entity->name[0]->getPropertyValues(), array('value' => 'foo'), $entity_type . ': Field value has been retrieved via getPropertyValue()'); + $entity->name[0]->setPropertyValues(array('value' => 'bar')); + $this->assertEqual($entity->name->value, 'bar', $entity_type . ': Field value has been set via setPropertyValue()'); + + $values = $entity->getPropertyValues(); + $this->assertEqual($values['name'], array(0 => array('value' => 'bar')), $entity_type . ': Field value has been retrieved via getPropertyValue() from an entity.'); + $entity->setPropertyValues(array('name' => 'foo')); + $this->assertEqual($entity->name->value, 'foo', $entity_type . ': Field value has been set via setPropertyValue() on an entity.'); + + // Make sure the user id can be set to zero. + $user_item[0]['value'] = 0; + $entity = entity_create($entity_type, array( + 'name' => $name_item, + 'user_id' => $user_item, + 'field_test_text' => $text_item, + )); + $this->assertNotNull($entity->user_id->value, $entity_type . ': User id is not NULL'); + $this->assertIdentical($entity->user_id->value, 0, $entity_type . ': User id has been set to 0'); + + // Test setting the ID with the value only. + $entity = entity_create($entity_type, array( + 'name' => $name_item, + 'user_id' => 0, + 'field_test_text' => $text_item, + )); + $this->assertNotNull($entity->user_id->value, $entity_type . ': User id is not NULL'); + $this->assertIdentical($entity->user_id->value, 0, $entity_type . ': User id has been set to 0'); + } } /** * Tries to save and load an entity again. */ public function testSave() { - $entity = $this->createTestEntity(); - $entity->save(); - $this->assertTrue((bool) $entity->id(), 'Entity has received an id.'); - - $entity = entity_load('entity_test', $entity->id()); - $this->assertTrue((bool) $entity->id(), 'Entity loaded.'); - - // Access the name field. - $this->assertEqual(1, $entity->id->value, 'ID value can be read.'); - $this->assertTrue(is_string($entity->uuid->value), 'UUID value can be read.'); - $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, 'Language code can be read.'); - $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, 'Language object can be read.'); - $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.'); - $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.'); - $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, 'Text field can be read.'); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + $entity = $this->createTestEntity($entity_type); + $entity->save(); + $this->assertTrue((bool) $entity->id(), $entity_type . ': Entity has received an id.'); + + $entity = entity_load($entity_type, $entity->id()); + $this->assertTrue((bool) $entity->id(), $entity_type . ': Entity loaded.'); + + // Access the name field. + $this->assertEqual(1, $entity->id->value, $entity_type . ': ID value can be read.'); + $this->assertTrue(is_string($entity->uuid->value), $entity_type . ': UUID value can be read.'); + $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, $entity_type . ': Language code can be read.'); + $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, $entity_type . ': Language object can be read.'); + $this->assertEqual($this->entity_user->uid, $entity->user_id->value, $entity_type . ': User id can be read.'); + $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, $entity_type . ': User name can be read.'); + $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, $entity_type . ': Text field can be read.'); + } } /** * Tests introspection and getting metadata upfront. */ public function testIntrospection() { - // Test getting metadata upfront, i.e. without having an entity object. - $definition = array( - 'type' => 'entity', - 'constraints' => array( - 'entity type' => 'entity_test', - ), - 'label' => t('Test entity'), - ); - $wrapped_entity = typed_data()->create($definition); - $definitions = $wrapped_entity->getPropertyDefinitions($definition); - $this->assertEqual($definitions['name']['type'], 'string_field', 'Name field found.'); - $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', 'User field found.'); - $this->assertEqual($definitions['field_test_text']['type'], 'text_field', 'Test-text-field field found.'); - - // Test introspecting an entity object. - // @todo: Add bundles and test bundles as well. - $entity = entity_create('entity_test', array()); - - $definitions = $entity->getPropertyDefinitions(); - $this->assertEqual($definitions['name']['type'], 'string_field', 'Name field found.'); - $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', 'User field found.'); - $this->assertEqual($definitions['field_test_text']['type'], 'text_field', 'Test-text-field field found.'); - - $name_properties = $entity->name->getPropertyDefinitions(); - $this->assertEqual($name_properties['value']['type'], 'string', 'String value property of the name found.'); - - $userref_properties = $entity->user_id->getPropertyDefinitions(); - $this->assertEqual($userref_properties['value']['type'], 'integer', 'Entity id property of the user found.'); - $this->assertEqual($userref_properties['entity']['type'], 'entity', 'Entity reference property of the user found.'); - - $textfield_properties = $entity->field_test_text->getPropertyDefinitions(); - $this->assertEqual($textfield_properties['value']['type'], 'string', 'String value property of the test-text field found.'); - $this->assertEqual($textfield_properties['format']['type'], 'string', 'String format field of the test-text field found.'); - $this->assertEqual($textfield_properties['processed']['type'], 'string', 'String processed property of the test-text field found.'); - - // @todo: Once the user entity has definitions, continue testing getting - // them from the $userref_values['entity'] property. + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + // Test getting metadata upfront, i.e. without having an entity object. + $definition = array( + 'type' => 'entity', + 'constraints' => array( + 'entity type' => $entity_type, + ), + 'label' => t('Test entity'), + ); + $wrapped_entity = typed_data()->create($definition); + $definitions = $wrapped_entity->getPropertyDefinitions($definition); + $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.'); + $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', $entity_type .': User field found.'); + $this->assertEqual($definitions['field_test_text']['type'], 'text_field', $entity_type .': Test-text-field field found.'); + + // Test introspecting an entity object. + // @todo: Add bundles and test bundles as well. + $entity = entity_create($entity_type, array()); + + $definitions = $entity->getPropertyDefinitions(); + $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.'); + $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', $entity_type .': User field found.'); + $this->assertEqual($definitions['field_test_text']['type'], 'text_field', $entity_type .': Test-text-field field found.'); + + $name_properties = $entity->name->getPropertyDefinitions(); + $this->assertEqual($name_properties['value']['type'], 'string', $entity_type .': String value property of the name found.'); + + $userref_properties = $entity->user_id->getPropertyDefinitions(); + $this->assertEqual($userref_properties['value']['type'], 'integer', $entity_type .': Entity id property of the user found.'); + $this->assertEqual($userref_properties['entity']['type'], 'entity', $entity_type .': Entity reference property of the user found.'); + + $textfield_properties = $entity->field_test_text->getPropertyDefinitions(); + $this->assertEqual($textfield_properties['value']['type'], 'string', $entity_type .': String value property of the test-text field found.'); + $this->assertEqual($textfield_properties['format']['type'], 'string', $entity_type .': String format field of the test-text field found.'); + $this->assertEqual($textfield_properties['processed']['type'], 'string', $entity_type .': String processed property of the test-text field found.'); + + // @todo: Once the user entity has definitions, continue testing getting + // them from the $userref_values['entity'] property. + } } /** * Tests iterating over properties. */ public function testIterator() { - $entity = $this->createTestEntity(); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + $entity = $this->createTestEntity($entity_type); - foreach ($entity as $name => $field) { - $this->assertTrue($field instanceof FieldInterface, "Field $name implements interface."); + foreach ($entity as $name => $field) { + $this->assertTrue($field instanceof FieldInterface, $entity_type . ": Field $name implements interface."); - foreach ($field as $delta => $item) { - $this->assertTrue($field[0] instanceof FieldItemInterface, "Item $delta of field $name implements interface."); + foreach ($field as $delta => $item) { + $this->assertTrue($field[0] instanceof FieldItemInterface, $entity_type . ": Item $delta of field $name implements interface."); - foreach ($item as $value_name => $value_property) { - $this->assertTrue($value_property instanceof TypedDataInterface, "Value $value_name of item $delta of field $name implements interface."); + foreach ($item as $value_name => $value_property) { + $this->assertTrue($value_property instanceof TypedDataInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface."); - $value = $value_property->getValue(); - $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, "Value $value_name of item $delta of field $name is a primitive or an entity."); + $value = $value_property->getValue(); + $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value $value_name of item $delta of field $name is a primitive or an entity."); + } } } - } - $properties = $entity->getProperties(); - $this->assertEqual(array_keys($properties), array_keys($entity->getPropertyDefinitions()), 'All properties returned.'); - $this->assertEqual($properties, iterator_to_array($entity->getIterator()), 'Entity iterator iterates over all properties.'); + $properties = $entity->getProperties(); + $this->assertEqual(array_keys($properties), array_keys($entity->getPropertyDefinitions()), $entity_type . ': All properties returned.'); + $this->assertEqual($properties, iterator_to_array($entity->getIterator()), $entity_type . ': Entity iterator iterates over all properties.'); + } } /** @@ -346,33 +359,36 @@ public function testIterator() { * list interfaces. */ public function testDataStructureInterfaces() { - $entity = $this->createTestEntity(); - $entity->save(); - $entity_definition = array( - 'type' => 'entity', - 'constraints' => array( - 'entity type' => 'entity_test', - ), - 'label' => t('Test entity'), - ); - $wrapped_entity = typed_data()->create($entity_definition, $entity); - - // For the test we navigate through the tree of contained properties and get - // all contained strings, limited by a certain depth. - $strings = array(); - $this->getContainedStrings($wrapped_entity, 0, $strings); - - // @todo: Once the user entity has defined properties this should contain - // the user name and other user entity strings as well. - $target_strings = array( - $entity->uuid->value, - LANGUAGE_NOT_SPECIFIED, - $this->entity_name, - $this->entity_field_text, - // Field format. - NULL, - ); - $this->assertEqual($strings, $target_strings, 'All contained strings found.'); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + $entity = $this->createTestEntity($entity_type); + $entity->save(); + $entity_definition = array( + 'type' => 'entity', + 'constraints' => array( + 'entity type' => $entity_type, + ), + 'label' => t('Test entity'), + ); + $wrapped_entity = typed_data()->create($entity_definition, $entity); + + // For the test we navigate through the tree of contained properties and get + // all contained strings, limited by a certain depth. + $strings = array(); + $this->getContainedStrings($wrapped_entity, 0, $strings); + + // @todo: Once the user entity has defined properties this should contain + // the user name and other user entity strings as well. + $target_strings = array( + $entity->uuid->value, + LANGUAGE_NOT_SPECIFIED, + $this->entity_name, + $this->entity_field_text, + // Field format. + NULL, + ); + $this->assertEqual($strings, $target_strings, $entity_type . ': All contained strings found.'); + } } /** @@ -404,21 +420,24 @@ public function getContainedStrings(TypedDataInterface $wrapper, $depth, array & * Tests getting processed property values via a computed property. */ public function testComputedProperties() { - // Make the test text field processed. - $instance = field_info_instance('entity_test', 'field_test_text', 'entity_test'); - $instance['settings']['text_processing'] = 1; - field_update_instance($instance); - - $entity = $this->createTestEntity(); - $entity->field_test_text->value = "The text text to filter."; - $entity->field_test_text->format = filter_default_format(); - - $target = "

The <strong>text</strong> text to filter.

\n"; - $this->assertEqual($entity->field_test_text->processed, $target, 'Text is processed with the default filter.'); - - // Save and load entity and make sure it still works. - $entity->save(); - $entity = entity_load('entity_test', $entity->id()); - $this->assertEqual($entity->field_test_text->processed, $target, 'Text is processed with the default filter.'); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + // Make the test text field processed. + $instance = field_info_instance($entity_type, 'field_test_text', $entity_type); + $instance['settings']['text_processing'] = 1; + field_update_instance($instance); + + $entity = $this->createTestEntity($entity_type); + $entity->field_test_text->value = "The text text to filter."; + $entity->field_test_text->format = filter_default_format(); + + $target = "

The <strong>text</strong> text to filter.

\n"; + $this->assertEqual($entity->field_test_text->processed, $target, $entity_type . ': Text is processed with the default filter.'); + + // Save and load entity and make sure it still works. + $entity->save(); + $entity = entity_load($entity_type, $entity->id()); + $this->assertEqual($entity->field_test_text->processed, $target, $entity_type . ': Text is processed with the default filter.'); + } } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php index 278e151..7dcf11f 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php @@ -39,38 +39,42 @@ function setUp() { * Tests basic form CRUD functionality. */ function testFormCRUD() { - $langcode = LANGUAGE_NOT_SPECIFIED; - $name1 = $this->randomName(8); - $name2 = $this->randomName(10); + // All entity variations have to have the same results. + foreach(_entity_test_entity_types() as $entity_type) { + $entity_type_path = str_replace('_', '-', $entity_type); - $edit = array( - 'name' => $name1, - 'user_id' => mt_rand(0, 128), - "field_test_text[$langcode][0][value]" => $this->randomName(16), - ); + $langcode = LANGUAGE_NOT_SPECIFIED; + $name1 = $this->randomName(8); + $name2 = $this->randomName(10); + + $edit = array( + 'name' => $name1, + 'user_id' => mt_rand(0, 128), + "field_test_text[$langcode][0][value]" => $this->randomName(16), + ); - $this->drupalPost('entity-test/add', $edit, t('Save')); - $entity = $this->loadEntityByName($name1); - $this->assertTrue($entity, 'Entity found in the database.'); + $this->drupalPost($entity_type_path . '/add', $edit, t('Save')); + $entity = $this->loadEntityByName($entity_type, $name1); + $this->assertTrue($entity, $entity_type . ': Entity found in the database.'); - $edit['name'] = $name2; - $this->drupalPost('entity-test/manage/' . $entity->id() . '/edit', $edit, t('Save')); - $entity = $this->loadEntityByName($name1); - $this->assertFalse($entity, 'The entity has been modified.'); - $entity = $this->loadEntityByName($name2); - $this->assertTrue($entity, 'Modified entity found in the database.'); - $this->assertNotEqual($entity->name->value, $name1, 'The entity name has been modified.'); + $edit['name'] = $name2; + $this->drupalPost($entity_type_path . '/manage/' . $entity->id() . '/edit', $edit, t('Save')); + $entity = $this->loadEntityByName($entity_type, $name1); + $this->assertFalse($entity, $entity_type . ': The entity has been modified.'); + $entity = $this->loadEntityByName($entity_type, $name2); + $this->assertTrue($entity, $entity_type . ': Modified entity found in the database.'); + $this->assertNotEqual($entity->name->value, $name1, $entity_type . ': The entity name has been modified.'); - $this->drupalPost('entity-test/manage/' . $entity->id() . '/edit', array(), t('Delete')); - $entity = $this->loadEntityByName($name2); - $this->assertFalse($entity, 'Entity not found in the database.'); + $this->drupalPost($entity_type_path . '/manage/' . $entity->id() . '/edit', array(), t('Delete')); + $entity = $this->loadEntityByName($entity_type, $name2); + $this->assertFalse($entity, $entity_type . ': Entity not found in the database.'); + } } /** * Loads a test entity by name always resetting the storage controller cache. */ - protected function loadEntityByName($name) { - $entity_type = 'entity_test'; + protected function loadEntityByName($entity_type, $name) { // Always load the entity from the database to ensure that changes are // correctly picked up. entity_get_controller($entity_type)->resetCache(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php index c94972d..475922a 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php @@ -47,53 +47,58 @@ public function setUp() { */ public function testRevisions() { - // Create initial entity. - $entity = entity_create('entity_test', array( - 'name' => 'foo', - 'user_id' => $this->web_user->uid, - )); - $entity->field_test_text->value = 'bar'; - $entity->save(); - - $entities = array(); - $names = array(); - $texts = array(); - $revision_ids = array(); - - // Create three revisions. - $revision_count = 3; - for ($i = 0; $i < $revision_count; $i++) { - $legacy_revision_id = $entity->revision_id->value; - $legacy_name = $entity->name->value; - $legacy_text = $entity->field_test_text->value; - - $entity = entity_test_load($entity->id->value); - $entity->setNewRevision(TRUE); - $names[] = $entity->name->value = $this->randomName(32); - $texts[] = $entity->field_test_text->value = $this->randomName(32); + // All revisionable entity variations have to have the same results. + foreach(_entity_test_revisionable_entity_types() as $entity_type) { + $entity_type_path = str_replace('_', '-', $entity_type); + + // Create initial entity. + $entity = entity_create($entity_type, array( + 'name' => 'foo', + 'user_id' => $this->web_user->uid, + )); + $entity->field_test_text->value = 'bar'; $entity->save(); - $revision_ids[] = $entity->revision_id->value; - // Check that the fields and properties contain new content. - $this->assertTrue($entity->revision_id->value > $legacy_revision_id, 'Revision ID changed.'); - $this->assertNotEqual($entity->name->value, $legacy_name, 'Name changed.'); - $this->assertNotEqual($entity->field_test_text->value, $legacy_text, 'Text changed.'); + $entities = array(); + $names = array(); + $texts = array(); + $revision_ids = array(); + + // Create three revisions. + $revision_count = 3; + for ($i = 0; $i < $revision_count; $i++) { + $legacy_revision_id = $entity->revision_id->value; + $legacy_name = $entity->name->value; + $legacy_text = $entity->field_test_text->value; + + $entity = entity_load($entity_type, $entity->id->value); + $entity->setNewRevision(TRUE); + $names[] = $entity->name->value = $this->randomName(32); + $texts[] = $entity->field_test_text->value = $this->randomName(32); + $entity->save(); + $revision_ids[] = $entity->revision_id->value; + + // Check that the fields and properties contain new content. + $this->assertTrue($entity->revision_id->value > $legacy_revision_id, $entity_type . ': Revision ID changed.'); + $this->assertNotEqual($entity->name->value, $legacy_name, $entity_type . ': Name changed.'); + $this->assertNotEqual($entity->field_test_text->value, $legacy_text, $entity_type . ': Text changed.'); + } + + for ($i = 0; $i < $revision_count; $i++) { + // Load specific revision. + $entity_revision = entity_revision_load($entity_type, $revision_ids[$i]); + + // Check if properties and fields contain the revision specific content. + $this->assertEqual($entity_revision->revision_id->value, $revision_ids[$i], $entity_type . ': Revision ID matches.'); + $this->assertEqual($entity_revision->name->value, $names[$i], $entity_type . ': Name matches.'); + $this->assertEqual($entity_revision->field_test_text->value, $texts[$i], $entity_type . ': Text matches.'); + } + + // Confirm the correct revision text appears in the edit form. + $entity = entity_load($entity_type, $entity->id->value); + $this->drupalGet($entity_type_path . '/manage/' . $entity->id->value); + $this->assertFieldById('edit-name', $entity->name->value, $entity_type . ': Name matches in UI.'); + $this->assertFieldById('edit-field-test-text-und-0-value', $entity->field_test_text->value, $entity_type . ': Text matches in UI.'); } - - for ($i = 0; $i < $revision_count; $i++) { - // Load specific revision. - $entity_revision = entity_revision_load('entity_test', $revision_ids[$i]); - - // Check if properties and fields contain the revision specific content. - $this->assertEqual($entity_revision->revision_id->value, $revision_ids[$i], 'Revision ID matches.'); - $this->assertEqual($entity_revision->name->value, $names[$i], 'Name matches.'); - $this->assertEqual($entity_revision->field_test_text->value, $texts[$i], 'Text matches.'); - } - - // Confirm the correct revision text appears in the edit form. - $entity = entity_load('entity_test', $entity->id->value); - $this->drupalGet('entity-test/manage/' . $entity->id->value); - $this->assertFieldById('edit-name', $entity->name->value, 'Name matches in UI.'); - $this->assertFieldById('edit-field-test-text-und-0-value', $entity->field_test_text->value, 'Text matches in UI.'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php index b34873a..fc4f711 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php @@ -50,13 +50,16 @@ function setUp() { field_create_field($field); $this->field = field_read_field($this->field_name); - $instance = array( - 'field_name' => $this->field_name, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ); - field_create_instance($instance); - $this->instance = field_read_instance('entity_test', $this->field_name, 'entity_test'); + // Create instance in all entity variations. + foreach (_entity_test_entity_types() as $entity_type) { + $instance = array( + 'field_name' => $this->field_name, + 'entity_type' => $entity_type, + 'bundle' => $entity_type, + ); + field_create_instance($instance); + $this->instance[$entity_type] = field_read_instance($entity_type, $this->field_name, $entity_type); + } // Create test languages. $this->langcodes = array(); @@ -74,229 +77,239 @@ function setUp() { * Tests language related methods of the Entity class. */ function testEntityLanguageMethods() { - $entity = entity_create('entity_test', array( - 'name' => 'test', - 'user_id' => $GLOBALS['user']->uid, - )); - $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, 'Entity language not specified.'); - $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available'); - - // Set the value in default language. - $entity->set($this->field_name, array(0 => array('value' => 'default value'))); - // Get the value. - $this->assertEqual($entity->getTranslation(LANGUAGE_DEFAULT)->get($this->field_name)->value, 'default value', 'Untranslated value retrieved.'); - - // Set the value in a certain language. As the entity is not - // language-specific it should use the default language and so ignore the - // specified language. - $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'default value2'))); - $this->assertEqual($entity->get($this->field_name)->value, 'default value2', 'Untranslated value updated.'); - $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available'); - - // Test getting a field value using a specific language for a not - // language-specific entity. - $this->assertEqual($entity->getTranslation($this->langcodes[1])->get($this->field_name)->value, 'default value2', 'Untranslated value retrieved.'); - - // Now, make the entity language-specific by assigning a language and test - // translating it. - $entity->langcode->value = $this->langcodes[0]; - $entity->{$this->field_name} = array(); - $this->assertEqual($entity->language(), language_load($this->langcodes[0]), 'Entity language retrieved.'); - $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available'); - - // Set the value in default language. - $entity->set($this->field_name, array(0 => array('value' => 'default value'))); - // Get the value. - $this->assertEqual($entity->get($this->field_name)->value, 'default value', 'Untranslated value retrieved.'); - - // Set a translation. - $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'translation 1'))); - $this->assertEqual($entity->getTranslation($this->langcodes[1])->{$this->field_name}->value, 'translation 1', 'Translated value set.'); - - // Make sure the untranslated value stays. - $this->assertEqual($entity->get($this->field_name)->value, 'default value', 'Untranslated value stays.'); - - $translations[$this->langcodes[1]] = language_load($this->langcodes[1]); - $this->assertEqual($entity->getTranslationLanguages(FALSE), $translations, 'Translations retrieved.'); - - // Try to get a not available translation. - $this->assertNull($entity->getTranslation($this->langcodes[2])->get($this->field_name)->value, 'A translation that is not available is NULL.'); - - // Try to get a value using an invalid language code. - try { - $entity->getTranslation('invalid')->get($this->field_name)->value; - $this->fail('Getting a translation for an invalid language is NULL.'); - } - catch (InvalidArgumentException $e) { - $this->pass('A translation for an invalid language is NULL.'); - } + // Test all entity variations. + foreach (_entity_test_entity_types() as $entity_type) { + $entity = entity_create($entity_type, array( + 'name' => 'test', + 'user_id' => $GLOBALS['user']->uid, + )); + $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, $entity_type . ': Entity language not specified.'); + $this->assertFalse($entity->getTranslationLanguages(FALSE), $entity_type . ': No translations are available'); + + // Set the value in default language. + $entity->set($this->field_name, array(0 => array('value' => 'default value'))); + // Get the value. + $this->assertEqual($entity->getTranslation(LANGUAGE_DEFAULT)->get($this->field_name)->value, 'default value', $entity_type . ': Untranslated value retrieved.'); + + // Set the value in a certain language. As the entity is not + // language-specific it should use the default language and so ignore the + // specified language. + $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'default value2'))); + $this->assertEqual($entity->get($this->field_name)->value, 'default value2', $entity_type . ': Untranslated value updated.'); + $this->assertFalse($entity->getTranslationLanguages(FALSE), $entity_type . ': No translations are available'); + + // Test getting a field value using a specific language for a not + // language-specific entity. + $this->assertEqual($entity->getTranslation($this->langcodes[1])->get($this->field_name)->value, 'default value2', $entity_type . ': Untranslated value retrieved.'); + + // Now, make the entity language-specific by assigning a language and test + // translating it. + $entity->langcode->value = $this->langcodes[0]; + $entity->{$this->field_name} = array(); + $this->assertEqual($entity->language(), language_load($this->langcodes[0]), $entity_type . ': Entity language retrieved.'); + $this->assertFalse($entity->getTranslationLanguages(FALSE), $entity_type . ': No translations are available'); + + // Set the value in default language. + $entity->set($this->field_name, array(0 => array('value' => 'default value'))); + // Get the value. + $this->assertEqual($entity->get($this->field_name)->value, 'default value', $entity_type . ': Untranslated value retrieved.'); + + // Set a translation. + $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'translation 1'))); + $this->assertEqual($entity->getTranslation($this->langcodes[1])->{$this->field_name}->value, 'translation 1', $entity_type . ': Translated value set.'); + + // Make sure the untranslated value stays. + $this->assertEqual($entity->get($this->field_name)->value, 'default value', 'Untranslated value stays.'); + + $translations[$this->langcodes[1]] = language_load($this->langcodes[1]); + $this->assertEqual($entity->getTranslationLanguages(FALSE), $translations, 'Translations retrieved.'); + + // Try to get a not available translation. + $this->assertNull($entity->getTranslation($this->langcodes[2])->get($this->field_name)->value, $entity_type . ': A translation that is not available is NULL.'); + + // Try to get a value using an invalid language code. + try { + $entity->getTranslation('invalid')->get($this->field_name)->value; + $this->fail('Getting a translation for an invalid language is NULL.'); + } + catch (InvalidArgumentException $e) { + $this->pass('A translation for an invalid language is NULL.'); + } - // Try to get an untranslatable value from a translation in strict mode. - try { - $field_name = 'field_test_text'; - $value = $entity->getTranslation($this->langcodes[1])->get($field_name); - $this->fail('Getting an untranslatable value from a translation in strict mode throws an exception.'); - } - catch (InvalidArgumentException $e) { - $this->pass('Getting an untranslatable value from a translation in strict mode throws an exception.'); - } + // Try to get an untranslatable value from a translation in strict mode. + try { + $field_name = 'field_test_text'; + $value = $entity->getTranslation($this->langcodes[1])->get($field_name); + $this->fail($entity_type . ': Getting an untranslatable value from a translation in strict mode throws an exception.'); + } + catch (InvalidArgumentException $e) { + $this->pass($entity_type . ': Getting an untranslatable value from a translation in strict mode throws an exception.'); + } - // Try to get an untranslatable value from a translation in non-strict - // mode. - $entity->set($field_name, array(0 => array('value' => 'default value'))); - $value = $entity->getTranslation($this->langcodes[1], FALSE)->get($field_name)->value; - $this->assertEqual($value, 'default value', 'Untranslated value retrieved from translation in non-strict mode.'); + // Try to get an untranslatable value from a translation in non-strict + // mode. + $entity->set($field_name, array(0 => array('value' => 'default value'))); + $value = $entity->getTranslation($this->langcodes[1], FALSE)->get($field_name)->value; + $this->assertEqual($value, 'default value', $entity_type . ': Untranslated value retrieved from translation in non-strict mode.'); - // Try to set a value using an invalid language code. - try { - $entity->getTranslation('invalid')->set($this->field_name, NULL); - $this->fail("Setting a translation for an invalid language throws an exception."); - } - catch (InvalidArgumentException $e) { - $this->pass("Setting a translation for an invalid language throws an exception."); - } + // Try to set a value using an invalid language code. + try { + $entity->getTranslation('invalid')->set($this->field_name, NULL); + $this->fail($entity_type . ': Setting a translation for an invalid language throws an exception.'); + } + catch (InvalidArgumentException $e) { + $this->pass($entity_type . ': Setting a translation for an invalid language throws an exception.'); + } - // Try to set an untranslatable value into a translation in strict mode. - try { - $entity->getTranslation($this->langcodes[1])->set($field_name, NULL); - $this->fail("Setting an untranslatable value into a translation in strict mode throws an exception."); - } - catch (InvalidArgumentException $e) { - $this->pass("Setting an untranslatable value into a translation in strict mode throws an exception."); - } + // Try to set an untranslatable value into a translation in strict mode. + try { + $entity->getTranslation($this->langcodes[1])->set($field_name, NULL); + $this->fail($entity_type . ': Setting an untranslatable value into a translation in strict mode throws an exception.'); + } + catch (InvalidArgumentException $e) { + $this->pass($entity_type . ': Setting an untranslatable value into a translation in strict mode throws an exception.'); + } - // Set the value in default language. - $entity->getTranslation($this->langcodes[1], FALSE)->set($field_name, array(0 => array('value' => 'default value2'))); - // Get the value. - $this->assertEqual($entity->get($field_name)->value, 'default value2', 'Untranslated value set into a translation in non-strict mode.'); + // Set the value in default language. + $entity->getTranslation($this->langcodes[1], FALSE)->set($field_name, array(0 => array('value' => 'default value2'))); + // Get the value. + $this->assertEqual($entity->get($field_name)->value, 'default value2', $entity_type . ': Untranslated value set into a translation in non-strict mode.'); + } } /** * Tests multilingual properties. */ function testMultilingualProperties() { - $name = $this->randomName(); - $uid = mt_rand(0, 127); - $langcode = $this->langcodes[0]; - - // Create a language neutral entity and check that properties are stored - // as language neutral. - $entity = entity_create('entity_test', array('name' => $name, 'user_id' => $uid)); - $entity->save(); - $entity = entity_test_load($entity->id()); - $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, 'Entity created as language neutral.'); - $this->assertEqual($name, $entity->getTranslation(LANGUAGE_DEFAULT)->get('name')->value, 'The entity name has been correctly stored as language neutral.'); - $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_DEFAULT)->get('user_id')->value, 'The entity author has been correctly stored as language neutral.'); - // As fields, translatable properties should ignore the given langcode and - // use neutral language if the entity is not translatable. - $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, 'The entity name defaults to neutral language.'); - $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, 'The entity author defaults to neutral language.'); - $this->assertEqual($name, $entity->get('name')->value, 'The entity name can be retrieved without specifying a language.'); - $this->assertEqual($uid, $entity->get('user_id')->value, 'The entity author can be retrieved without specifying a language.'); - - // Create a language-aware entity and check that properties are stored - // as language-aware. - $entity = entity_create('entity_test', array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode)); - $entity->save(); - $entity = entity_test_load($entity->id()); - $this->assertEqual($entity->language()->langcode, $langcode, 'Entity created as language specific.'); - $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, 'The entity name has been correctly stored as a language-aware property.'); - $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, 'The entity author has been correctly stored as a language-aware property.'); - // Translatable properties on a translatable entity should use default - // language if LANGUAGE_NOT_SPECIFIED is passed. - $this->assertEqual($name, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('name')->value, 'The entity name defaults to the default language.'); - $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('user_id')->value, 'The entity author defaults to the default language.'); - $this->assertEqual($name, $entity->get('name')->value, 'The entity name can be retrieved without specifying a language.'); - $this->assertEqual($uid, $entity->get('user_id')->value, 'The entity author can be retrieved without specifying a language.'); - - // Create property translations. - $properties = array(); - $default_langcode = $langcode; - foreach ($this->langcodes as $langcode) { - if ($langcode != $default_langcode) { - $properties[$langcode] = array( - 'name' => array(0 => $this->randomName()), - 'user_id' => array(0 => mt_rand(0, 127)), - ); + // Test all entity variations with data table support. + foreach (_entity_test_multilingual_entity_types() as $entity_type) { + + $name = $this->randomName(); + $uid = mt_rand(0, 127); + $langcode = $this->langcodes[0]; + + // Create a language neutral entity and check that properties are stored + // as language neutral. + $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid)); + $entity->save(); + $entity = entity_load($entity_type, $entity->id()); + $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, $entity_type . ': Entity created as language neutral.'); + $this->assertEqual($name, $entity->getTranslation(LANGUAGE_DEFAULT)->get('name')->value, $entity_type . ': The entity name has been correctly stored as language neutral.'); + $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_DEFAULT)->get('user_id')->value, $entity_type . ': The entity author has been correctly stored as language neutral.'); + // As fields, translatable properties should ignore the given langcode and + // use neutral language if the entity is not translatable. + $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, $entity_type . ': The entity name defaults to neutral language.'); + $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, $entity_type . ': The entity author defaults to neutral language.'); + $this->assertEqual($name, $entity->get('name')->value, $entity_type . ': The entity name can be retrieved without specifying a language.'); + $this->assertEqual($uid, $entity->get('user_id')->value, $entity_type . ': The entity author can be retrieved without specifying a language.'); + + // Create a language-aware entity and check that properties are stored + // as language-aware. + $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode)); + $entity->save(); + $entity = entity_load($entity_type, $entity->id()); + $this->assertEqual($entity->language()->langcode, $langcode, $entity_type . ': Entity created as language specific.'); + $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, $entity_type . ': The entity name has been correctly stored as a language-aware property.'); + $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, $entity_type . ': The entity author has been correctly stored as a language-aware property.'); + // Translatable properties on a translatable entity should use default + // language if LANGUAGE_NOT_SPECIFIED is passed. + $this->assertEqual($name, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('name')->value, $entity_type . ': The entity name defaults to the default language.'); + $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('user_id')->value, $entity_type . ': The entity author defaults to the default language.'); + $this->assertEqual($name, $entity->get('name')->value, $entity_type . ': The entity name can be retrieved without specifying a language.'); + $this->assertEqual($uid, $entity->get('user_id')->value, $entity_type . ': The entity author can be retrieved without specifying a language.'); + + // Create property translations. + $properties = array(); + $default_langcode = $langcode; + foreach ($this->langcodes as $langcode) { + if ($langcode != $default_langcode) { + $properties[$langcode] = array( + 'name' => array(0 => $this->randomName()), + 'user_id' => array(0 => mt_rand(0, 127)), + ); + } + else { + $properties[$langcode] = array( + 'name' => array(0 => $name), + 'user_id' => array(0 => $uid), + ); + } + $entity->getTranslation($langcode)->setPropertyValues($properties[$langcode]); } - else { - $properties[$langcode] = array( - 'name' => array(0 => $name), - 'user_id' => array(0 => $uid), + $entity->save(); + + // Check that property translation were correctly stored. + $entity = entity_load($entity_type, $entity->id()); + foreach ($this->langcodes as $langcode) { + $args = array( + '%entity_type' => $entity_type, + '%langcode' => $langcode, ); + $this->assertEqual($properties[$langcode]['name'][0], $entity->getTranslation($langcode)->get('name')->value, format_string('%entity_type: The entity name has been correctly stored for language %langcode.', $args)); + $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->value, format_string('%entity_type: The entity author has been correctly stored for language %langcode.', $args)); } - $entity->getTranslation($langcode)->setPropertyValues($properties[$langcode]); - } - $entity->save(); - - // Check that property translation were correctly stored. - $entity = entity_test_load($entity->id()); - foreach ($this->langcodes as $langcode) { - $args = array('%langcode' => $langcode); - $this->assertEqual($properties[$langcode]['name'][0], $entity->getTranslation($langcode)->get('name')->value, format_string('The entity name has been correctly stored for language %langcode.', $args)); - $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->value, format_string('The entity author has been correctly stored for language %langcode.', $args)); - } - // Test query conditions (cache is reset at each call). - $translated_id = $entity->id(); - // Create an additional entity with only the uid set. The uid for the - // original language is the same of one used for a translation. - $langcode = $this->langcodes[1]; - entity_create('entity_test', array( - 'user_id' => $properties[$langcode]['user_id'], - 'name' => 'some name', - ))->save(); - - $entities = entity_test_load_multiple(); - $this->assertEqual(count($entities), 3, 'Three entities were created.'); - $entities = entity_test_load_multiple(array($translated_id)); - $this->assertEqual(count($entities), 1, 'One entity correctly loaded by id.'); - $entities = entity_load_multiple_by_properties('entity_test', array('name' => $name)); - $this->assertEqual(count($entities), 2, 'Two entities correctly loaded by name.'); - // @todo The default language condition should go away in favor of an - // explicit parameter. - $entities = entity_load_multiple_by_properties('entity_test', array('name' => $properties[$langcode]['name'][0], 'default_langcode' => 0)); - $this->assertEqual(count($entities), 1, 'One entity correctly loaded by name translation.'); - $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $default_langcode, 'name' => $name)); - $this->assertEqual(count($entities), 1, 'One entity correctly loaded by name and language.'); - - $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0])); - $this->assertEqual(count($entities), 0, 'No entity loaded by name translation specifying the translation language.'); - $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0], 'default_langcode' => 0)); - $this->assertEqual(count($entities), 1, 'One entity loaded by name translation and language specifying to look for translations.'); - $entities = entity_load_multiple_by_properties('entity_test', array('user_id' => $properties[$langcode]['user_id'][0], 'default_langcode' => NULL)); - $this->assertEqual(count($entities), 2, 'Two entities loaded by uid without caring about property translatability.'); - - // Test property conditions and orders with multiple languages in the same - // query. - $query = entity_query('entity_test'); - $group = $query->andConditionGroup() - ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) - ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); - $result = $query - ->condition($group) - ->condition('name', $properties[$langcode]['name'], '=', $langcode) - ->execute(); - $this->assertEqual(count($result), 1, 'One entity loaded by name and uid using different language meta conditions.'); - - // Test mixed property and field conditions. - $entity = entity_load('entity_test', reset($result), TRUE); - $field_value = $this->randomString(); - $entity->getTranslation($langcode)->set($this->field_name, array(array('value' => $field_value))); - $entity->save(); - $query = entity_query('entity_test'); - $default_langcode_group = $query->andConditionGroup() - ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) - ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); - $langcode_group = $query->andConditionGroup() - ->condition('name', $properties[$langcode]['name'], '=', $langcode) - ->condition("$this->field_name.value", $field_value, '=', $langcode); - $result = $query - ->condition('langcode', $default_langcode) - ->condition($default_langcode_group) - ->condition($langcode_group) - ->execute(); - $this->assertEqual(count($result), 1, 'One entity loaded by name, uid and field value using different language meta conditions.'); + // Test query conditions (cache is reset at each call). + $translated_id = $entity->id(); + // Create an additional entity with only the uid set. The uid for the + // original language is the same of one used for a translation. + $langcode = $this->langcodes[1]; + entity_create($entity_type, array( + 'user_id' => $properties[$langcode]['user_id'], + 'name' => 'some name', + ))->save(); + + $entities = entity_load_multiple($entity_type); + $this->assertEqual(count($entities), 3, $entity_type . ': Three entities were created.'); + $entities = entity_load_multiple($entity_type, array($translated_id)); + $this->assertEqual(count($entities), 1, $entity_type . ': One entity correctly loaded by id.'); + $entities = entity_load_multiple_by_properties($entity_type, array('name' => $name)); + $this->assertEqual(count($entities), 2, $entity_type . ': Two entities correctly loaded by name.'); + // @todo The default language condition should go away in favor of an + // explicit parameter. + $entities = entity_load_multiple_by_properties($entity_type, array('name' => $properties[$langcode]['name'][0], 'default_langcode' => 0)); + $this->assertEqual(count($entities), 1, $entity_type . ': One entity correctly loaded by name translation.'); + $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $default_langcode, 'name' => $name)); + $this->assertEqual(count($entities), 1, $entity_type . ': One entity correctly loaded by name and language.'); + + $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0])); + $this->assertEqual(count($entities), 0, $entity_type . ': No entity loaded by name translation specifying the translation language.'); + $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0], 'default_langcode' => 0)); + $this->assertEqual(count($entities), 1, $entity_type . ': One entity loaded by name translation and language specifying to look for translations.'); + $entities = entity_load_multiple_by_properties($entity_type, array('user_id' => $properties[$langcode]['user_id'][0], 'default_langcode' => NULL)); + $this->assertEqual(count($entities), 2, $entity_type . ': Two entities loaded by uid without caring about property translatability.'); + + // Test property conditions and orders with multiple languages in the same + // query. + $query = entity_query($entity_type); + $group = $query->andConditionGroup() + ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) + ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); + $result = $query + ->condition($group) + ->condition('name', $properties[$langcode]['name'], '=', $langcode) + ->execute(); + $this->assertEqual(count($result), 1, $entity_type . ': One entity loaded by name and uid using different language meta conditions.'); + + // Test mixed property and field conditions. + $entity = entity_load($entity_type, reset($result), TRUE); + $field_value = $this->randomString(); + $entity->getTranslation($langcode)->set($this->field_name, array(array('value' => $field_value))); + $entity->save(); + $query = entity_query($entity_type); + $default_langcode_group = $query->andConditionGroup() + ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) + ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); + $langcode_group = $query->andConditionGroup() + ->condition('name', $properties[$langcode]['name'], '=', $langcode) + ->condition("$this->field_name.value", $field_value, '=', $langcode); + $result = $query + ->condition('langcode', $default_langcode) + ->condition($default_langcode_group) + ->condition($langcode_group) + ->execute(); + $this->assertEqual(count($result), 1, $entity_type . ': One entity loaded by name, uid and field value using different language meta conditions.'); + } } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php index cb2f7f3..442396d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php @@ -34,57 +34,60 @@ public static function getInfo() { * Tests UUID generation in entity CRUD operations. */ function testCRUD() { - // Verify that no UUID is auto-generated when passing one for creation. - $uuid_service = new Uuid(); - $uuid = $uuid_service->generate(); - $custom_entity = entity_create('entity_test', array( - 'name' => $this->randomName(), - 'uuid' => $uuid, - )); - $this->assertIdentical($custom_entity->uuid(), $uuid); - // Save this entity, so we have more than one later. - $custom_entity->save(); + // All entity variations have to have the same results. + foreach (_entity_test_entity_types() as $entity_type) { + // Verify that no UUID is auto-generated when passing one for creation. + $uuid_service = new Uuid(); + $uuid = $uuid_service->generate(); + $custom_entity = entity_create($entity_type, array( + 'name' => $this->randomName(), + 'uuid' => $uuid, + )); + $this->assertIdentical($custom_entity->uuid(), $uuid); + // Save this entity, so we have more than one later. + $custom_entity->save(); - // Verify that a new UUID is generated upon creating an entity. - $entity = entity_create('entity_test', array('name' => $this->randomName())); - $uuid = $entity->uuid(); - $this->assertTrue($uuid); + // Verify that a new UUID is generated upon creating an entity. + $entity = entity_create($entity_type, array('name' => $this->randomName())); + $uuid = $entity->uuid(); + $this->assertTrue($uuid); - // Verify that the new UUID is different. - $this->assertNotEqual($custom_entity->uuid(), $uuid); + // Verify that the new UUID is different. + $this->assertNotEqual($custom_entity->uuid(), $uuid); - // Verify that the UUID is retained upon saving. - $entity->save(); - $this->assertIdentical($entity->uuid(), $uuid); + // Verify that the UUID is retained upon saving. + $entity->save(); + $this->assertIdentical($entity->uuid(), $uuid); - // Verify that the UUID is retained upon loading. - $entity_loaded = entity_test_load($entity->id(), TRUE); - $this->assertIdentical($entity_loaded->uuid(), $uuid); + // Verify that the UUID is retained upon loading. + $entity_loaded = entity_load($entity_type, $entity->id(), TRUE); + $this->assertIdentical($entity_loaded->uuid(), $uuid); - // Verify that entity_load_by_uuid() loads the same entity. - $entity_loaded_by_uuid = entity_load_by_uuid('entity_test', $uuid, TRUE); - $this->assertIdentical($entity_loaded_by_uuid->uuid(), $uuid); - $this->assertEqual($entity_loaded_by_uuid->id(), $entity_loaded->id()); + // Verify that entity_load_by_uuid() loads the same entity. + $entity_loaded_by_uuid = entity_load_by_uuid($entity_type, $uuid, TRUE); + $this->assertIdentical($entity_loaded_by_uuid->uuid(), $uuid); + $this->assertEqual($entity_loaded_by_uuid->id(), $entity_loaded->id()); - // Creating a duplicate needs to result in a new UUID. - $entity_duplicate = $entity->createDuplicate(); - foreach ($entity->getProperties() as $property => $value) { - switch($property) { - case 'uuid': - $this->assertNotNull($entity_duplicate->uuid()); - $this->assertNotNull($entity->uuid()); - $this->assertNotEqual($entity_duplicate->uuid(), $entity->uuid()); - break; - case 'id': - $this->assertNull($entity_duplicate->id()); - $this->assertNotNull($entity->id()); - $this->assertNotEqual($entity_duplicate->id(), $entity->id()); - break; - default: - $this->assertEqual($entity_duplicate->{$property}->value, $entity->{$property}->value); + // Creating a duplicate needs to result in a new UUID. + $entity_duplicate = $entity->createDuplicate(); + foreach ($entity->getProperties() as $property => $value) { + switch($property) { + case 'uuid': + $this->assertNotNull($entity_duplicate->uuid()); + $this->assertNotNull($entity->uuid()); + $this->assertNotEqual($entity_duplicate->uuid(), $entity->uuid()); + break; + case 'id': + $this->assertNull($entity_duplicate->id()); + $this->assertNotNull($entity->id()); + $this->assertNotEqual($entity_duplicate->id(), $entity->id()); + break; + default: + $this->assertEqual($entity_duplicate->{$property}->value, $entity->{$property}->value); + } } + $entity_duplicate->save(); + $this->assertNotEqual($entity->id(), $entity_duplicate->id()); } - $entity_duplicate->save(); - $this->assertNotEqual($entity->id(), $entity_duplicate->id()); } } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.install b/core/modules/system/tests/modules/entity_test/entity_test.install index 617986a..8fed8b2 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.install +++ b/core/modules/system/tests/modules/entity_test/entity_test.install @@ -18,23 +18,32 @@ function entity_test_install() { ); field_create_field($field); - $instance = array( - 'entity_type' => 'entity_test', - 'field_name' => 'field_test_text', - 'bundle' => 'entity_test', - 'label' => 'Test text-field', - 'widget' => array( - 'type' => 'text_textfield', - 'weight' => 0, - ), + $entity_types = array( + 'entity_test', + 'entity_test_rev', + 'entity_test_mul', + 'entity_test_mulrev', ); - field_create_instance($instance); + foreach ($entity_types as $entity_type) { + $instance = array( + 'entity_type' => $entity_type, + 'field_name' => 'field_test_text', + 'bundle' => $entity_type, + 'label' => 'Test text-field', + 'widget' => array( + 'type' => 'text_textfield', + 'weight' => 0, + ), + ); + field_create_instance($instance); + } } /** * Implements hook_schema(). */ function entity_test_schema() { + // Schema for simple entity. $schema['entity_test'] = array( 'description' => 'Stores entity_test items.', 'fields' => array( @@ -43,8 +52,51 @@ function entity_test_schema() { 'not null' => TRUE, 'description' => 'Primary Key: Unique entity-test item ID.', ), + 'uuid' => array( + 'description' => 'Unique Key: Universally unique identifier for this entity.', + 'type' => 'varchar', + 'length' => 128, + 'not null' => FALSE, + ), + 'langcode' => array( + 'description' => 'The {language}.langcode of the original variant of this test entity.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + 'name' => array( + 'description' => 'The name of the test entity.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + 'user_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The {users}.uid of the associated user.", + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'uuid' => array('uuid'), + ), + ); + + // Schema for entity with revisions. + $schema['entity_test_rev'] = array( + 'description' => 'Stores entity_test_rev items.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique entity-test item ID.', + ), 'revision_id' => array( - 'description' => 'The current {entity_test_property_revision}.revision_id version identifier.', + 'description' => 'The current {entity_test_rev_property_revision}.revision_id version identifier.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -63,23 +115,187 @@ function entity_test_schema() { 'not null' => TRUE, 'default' => '', ), + 'name' => array( + 'description' => 'The name of the test entity.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), ), 'primary key' => array('id'), 'unique keys' => array( 'uuid' => array('uuid'), ), ); - $schema['entity_test_property_data'] = array( - 'description' => 'Stores entity_test item properties.', + $schema['entity_test_rev_revision'] = array( + 'description' => 'Stores entity_test_rev item property revisions.', 'fields' => array( 'id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, - 'description' => 'The {entity_test}.id of the test entity.', + 'description' => 'The {entity_test_rev}.id of the test entity.', ), 'revision_id' => array( - 'description' => 'The current {entity_test_property_revision}.revision_id version identifier.', + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The primary identifier for this version.', + ), + 'langcode' => array( + 'description' => 'The {language}.langcode of this variant of this test entity.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + 'name' => array( + 'description' => 'The name of the test entity.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + 'user_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The {users}.uid of the associated user.", + ), + ), + 'indexes' => array( + 'user_id' => array('user_id'), + ), + 'foreign keys' => array( + 'user_id' => array('users' => 'uid'), + 'id' => array('entity_test_rev' => 'id'), + ), + 'primary key' => array('revision_id', 'id', 'langcode'), + ); + + // Schema for entity with data table. + $schema['entity_test_mul'] = array( + 'description' => 'Stores entity_test_mul items.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique entity-test item ID.', + ), + 'uuid' => array( + 'description' => 'Unique Key: Universally unique identifier for this entity.', + 'type' => 'varchar', + 'length' => 128, + 'not null' => FALSE, + ), + 'langcode' => array( + 'description' => 'The {language}.langcode of the original variant of this test entity.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'uuid' => array('uuid'), + ), + ); + $schema['entity_test_mul_property_data'] = array( + 'description' => 'Stores entity_test_mul item properties.', + 'fields' => array( + 'id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The {entity_test_mul}.id of the test entity.', + ), + 'langcode' => array( + 'description' => 'The {language}.langcode of this variant of this test entity.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + 'default_langcode' => array( + 'description' => 'Boolean indicating whether the current variant is in the original entity language.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 1, + ), + 'name' => array( + 'description' => 'The name of the test entity.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + 'user_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => NULL, + 'description' => "The {users}.uid of the associated user.", + ), + ), + 'indexes' => array( + 'user_id' => array('user_id'), + ), + 'foreign keys' => array( + 'user_id' => array('users' => 'uid'), + 'id' => array('entity_test_mul' => 'id'), + ), + 'primary key' => array('id', 'langcode'), + ); + + // Schema for entity with data table and revisions. + $schema['entity_test_mulrev'] = array( + 'description' => 'Stores entity_test_mulrev items.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique entity-test item ID.', + ), + 'revision_id' => array( + 'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'uuid' => array( + 'description' => 'Unique Key: Universally unique identifier for this entity.', + 'type' => 'varchar', + 'length' => 128, + 'not null' => FALSE, + ), + 'langcode' => array( + 'description' => 'The {language}.langcode of the original variant of this test entity.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'uuid' => array('uuid'), + ), + ); + $schema['entity_test_mulrev_property_data'] = array( + 'description' => 'Stores entity_test_mulrev item properties.', + 'fields' => array( + 'id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The {entity_test_mulrev}.id of the test entity.', + ), + 'revision_id' => array( + 'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -118,18 +334,18 @@ function entity_test_schema() { ), 'foreign keys' => array( 'user_id' => array('users' => 'uid'), - 'id' => array('entity_test' => 'id'), + 'id' => array('entity_test_mulrev' => 'id'), ), 'primary key' => array('id', 'langcode'), ); - $schema['entity_test_property_revision'] = array( - 'description' => 'Stores entity_test item property revisions.', + $schema['entity_test_mulrev_property_revision'] = array( + 'description' => 'Stores entity_test_mulrev item property revisions.', 'fields' => array( 'id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, - 'description' => 'The {entity_test}.id of the test entity.', + 'description' => 'The {entity_test_mulrev}.id of the test entity.', ), 'revision_id' => array( 'type' => 'serial', @@ -170,9 +386,10 @@ function entity_test_schema() { ), 'foreign keys' => array( 'user_id' => array('users' => 'uid'), - 'id' => array('entity_test' => 'id'), + 'id' => array('entity_test_mulrev' => 'id'), ), 'primary key' => array('revision_id', 'id', 'langcode'), ); + return $schema; } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 403c1b9..54d1ac9 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -2,11 +2,54 @@ /** * @file - * Test module for the entity API providing an entity type for testing. + * Test module for the entity API providing several entity types for testing. */ use Drupal\entity_test\Plugin\Core\Entity\EntityTest; +use Drupal\entity_test\Plugin\Core\Entity\EntityTestRev; +use Drupal\entity_test\Plugin\Core\Entity\EntityTestMul; +use Drupal\entity_test\Plugin\Core\Entity\EntityTestMulRev; +/** + * Returns the a list of entity types to deal with. + * + * @return array + * List with entity_types. + */ +function _entity_test_entity_types() { + return array( + 'entity_test' => 'entity_test', + 'entity_test_rev' => 'entity_test_rev', + 'entity_test_mul' => 'entity_test_mul', + 'entity_test_mulrev' => 'entity_test_mulrev', + ); +} + +/** + * Returns the a list of entity types that support revisions. + * + * @return array + * List with entity_types. + */ +function _entity_test_revisionable_entity_types() { + return array( + 'entity_test_rev' => 'entity_test_rev', + 'entity_test_mulrev' => 'entity_test_mulrev', + ); +} + +/** + * Returns the a list of entity types that have a dedicated data table. + * + * @return array + * List with entity_types. + */ +function _entity_test_multilingual_entity_types() { + return array( + 'entity_test_mul' => 'entity_test_mul', + 'entity_test_mulrev' => 'entity_test_mulrev', + ); +} /** * Implements hook_entity_info_alter(). @@ -14,7 +57,9 @@ function entity_test_entity_info_alter(&$info) { // Optionally specify a translation handler for testing translations. if (variable_get('entity_test_translation')) { - $info['entity_test']['translation']['entity_test'] = TRUE; + foreach(_entity_test_entity_types() as $entity_type) { + $info[$entity_type]['translation'][$entity_type] = TRUE; + } } // Optionally unset the access controller to test the fallback. if (state()->get('entity_test.default_access_controller')) { @@ -47,30 +92,41 @@ function entity_test_permission() { function entity_test_menu() { $items = array(); - $items['entity-test/add'] = array( - 'title' => 'Add an entity_test', - 'page callback' => 'entity_test_add', - 'access arguments' => array('administer entity_test content'), - 'type' => MENU_NORMAL_ITEM, - ); + foreach(_entity_test_entity_types() as $entity_type) { + $entity_type_path = str_replace('_', '-', $entity_type); + $items[$entity_type_path . '/add'] = array( + 'title' => 'Add an ' . $entity_type, + 'page callback' => $entity_type . '_add', + 'access arguments' => array('administer entity_test content'), + 'type' => MENU_NORMAL_ITEM, + ); - $items['entity-test/manage/%entity_test'] = array( - 'title' => 'Edit test entity', - 'page callback' => 'entity_test_edit', - 'page arguments' => array(2), - 'access arguments' => array('administer entity_test content'), - 'type' => MENU_NORMAL_ITEM, - ); + $items[$entity_type_path . '/manage/%' . $entity_type] = array( + 'title' => 'Edit ' . $entity_type, + 'page callback' => $entity_type . '_edit', + 'page arguments' => array(2), + 'access arguments' => array('administer entity_test content'), + 'type' => MENU_NORMAL_ITEM, + ); - $items['entity-test/manage/%entity_test/edit'] = array( - 'title' => 'Edit', - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); + $items[$entity_type_path . '/manage/%' . $entity_type . '/edit'] = array( + 'title' => 'Edit', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + } return $items; } /** + * Implements hook_form_BASE_FORM_ID_alter(). + */ +function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) { + $langcode = $form_state['controller']->getFormLangcode($form_state); + variable_set('entity_form_langcode', $langcode); +} + +/** * Menu callback: displays the 'Add new entity_test' form. * * @return array @@ -87,7 +143,7 @@ function entity_test_add() { /** * Menu callback: displays the 'Edit existing entity_test' form. * - * @param array $entity + * @param EntityTest $entity * The entity to be edited. * * @return array @@ -141,9 +197,211 @@ function entity_test_delete_multiple(array $ids) { } /** - * Implements hook_form_BASE_FORM_ID_alter(). + * Menu callback: displays the 'Add new entity_test_rev' form. + * + * @return array + * The processed form for a new entity_test_rev. + * + * @see entity_test_menu() */ -function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) { - $langcode = $form_state['controller']->getFormLangcode($form_state); - variable_set('entity_form_langcode', $langcode); +function entity_test_rev_add() { + drupal_set_title(t('Create an entity_test_rev')); + $entity = entity_create('entity_test_rev', array()); + return entity_get_form($entity); +} + +/** + * Menu callback: displays the 'Edit existing entity_test_rev' form. + * + * @param EntityTestRev $entity + * The entity to be edited. + * + * @return array + * The processed form for the edited entity_test_rev. + * + * @see entity_test_menu() + */ +function entity_test_rev_edit(EntityTestRev $entity) { + drupal_set_title($entity->label(), PASS_THROUGH); + return entity_get_form($entity); +} + +/** + * Loads a test entity. + * + * @param int $id + * A test entity ID. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return Drupal\entity_test\Plugin\Core\Entity\EntityTest + * The loaded entity object, or FALSE if the entity cannot be loaded. + */ +function entity_test_rev_load($id, $reset = FALSE) { + return entity_load('entity_test_rev', $id, $reset); +} + +/** + * Loads multiple test entities based on certain conditions. + * + * @param array $ids + * (optional) An array of entity IDs. If omitted, all entities are loaded. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return array + * An array of test entity objects, indexed by ID. + */ +function entity_test_rev_load_multiple(array $ids = NULL, $reset = FALSE) { + return entity_load_multiple('entity_test_rev', $ids, $reset); +} + +/** + * Deletes multiple test entities. + * + * @param $ids + * An array of test entity IDs. + */ +function entity_test_rev_delete_multiple(array $ids) { + entity_delete_multiple('entity_test_rev', $ids); +} + +/** + * Menu callback: displays the 'Add new entity_test_mul' form. + * + * @return array + * The processed form for a new entity_test_mul. + * + * @see entity_test_menu() + */ +function entity_test_mul_add() { + drupal_set_title(t('Create an entity_test_mul')); + $entity = entity_create('entity_test_mul', array()); + return entity_get_form($entity); +} + +/** + * Menu callback: displays the 'Edit existing entity_test_mul' form. + * + * @param EntityTestMul $entity + * The entity to be edited. + * + * @return array + * The processed form for the edited entity_test_mul. + * + * @see entity_test_menu() + */ +function entity_test_mul_edit(EntityTestMul $entity) { + drupal_set_title($entity->label(), PASS_THROUGH); + return entity_get_form($entity); +} + +/** + * Loads a test entity. + * + * @param int $id + * A test entity ID. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return Drupal\entity_test\Plugin\Core\Entity\EntityTest + * The loaded entity object, or FALSE if the entity cannot be loaded. + */ +function entity_test_mul_load($id, $reset = FALSE) { + return entity_load('entity_test_mul', $id, $reset); +} + +/** + * Loads multiple test entities based on certain conditions. + * + * @param array $ids + * (optional) An array of entity IDs. If omitted, all entities are loaded. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return array + * An array of test entity objects, indexed by ID. + */ +function entity_test_mul_load_multiple(array $ids = NULL, $reset = FALSE) { + return entity_load_multiple('entity_test_mul', $ids, $reset); +} + +/** + * Deletes multiple test entities. + * + * @param $ids + * An array of test entity IDs. + */ +function entity_test_mul_delete_multiple(array $ids) { + entity_delete_multiple('entity_test_mul', $ids); +} + +/** + * Menu callback: displays the 'Add new entity_test_mulrev' form. + * + * @return array + * The processed form for a new entity_test_mulrev. + * + * @see entity_test_menu() + */ +function entity_test_mulrev_add() { + drupal_set_title(t('Create an entity_test_mulrev')); + $entity = entity_create('entity_test_mulrev', array()); + return entity_get_form($entity); +} + +/** + * Menu callback: displays the 'Edit existing entity_test_mulrev' form. + * + * @param EntityTestMulRev $entity + * The entity to be edited. + * + * @return array + * The processed form for the edited entity_test_mulrev. + * + * @see entity_test_menu() + */ +function entity_test_mulrev_edit(EntityTestMulRev $entity) { + drupal_set_title($entity->label(), PASS_THROUGH); + return entity_get_form($entity); +} + +/** + * Loads a test entity. + * + * @param int $id + * A test entity ID. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return Drupal\entity_test\Plugin\Core\Entity\EntityTest + * The loaded entity object, or FALSE if the entity cannot be loaded. + */ +function entity_test_mulrev_load($id, $reset = FALSE) { + return entity_load('entity_test_mulrev', $id, $reset); +} + +/** + * Loads multiple test entities based on certain conditions. + * + * @param array $ids + * (optional) An array of entity IDs. If omitted, all entities are loaded. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return array + * An array of test entity objects, indexed by ID. + */ +function entity_test_mulrev_load_multiple(array $ids = NULL, $reset = FALSE) { + return entity_load_multiple('entity_test_mulrev', $ids, $reset); +} + +/** + * Deletes multiple test entities. + * + * @param $ids + * An array of test entity IDs. + */ +function entity_test_mulrev_delete_multiple(array $ids) { + entity_delete_multiple('entity_test_mulrev', $ids); } diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulFormController.php new file mode 100644 index 0000000..90f438b --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulFormController.php @@ -0,0 +1,86 @@ +getFormLangcode($form_state); + $translation = $entity->getTranslation($langcode); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#default_value' => $translation->name->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['user_id'] = array( + '#type' => 'textfield', + '#title' => 'UID', + '#default_value' => $translation->user_id->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['langcode'] = array( + '#title' => t('Language'), + '#type' => 'language_select', + '#default_value' => $entity->language()->langcode, + '#languages' => LANGUAGE_ALL, + ); + + return $form; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $is_new = $entity->isNew(); + $entity->save(); + + $message = $is_new ? t('entity_test_mul @id has been created.', array('@id' => $entity->id())) : t('entity_test_mul @id has been updated.', array('@id' => $entity->id())); + drupal_set_message($message); + + if ($entity->id()) { + $form_state['redirect'] = 'entity-test-mul/manage/' . $entity->id() . '/edit'; + } + else { + // Error on save. + drupal_set_message(t('The entity could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + */ + public function delete(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $entity->delete(); + drupal_set_message(t('entity_test_mul @id has been deleted.', array('@id' => $entity->id()))); + $form_state['redirect'] = ''; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevFormController.php new file mode 100644 index 0000000..229f3ef --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevFormController.php @@ -0,0 +1,86 @@ +getFormLangcode($form_state); + $translation = $entity->getTranslation($langcode); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#default_value' => $translation->name->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['user_id'] = array( + '#type' => 'textfield', + '#title' => 'UID', + '#default_value' => $translation->user_id->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['langcode'] = array( + '#title' => t('Language'), + '#type' => 'language_select', + '#default_value' => $entity->language()->langcode, + '#languages' => LANGUAGE_ALL, + ); + + return $form; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $is_new = $entity->isNew(); + $entity->save(); + + $message = $is_new ? t('entity_test_mulrev @id has been created.', array('@id' => $entity->id())) : t('entity_test_mulrev @id has been updated.', array('@id' => $entity->id())); + drupal_set_message($message); + + if ($entity->id()) { + $form_state['redirect'] = 'entity-test-mul-rev/manage/' . $entity->id() . '/edit'; + } + else { + // Error on save. + drupal_set_message(t('The entity could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + */ + public function delete(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $entity->delete(); + drupal_set_message(t('entity_test_mulrev @id has been deleted.', array('@id' => $entity->id()))); + $form_state['redirect'] = ''; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php new file mode 100644 index 0000000..94dffc0 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php @@ -0,0 +1,69 @@ + t('ID'), + 'description' => t('The ID of the test entity.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['revision_id'] = array( + 'label' => t('ID'), + 'description' => t('The version id of the test entity.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['uuid'] = array( + 'label' => t('UUID'), + 'description' => t('The UUID of the test entity.'), + 'type' => 'string_field', + ); + $fields['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The language code of the test entity.'), + 'type' => 'language_field', + ); + $fields['default_langcode'] = array( + 'label' => t('Default language'), + 'description' => t('Flag to inditcate whether this is the default language.'), + 'type' => 'boolean_field', + ); + $fields['name'] = array( + 'label' => t('Name'), + 'description' => t('The name of the test entity.'), + 'type' => 'string_field', + 'translatable' => TRUE, + ); + $fields['user_id'] = array( + 'label' => t('User ID'), + 'description' => t('The ID of the associated user.'), + 'type' => 'entityreference_field', + 'settings' => array('entity type' => 'user'), + 'translatable' => TRUE, + ); + return $fields; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevTranslationController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevTranslationController.php new file mode 100644 index 0000000..57492ff --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevTranslationController.php @@ -0,0 +1,28 @@ +getTranslation($langcode); + foreach ($translation->getPropertyDefinitions() as $property_name => $langcode) { + $translation->$property_name = array(); + } + } + +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php new file mode 100644 index 0000000..7187c07 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php @@ -0,0 +1,63 @@ + t('ID'), + 'description' => t('The ID of the test entity.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['uuid'] = array( + 'label' => t('UUID'), + 'description' => t('The UUID of the test entity.'), + 'type' => 'string_field', + ); + $fields['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The language code of the test entity.'), + 'type' => 'language_field', + ); + $fields['default_langcode'] = array( + 'label' => t('Default language'), + 'description' => t('Flag to inditcate whether this is the default language.'), + 'type' => 'boolean_field', + ); + $fields['name'] = array( + 'label' => t('Name'), + 'description' => t('The name of the test entity.'), + 'type' => 'string_field', + 'translatable' => TRUE, + ); + $fields['user_id'] = array( + 'label' => t('User ID'), + 'description' => t('The ID of the associated user.'), + 'type' => 'entityreference_field', + 'settings' => array('entity type' => 'user'), + 'translatable' => TRUE, + ); + return $fields; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulTranslationController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulTranslationController.php new file mode 100644 index 0000000..2575515 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulTranslationController.php @@ -0,0 +1,28 @@ +getTranslation($langcode); + foreach ($translation->getPropertyDefinitions() as $property_name => $langcode) { + $translation->$property_name = array(); + } + } + +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevFormController.php new file mode 100644 index 0000000..d3ca781 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevFormController.php @@ -0,0 +1,86 @@ +getFormLangcode($form_state); + $translation = $entity->getTranslation($langcode); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#default_value' => $translation->name->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['user_id'] = array( + '#type' => 'textfield', + '#title' => 'UID', + '#default_value' => $translation->user_id->value, + '#size' => 60, + '#maxlength' => 128, + '#required' => TRUE, + '#weight' => -10, + ); + + $form['langcode'] = array( + '#title' => t('Language'), + '#type' => 'language_select', + '#default_value' => $entity->language()->langcode, + '#languages' => LANGUAGE_ALL, + ); + + return $form; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $is_new = $entity->isNew(); + $entity->save(); + + $message = $is_new ? t('entity_test_rev @id has been created.', array('@id' => $entity->id())) : t('entity_test_rev @id has been updated.', array('@id' => $entity->id())); + drupal_set_message($message); + + if ($entity->id()) { + $form_state['redirect'] = 'entity-test-rev/manage/' . $entity->id() . '/edit'; + } + else { + // Error on save. + drupal_set_message(t('The entity could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + */ + public function delete(array $form, array &$form_state) { + $entity = $this->getEntity($form_state); + $entity->delete(); + drupal_set_message(t('entity_test_rev @id has been deleted.', array('@id' => $entity->id()))); + $form_state['redirect'] = ''; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php new file mode 100644 index 0000000..89801a6 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php @@ -0,0 +1,64 @@ + t('ID'), + 'description' => t('The ID of the test entity.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['revision_id'] = array( + 'label' => t('ID'), + 'description' => t('The version id of the test entity.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['uuid'] = array( + 'label' => t('UUID'), + 'description' => t('The UUID of the test entity.'), + 'type' => 'string_field', + ); + $fields['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The language code of the test entity.'), + 'type' => 'language_field', + ); + $fields['name'] = array( + 'label' => t('Name'), + 'description' => t('The name of the test entity.'), + 'type' => 'string_field', + 'translatable' => TRUE, + ); + $fields['user_id'] = array( + 'label' => t('User ID'), + 'description' => t('The ID of the associated user.'), + 'type' => 'entityreference_field', + 'settings' => array('entity type' => 'user'), + 'translatable' => TRUE, + ); + return $fields; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevTranslationController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevTranslationController.php new file mode 100644 index 0000000..1108860 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevTranslationController.php @@ -0,0 +1,28 @@ +getTranslation($langcode); + foreach ($translation->getPropertyDefinitions() as $property_name => $langcode) { + $translation->$property_name = array(); + } + } + +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php index e3b45fa..246cb97 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php @@ -21,114 +21,6 @@ class EntityTestStorageController extends DatabaseStorageControllerNG { /** - * Overrides Drupal\Core\Entity\DatabaseStorageController::buildPropertyQuery(). - */ - protected function buildPropertyQuery(QueryInterface $entity_query, array $values) { - // @todo We should not be using a condition to specify whether conditions - // apply to the default language or not. We need to move this to a - // separate parameter during the following API refactoring. - // Default to the original entity language if not explicitly specified - // otherwise. - if (!array_key_exists('default_langcode', $values)) { - $values['default_langcode'] = 1; - } - // If the 'default_langcode' flag is esplicitly not set, we do not care - // whether the queried values are in the original entity language or not. - elseif ($values['default_langcode'] === NULL) { - unset($values['default_langcode']); - } - - parent::buildPropertyQuery($entity_query, $values); - } - - /** - * Maps from storage records to entity objects. - * - * @return array - * An array of entity objects implementing the EntityInterface. - */ - protected function mapFromStorageRecords(array $records, $load_revision = FALSE) { - $records = parent::mapFromStorageRecords($records, $load_revision); - - // Load data of translatable properties. - $this->attachPropertyData($records, $load_revision); - return $records; - } - - /** - * Attaches property data in all languages for translatable properties. - */ - protected function attachPropertyData(&$queried_entities, $load_revision = FALSE) { - $query = db_select('entity_test_property_data', 'data', array('fetch' => PDO::FETCH_ASSOC)) - ->fields('data') - ->condition('id', array_keys($queried_entities)) - ->orderBy('data.id'); - if ($load_revision) { - // Get revision id's. - $revision_ids = array(); - foreach ($queried_entities as $id => $entity) { - $revision_ids[] = $entity->get('revision_id')->value; - } - $query->condition('revision_id', $revision_ids); - } - $data = $query->execute(); - - foreach ($data as $values) { - $id = $values['id']; - // Field values in default language are stored with - // LANGUAGE_DEFAULT as key. - $langcode = empty($values['default_langcode']) ? $values['langcode'] : LANGUAGE_DEFAULT; - - $queried_entities[$id]->name[$langcode][0]['value'] = $values['name']; - $queried_entities[$id]->user_id[$langcode][0]['value'] = $values['user_id']; - } - } - - /** - * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave(). - * - * Stores values of translatable properties. - */ - protected function postSave(EntityInterface $entity, $update) { - $default_langcode = $entity->language()->langcode; - - // Delete and insert to handle removed values. - db_delete('entity_test_property_data') - ->condition('id', $entity->id()) - ->execute(); - - $query = db_insert('entity_test_property_data'); - - foreach ($entity->getTranslationLanguages() as $langcode => $language) { - $translation = $entity->getTranslation($langcode); - - $values = array( - 'id' => $entity->id(), - 'revision_id' => $entity->getRevisionId(), - 'langcode' => $langcode, - 'default_langcode' => intval($default_langcode == $langcode), - 'name' => $translation->name->value, - 'user_id' => $translation->user_id->value, - ); - - $query - ->fields(array_keys($values)) - ->values($values); - } - - $query->execute(); - } - - /** - * Overrides Drupal\Core\Entity\DatabaseStorageController::postDelete(). - */ - protected function postDelete($entities) { - db_delete('entity_test_property_data') - ->condition('id', array_keys($entities)) - ->execute(); - } - - /** * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions(). */ public function baseFieldDefinitions() { diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php index 9b4d368..2babb66 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php @@ -25,13 +25,10 @@ * }, * translation_controller_class = "Drupal\entity_test\EntityTestTranslationController", * base_table = "entity_test", - * data_table = "entity_test_property_data", - * revision_table = "entity_test_property_revision", * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", - * "revision" = "revision_id" * }, * menu_base_path = "entity-test/manage/%entity_test" * ) @@ -53,13 +50,6 @@ class EntityTest extends EntityNG { public $uuid; /** - * The entity revision id. - * - * @var \Drupal\Core\Entity\Field\FieldInterface - */ - public $revision_id; - - /** * The name of the test entity. * * @var \Drupal\Core\Entity\Field\FieldInterface @@ -81,9 +71,7 @@ public function __construct(array $values, $entity_type) { // We unset all defined properties, so magic getters apply. unset($this->id); - unset($this->langcode); unset($this->uuid); - unset($this->revision_id); unset($this->name); unset($this->user_id); } @@ -94,11 +82,4 @@ public function __construct(array $values, $entity_type) { public function label($langcode = LANGUAGE_DEFAULT) { return $this->getTranslation($langcode)->name->value; } - - /** - * Implements Drupal\Core\Entity\EntityInterface::getRevisionId(). - */ - public function getRevisionId() { - return $this->get('revision_id')->value; - } } diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php new file mode 100644 index 0000000..7a25821 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php @@ -0,0 +1,85 @@ +id); + unset($this->uuid); + unset($this->name); + unset($this->user_id); + } + + /** + * Overrides Drupal\entity\Entity::label(). + */ + public function label($langcode = LANGUAGE_DEFAULT) { + return $this->getTranslation($langcode)->name->value; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php new file mode 100644 index 0000000..5caba0a --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php @@ -0,0 +1,102 @@ +id); + unset($this->uuid); + unset($this->revision_id); + unset($this->name); + unset($this->user_id); + } + + /** + * Overrides Drupal\entity\Entity::label(). + */ + public function label($langcode = LANGUAGE_DEFAULT) { + return $this->getTranslation($langcode)->name->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::getRevisionId(). + */ + public function getRevisionId() { + return $this->get('revision_id')->value; + } +} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php new file mode 100644 index 0000000..76e477c --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php @@ -0,0 +1,101 @@ +id); + unset($this->uuid); + unset($this->revision_id); + unset($this->name); + unset($this->user_id); + } + + /** + * Overrides Drupal\entity\Entity::label(). + */ + public function label($langcode = LANGUAGE_DEFAULT) { + return $this->getTranslation($langcode)->name->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::getRevisionId(). + */ + public function getRevisionId() { + return $this->get('revision_id')->value; + } +} diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php index f66fcc3..2fbb509 100644 --- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php +++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php @@ -31,7 +31,8 @@ public static function getInfo() { * Overrides \Drupal\simpletest\WebTestBase::setUp(). */ function setUp() { - $this->entityType = 'entity_test'; + // Use the entity_test_mul as this has multilingual property support. + $this->entityType = 'entity_test_mul'; parent::setUp(); } diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php index eac0b7f..9e212c2 100644 --- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php +++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php @@ -220,8 +220,10 @@ function testTranslationUI() { $this->drupalPost($path, array(), t('Delete translation')); $this->drupalPost(NULL, array(), t('Delete')); $entity = entity_load($this->entityType, $entity->id(), TRUE); - $translations = $entity->getTranslationLanguages(); - $this->assertTrue(count($translations) == 2 && empty($translations[$enabled_langcode]), 'Translation successfully deleted.'); + if ($this->assertTrue(is_object($entity), 'Entity found')) { + $translations = $entity->getTranslationLanguages(); + $this->assertTrue(count($translations) == 2 && empty($translations[$enabled_langcode]), 'Translation successfully deleted.'); + } } /**