diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 1d2227883af2fc102e5a10ce6ebaa1a7828ffa64..fb75ee284103bc4e30a9e72e31156dedee3c9e81 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -184,7 +184,9 @@ public function get($property_name, $langcode = NULL) { $entity_info = $this->entityInfo(); if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) { $field = field_info_field($property_name); - $langcode = $this->getFieldLangcode($field, $langcode); + // Prevent getFieldLangcode() from throwing an exception in case a + // $langcode has been passed and it is invalid for the field. + $langcode = $this->getFieldLangcode($field, $langcode, FALSE); return isset($this->{$property_name}[$langcode]) ? $this->{$property_name}[$langcode] : NULL; } else { @@ -202,6 +204,7 @@ public function set($property_name, $value, $langcode = NULL) { $entity_info = $this->entityInfo(); if ($entity_info['fieldable'] && field_info_instance($this->entityType, $property_name, $this->bundle())) { $field = field_info_field($property_name); + // Throws an exception if the $langcode is invalid. $langcode = $this->getFieldLangcode($field, $langcode); $this->{$property_name}[$langcode] = $value; } @@ -213,9 +216,45 @@ public function set($property_name, $value, $langcode = NULL) { } /** - * Determines the language code to use for accessing a field value in a certain language. + * Determines the language code for accessing a field value. + * + * The effective language code to be used for a field varies: + * - If the entity is language-specific and the requested field is + * translatable, the entity's language code should be used to access the + * field value when no language is explicitly provided. + * - If the entity is not language-specific, LANGUAGE_NOT_SPECIFIED should be + * used to access all field values. + * - If a field's values are non-translatable (shared among all language + * versions of an entity), LANGUAGE_NOT_SPECIFIED should be used to access + * them. + * + * There cannot be valid field values if a field is not translatable and the + * requested langcode is not LANGUAGE_NOT_SPECIFIED. Therefore, this function + * throws an exception in that case (or returns NULL when $strict is FALSE). + * + * @param string $field + * Field the language code is being determined for. + * @param string|null $langcode + * (optional) The language code attempting to be applied to the field. + * Defaults to the entity language. + * @param bool $strict + * (optional) When $strict is TRUE, an exception is thrown if the field is + * not translatable and the langcode is not LANGUAGE_NOT_SPECIFIED. When + * $strict is FALSE, NULL is returned and no exception is thrown. For + * example, EntityInterface::set() passes TRUE, since it must not set field + * values for invalid langcodes. EntityInterface::get() passes FALSE to + * determine whether any field values exist for a specific langcode. + * Defaults to TRUE. + * + * @return string|null + * The langcode if appropriate, LANGUAGE_NOT_SPECIFIED for non-translatable + * fields, or NULL when an invalid langcode was used in non-strict mode. + * + * @throws \InvalidArgumentException + * Thrown in case a $langcode other than LANGUAGE_NOT_SPECIFIED is passed + * for a non-translatable field and $strict is TRUE. */ - protected function getFieldLangcode($field, $langcode = NULL) { + protected function getFieldLangcode($field, $langcode = NULL, $strict = TRUE) { // 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()) && !language_is_locked($this->langcode)) { @@ -224,9 +263,21 @@ protected function getFieldLangcode($field, $langcode = NULL) { return isset($langcode) ? $langcode : $default_language->langcode; } else { - // If there is a langcode defined for this field, just return it. Otherwise - // return LANGUAGE_NOT_SPECIFIED. - return (isset($this->langcode) ? $this->langcode : LANGUAGE_NOT_SPECIFIED); + // The field is not translatable, but the caller requested a specific + // langcode that does not exist. + if (isset($langcode) && $langcode !== LANGUAGE_NOT_SPECIFIED) { + if ($strict) { + throw new \InvalidArgumentException(format_string('Unable to resolve @langcode for non-translatable field @field_name. Use langcode LANGUAGE_NOT_SPECIFIED instead.', array( + '@field_name' => $field['field_name'], + '@langcode' => $langcode, + ))); + } + else { + return NULL; + } + } + // The field is not translatable and no $langcode was specified. + return LANGUAGE_NOT_SPECIFIED; } } 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 805d52c17a80a57b1f52ef288b46064d5a7a41ee..e5e5e2e2125a7374129e81108ab9fe05b32887db 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php @@ -87,18 +87,22 @@ function testEntityLanguageMethods() { $value = $entity->get($this->field_name); $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.'); + $message = "An exception is thrown when trying to set a field with an invalid language"; + // 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'); + // language-specific it will throw an exception. + try { + $entity->set($this->field_name, array(0 => array('value' => 'default value2')), $this->langcodes[1]); + $this->fail($message); + } + catch (Exception $e) { + $this->assertTrue($e instanceof InvalidArgumentException, $message); + } - // Test getting a field value using the default language for a not + // Test getting a field value using a specific 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.'); + $this->assertNull($value, 'Returned NULL for getter with invalid language.'); // Now, make the entity language-specific by assigning a language and test // translating it.