Issue #1277776 by fago, plach, Gábor Hojtsy, aspilicious, brantwynn: Add generic field/property getters/setters (with optional language support) for entities.
parent
05b0eb5b1f
commit
a86777338f
|
@ -92,6 +92,60 @@ interface EntityInterface {
|
|||
*/
|
||||
public function uri();
|
||||
|
||||
/**
|
||||
* Returns the default language of a language-specific entity.
|
||||
*
|
||||
* @return
|
||||
* The language object of the entity's default language, or FALSE if the
|
||||
* entity is not language-specific.
|
||||
*
|
||||
* @see EntityInterface::translations()
|
||||
*/
|
||||
public function language();
|
||||
|
||||
/**
|
||||
* Returns the languages the entity is translated to.
|
||||
*
|
||||
* @return
|
||||
* An array of language objects, keyed by language codes.
|
||||
*
|
||||
* @see EntityInterface::language()
|
||||
*/
|
||||
public function translations();
|
||||
|
||||
/**
|
||||
* Returns the value of an entity property.
|
||||
*
|
||||
* @param $property_name
|
||||
* The name of the property to return; e.g., 'title'.
|
||||
* @param $langcode
|
||||
* (optional) If the property is translatable, the language code of the
|
||||
* language that should be used for getting the property. If set to NULL,
|
||||
* the entity's default language is being used.
|
||||
*
|
||||
* @return
|
||||
* The property value, or NULL if it is not defined.
|
||||
*
|
||||
* @see EntityInterface::language()
|
||||
*/
|
||||
public function get($property_name, $langcode = NULL);
|
||||
|
||||
/**
|
||||
* Sets the value of an entity property.
|
||||
*
|
||||
* @param $property_name
|
||||
* The name of the property to set; e.g., 'title'.
|
||||
* @param $value
|
||||
* The value to set, or NULL to unset the property.
|
||||
* @param $langcode
|
||||
* (optional) If the property is translatable, the language code of the
|
||||
* language that should be used for getting the property. If set to
|
||||
* NULL, the entity's default language is being used.
|
||||
*
|
||||
* @see EntityInterface::language()
|
||||
*/
|
||||
public function set($property_name, $value, $langcode = NULL);
|
||||
|
||||
/**
|
||||
* Saves an entity permanently.
|
||||
*
|
||||
|
@ -138,6 +192,13 @@ interface EntityInterface {
|
|||
*/
|
||||
class Entity implements EntityInterface {
|
||||
|
||||
/**
|
||||
* The language code of the entity's default language.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $langcode = LANGUAGE_NOT_SPECIFIED;
|
||||
|
||||
/**
|
||||
* The entity type.
|
||||
*
|
||||
|
@ -246,6 +307,89 @@ class Entity implements EntityInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityInterface::language().
|
||||
*/
|
||||
public function language() {
|
||||
// @todo: Check for language.module instead, once Field API language
|
||||
// handling depends upon it too.
|
||||
return module_exists('locale') ? language_load($this->langcode) : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityInterface::translations().
|
||||
*/
|
||||
public function translations() {
|
||||
$languages = array();
|
||||
if ($this->entityInfo['fieldable'] && ($default_language = $this->language())) {
|
||||
// Go through translatable properties and determine all languages for
|
||||
// which translated values are available.
|
||||
foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) {
|
||||
$field = field_info_field($field_name);
|
||||
if (field_is_translatable($this->entityType, $field) && isset($this->$field_name)) {
|
||||
foreach ($this->$field_name as $langcode => $value) {
|
||||
$languages[$langcode] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the default language from the translations.
|
||||
unset($languages[$default_language->langcode]);
|
||||
$languages = array_intersect_key(language_list(), $languages);
|
||||
}
|
||||
return $languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityInterface::get().
|
||||
*/
|
||||
public function get($property_name, $langcode = NULL) {
|
||||
// Handle fields.
|
||||
if ($this->entityInfo['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) {
|
||||
$field = field_info_field($property_name);
|
||||
$langcode = $this->getFieldLangcode($field, $langcode);
|
||||
return isset($this->{$property_name}[$langcode]) ? $this->{$property_name}[$langcode] : NULL;
|
||||
}
|
||||
else {
|
||||
// Handle properties being not fields.
|
||||
// @todo: Add support for translatable properties being not fields.
|
||||
return isset($this->{$property_name}) ? $this->{$property_name} : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityInterface::set().
|
||||
*/
|
||||
public function set($property_name, $value, $langcode = NULL) {
|
||||
// Handle fields.
|
||||
if ($this->entityInfo['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) {
|
||||
$field = field_info_field($property_name);
|
||||
$langcode = $this->getFieldLangcode($field, $langcode);
|
||||
$this->{$property_name}[$langcode] = $value;
|
||||
}
|
||||
else {
|
||||
// Handle properties being not fields.
|
||||
// @todo: Add support for translatable properties being not fields.
|
||||
$this->{$property_name} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the language code to use for accessing a field value in a certain language.
|
||||
*/
|
||||
protected function getFieldLangcode($field, $langcode = NULL) {
|
||||
// Only apply the given langcode if the entity is language-specific.
|
||||
// Otherwise translatable fields are handled as non-translatable fields.
|
||||
if (field_is_translatable($this->entityType, $field) && ($default_language = $this->language())) {
|
||||
// For translatable fields the values in default language are stored using
|
||||
// the language code of the default language.
|
||||
return isset($langcode) ? $langcode : $default_language->langcode;
|
||||
}
|
||||
else {
|
||||
// Non-translatable fields always use LANGUAGE_NOT_SPECIFIED.
|
||||
return LANGUAGE_NOT_SPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements EntityInterface::save().
|
||||
*/
|
||||
|
|
|
@ -65,6 +65,138 @@ class EntityAPITestCase extends DrupalWebTestCase {
|
|||
$all = entity_test_load_multiple(FALSE);
|
||||
$this->assertTrue(empty($all), 'Deleted all entities.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Entity getters/setters.
|
||||
*/
|
||||
function testEntityGettersSetters() {
|
||||
$entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
|
||||
$this->assertNull($entity->get('uid'), 'Property is not set.');
|
||||
|
||||
$entity->set('uid', $GLOBALS['user']->uid);
|
||||
$this->assertEqual($entity->uid, $GLOBALS['user']->uid, 'Property has been set.');
|
||||
|
||||
$value = $entity->get('uid');
|
||||
$this->assertEqual($value, $entity->uid, 'Property has been retrieved.');
|
||||
|
||||
// Make sure setting/getting translations boils down to setting/getting the
|
||||
// regular value as the entity and property are not translatable.
|
||||
$entity->set('uid', NULL, 'en');
|
||||
$this->assertNull($entity->uid, 'Language neutral property has been set.');
|
||||
|
||||
$value = $entity->get('uid', 'en');
|
||||
$this->assertNull($value, 'Language neutral property has been retrieved.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity translation.
|
||||
*/
|
||||
class EntityTranslationTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Translation',
|
||||
'description' => 'Tests entity translation functionality.',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// Enable translations for the test entity type. We cannot use
|
||||
// variable_set() here as variables are cleared by parent::setUp();
|
||||
$GLOBALS['entity_test_translation'] = TRUE;
|
||||
parent::setUp('entity_test', 'language', 'locale');
|
||||
|
||||
// Create a translatable test field.
|
||||
$this->field_name = drupal_strtolower($this->randomName() . '_field_name');
|
||||
$field = array(
|
||||
'field_name' => $this->field_name,
|
||||
'type' => 'text',
|
||||
'cardinality' => 4,
|
||||
'translatable' => TRUE,
|
||||
);
|
||||
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 test languages.
|
||||
$this->langcodes = array();
|
||||
for ($i = 0; $i < 3; ++$i) {
|
||||
$language = (object) array(
|
||||
'langcode' => 'l' . $i,
|
||||
'name' => $this->randomString(),
|
||||
);
|
||||
$this->langcodes[$i] = $language->langcode;
|
||||
language_save($language);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests language related methods of the Entity class.
|
||||
*/
|
||||
function testEntityLanguageMethods() {
|
||||
$entity = entity_create('entity_test', array(
|
||||
'name' => 'test',
|
||||
'uid' => $GLOBALS['user']->uid,
|
||||
));
|
||||
$this->assertFalse($entity->language(), 'No entity language has been specified.');
|
||||
$this->assertFalse($entity->translations(), 'No translations are available');
|
||||
|
||||
// Set the value in default language.
|
||||
$entity->set($this->field_name, array(0 => array('value' => 'default value')));
|
||||
// Get the value.
|
||||
$value = $entity->get($this->field_name);
|
||||
$this->assertEqual($value, array(0 => array('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->set($this->field_name, array(0 => array('value' => 'default value2')), $this->langcodes[1]);
|
||||
$value = $entity->get($this->field_name);
|
||||
$this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value updated.');
|
||||
$this->assertFalse($entity->translations(), 'No translations are available');
|
||||
|
||||
// Test getting a field value using the default language for a not
|
||||
// language-specific entity.
|
||||
$value = $entity->get($this->field_name, $this->langcodes[1]);
|
||||
$this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value retrieved.');
|
||||
|
||||
// Now, make the entity language-specific by assigning a language and test
|
||||
// translating it.
|
||||
$entity->langcode = $this->langcodes[0];
|
||||
$entity->{$this->field_name} = array();
|
||||
$this->assertEqual($entity->language(), language_load($this->langcodes[0]), 'Entity language retrieved.');
|
||||
$this->assertFalse($entity->translations(), 'No translations are available');
|
||||
|
||||
// Set the value in default language.
|
||||
$entity->set($this->field_name, array(0 => array('value' => 'default value')));
|
||||
// Get the value.
|
||||
$value = $entity->get($this->field_name);
|
||||
$this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.');
|
||||
|
||||
// Set a translation.
|
||||
$entity->set($this->field_name, array(0 => array('value' => 'translation 1')), $this->langcodes[1]);
|
||||
$value = $entity->get($this->field_name, $this->langcodes[1]);
|
||||
$this->assertEqual($value, array(0 => array('value' => 'translation 1')), 'Translated value set.');
|
||||
// Make sure the untranslated value stays.
|
||||
$value = $entity->get($this->field_name);
|
||||
$this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value stays.');
|
||||
|
||||
$translations[$this->langcodes[1]] = language_load($this->langcodes[1]);
|
||||
$this->assertEqual($entity->translations(), $translations, 'Translations retrieved.');
|
||||
|
||||
// Try to get a not available translation.
|
||||
$value = $entity->get($this->field_name, $this->langcodes[2]);
|
||||
$this->assertNull($value, 'A translation that is not available is NULL.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,6 +57,13 @@ function entity_test_schema() {
|
|||
'default' => NULL,
|
||||
'description' => "The {users}.uid of the associated user.",
|
||||
),
|
||||
'langcode' => array(
|
||||
'description' => 'The {language}.langcode of the test entity.',
|
||||
'type' => 'varchar',
|
||||
'length' => 12,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'uid' => array('uid'),
|
||||
|
|
|
@ -9,19 +9,21 @@
|
|||
* Implements hook_entity_info().
|
||||
*/
|
||||
function entity_test_entity_info() {
|
||||
$return = array(
|
||||
'entity_test' => array(
|
||||
'label' => t('Test entity'),
|
||||
'entity class' => 'Entity',
|
||||
'controller class' => 'EntityDatabaseStorageController',
|
||||
'base table' => 'entity_test',
|
||||
'fieldable' => TRUE,
|
||||
'entity keys' => array(
|
||||
'id' => 'id',
|
||||
),
|
||||
$items['entity_test'] = array(
|
||||
'label' => t('Test entity'),
|
||||
'entity class' => 'Entity',
|
||||
'controller class' => 'EntityDatabaseStorageController',
|
||||
'base table' => 'entity_test',
|
||||
'fieldable' => TRUE,
|
||||
'entity keys' => array(
|
||||
'id' => 'id',
|
||||
),
|
||||
);
|
||||
return $return;
|
||||
// Optionally specify a translation handler for testing translations.
|
||||
if (!empty($GLOBALS['entity_test_translation'])) {
|
||||
$items['entity_test']['translation']['entity_test'] = TRUE;
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue