Commit c4d64f9d authored by malberts's avatar malberts Committed by Joel Muzzerall
Browse files

Issue #1344672 by malberts and many others: Field Collection: Field...

Issue #1344672 by malberts and many others: Field Collection: Field translation (entity_translation) support
parent 14076efc
Field collection
-----------------
Provides a field collection field, to which any number of fields can be attached.
......@@ -28,9 +27,20 @@ field collection item may also be viewed and edited separately.
module might provide such widgets itself too.
Restrictions
-------------
Using field collection with entity translation
-----------------------------------------------
* Field collection items must be selected as a translatable entity type at
Admin -> Config -> Regional -> Entity Translation.
* The common use case is to leave the field collection field untranslatable
and set the necessary fields inside it to translatable. There is currently
a known issue where a host can not be translated unless it has at least
one other field that is translatable, even if some fields inside one of
its field collections are translatable.
* As of now, the field collection field does not properly respect field
translation. Thus, for now it is suggested to only use the field for
entities that are not translatable.
* The alternate use case is to make the field collection field in the host
translatable. If this is done it does not matter whether the inner fields
are set to translatable or not, they will all be translatable as every
language for the host will have a completely separate copy of the field
collection item(s).
......@@ -231,8 +231,8 @@ class FieldCollectionItemEntity extends Entity {
if ($current_id == $recieved_id) {
$this->hostEntity = $entity;
$delta = $this->delta();
if (isset($entity->{$this->field_name}[$this->langcode][$delta]['entity'])) {
$entity->{$this->field_name}[$this->langcode][$delta]['entity'] = $this;
if (isset($entity->{$this->field_name}[$this->langcode()][$delta]['entity'])) {
$entity->{$this->field_name}[$this->langcode()][$delta]['entity'] = $this;
}
}
else {
......@@ -326,14 +326,34 @@ class FieldCollectionItemEntity extends Entity {
public function delta() {
if (($entity = $this->hostEntity()) && isset($entity->{$this->field_name})) {
foreach ($entity->{$this->field_name} as $langcode => &$data) {
foreach ($data as $delta => $item) {
if (isset($item['value']) && $item['value'] == $this->item_id) {
$this->langcode = $langcode;
return $delta;
if (!empty($data)) {
foreach ($data as $delta => $item) {
if (isset($item['value']) && $item['value'] == $this->item_id) {
$this->langcode = $langcode;
return $delta;
}
elseif (isset($item['entity']) && $item['entity'] === $this) {
$this->langcode = $langcode;
return $delta;
}
}
elseif (isset($item['entity']) && $item['entity'] === $this) {
$this->langcode = $langcode;
return $delta;
}
}
// If we don't find the delta in the current values (cause the item
// is being deleted, for example), we search the delta in the originalcontent.
if (!empty($entity->original)) {
foreach ($entity->original->{$this->field_name} as $langcode => &$data) {
if (!empty($data)) {
foreach ($data as $delta => $item) {
if (isset($item['value']) && $item['value'] == $this->item_id) {
$this->langcode = $langcode;
return $delta;
}
elseif (isset($item['entity']) && $item['entity'] === $this) {
$this->langcode = $langcode;
return $delta;
}
}
}
}
}
......@@ -344,9 +364,15 @@ class FieldCollectionItemEntity extends Entity {
* Determines the language code under which the item is stored.
*/
public function langcode() {
if ($this->delta() !== NULL) {
return $this->langcode;
if ($this->delta() === NULL || empty($this->langcode)) {
$this->langcode = field_collection_entity_language('field_collection_item', $this);
}
if (empty($this->langcode) || ($this->langcode != LANGUAGE_NONE && (!module_exists('entity_translation') || !entity_translation_enabled('field_collection_item')))) {
$this->langcode = LANGUAGE_NONE;
}
return $this->langcode;
}
/**
......@@ -388,6 +414,11 @@ class FieldCollectionItemEntity extends Entity {
throw new Exception("Unable to create a field collection item without a given host entity.");
}
// Copy the values of translatable fields for a new field collection item.
if (field_collection_item_is_translatable() && !empty($this->is_new) && $this->langcode() == LANGUAGE_NONE) {
$this->copyTranslations();
}
// Only save directly if we are told to skip saving the host entity. Else,
// we always save via the host as saving the host might trigger saving
// field collection items anyway (e.g. if a new revision is created).
......@@ -410,11 +441,12 @@ class FieldCollectionItemEntity extends Entity {
// @see field_collection_field_presave()
$delta = $this->delta();
if (isset($delta)) {
$host_entity->{$this->field_name}[$this->langcode][$delta] = array('entity' => $this);
$host_entity->{$this->field_name}[$this->langcode()][$delta] = array('entity' => $this);
}
else {
$host_entity->{$this->field_name}[$this->langcode][] = array('entity' => $this);
$host_entity->{$this->field_name}[$this->langcode()][] = array('entity' => $this);
}
return entity_save($this->hostEntityType, $host_entity);
}
}
......@@ -427,17 +459,60 @@ class FieldCollectionItemEntity extends Entity {
$this->deleteHostEntityReference();
}
/**
* Copies text to all languages the collection item has a translation for.
*
* @param $source_language
* Language code to copy the text from.
*/
public function copyTranslations($source_language = NULL) {
// Get a handler for Entity Translation if there is one.
$host_et_handler = NULL;
if (module_exists('entity_translation')) {
$host_et_handler = entity_translation_get_handler($this->hostEntityType(), $this->hostEntity());
}
if (is_null($host_et_handler)) {
return;
}
$host_languages = array_keys($host_et_handler->getTranslations()->data);
if (empty($host_languages)) {
$host_languages = array(entity_language($this->hostEntityType(), $this->hostEntity()));
}
$source_language = isset($source_language) ? $source_language : $host_et_handler->getLanguage();
$target_languages = array_diff($host_languages, array($source_language));
$fields_instances = array_keys(field_info_instances('field_collection_item', $this->field_name));
$fields = field_info_fields();
foreach ($fields_instances as $translatable_field) {
if ($fields[$translatable_field]['translatable'] == 1) {
foreach ($target_languages as $langcode) {
if (isset($this->{$translatable_field}[$source_language])) {
//Source (translatable_field) is set, therefore continue processing.
if(!isset($this->{$translatable_field}[$langcode])) {
//Destination (translatable_field) is not set, therefore safe to copy the translation.
$this->{$translatable_field}[$langcode] = $this->{$translatable_field}[$source_language];
}
}
}
if ($source_language == LANGUAGE_NONE && count($this->{$translatable_field}) > 1) {
$this->{$translatable_field}[$source_language] = NULL;
}
}
}
}
/**
* Deletes the host entity's reference of the field collection item.
*/
protected function deleteHostEntityReference() {
$delta = $this->delta();
if ($this->item_id && isset($delta)) {
unset($this->hostEntity->{$this->field_name}[$this->langcode][$delta]);
unset($this->hostEntity->{$this->field_name}[$this->langcode()][$delta]);
// Do not save when the host entity is being deleted. See
// field_collection_field_delete().
if (empty($this->hostEntity->field_collection_deleting)) {
entity_save($this->hostEntityType, $this->hostEntity);
entity_save($this->hostEntityType(), $this->hostEntity());
}
}
}
......@@ -449,7 +524,6 @@ class FieldCollectionItemEntity extends Entity {
* a field collection item on the default revision of the host should not
* delete the collection item from archived revisions too. Instead, we delete
* the current default revision and archive the field collection.
*
*/
public function deleteRevision($skip_host_update = FALSE) {
if (!$this->revision_id) {
......@@ -473,11 +547,8 @@ class FieldCollectionItemEntity extends Entity {
->condition('revision_id', $this->revision_id, '<>')
->execute()
->fetchAssoc();
// If no other revision is left, delete. Else archive the item.
if (!$row) {
$this->delete();
}
else {
if ($row) {
// Make the other revision the default revision and archive the item.
db_update('field_collection_item')
->fields(array('archived' => 1, 'revision_id' => $row['revision_id']))
......@@ -486,6 +557,10 @@ class FieldCollectionItemEntity extends Entity {
entity_get_controller('field_collection_item')->resetCache(array($this->item_id));
entity_revision_delete('field_collection_item', $this->revision_id);
}
if (!$row && !isset($this->hostEntity()->{$this->field_name}[$this->langcode()][$this->delta()])) {
// Delete if there is no existing revision or translation to be saved.
$this->delete();
}
}
}
......
......@@ -2,9 +2,11 @@ name = Field collection
description = Provides a field collection field, to which any number of fields can be attached.
core = 7.x
dependencies[] = entity
test_dependencies[] = entity_translation
files[] = field_collection.test
files[] = field_collection.entity.inc
files[] = field_collection.info.inc
files[] = includes/translation.handler.field_collection_item.inc
files[] = views/field_collection_handler_relationship.inc
files[] = field_collection.migrate.inc
configure = admin/structure/field-collections
......
......@@ -352,3 +352,32 @@ function field_collection_update_7007() {
}
}
}
/**
* Update fields in field collections already set to use Entity Translation.
*/
function field_collection_update_7008() {
// Include FieldCollectionItemEntity class.
module_load_include('inc', 'field_collection', 'field_collection.entity');
$results = array();
foreach (field_info_fields() as $f_name => $field) {
if ($field['translatable'] == 1 && isset($field['bundles']['field_collection_item'])) {
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'field_collection_item')
->fieldLanguageCondition($f_name, LANGUAGE_NONE);
$query_result = $query->execute();
if (isset($query_result['field_collection_item'])) {
$results = $results + $query_result['field_collection_item'];
}
}
}
if (count($results)) {
$ids = array_keys($results);
$field_collection_items = entity_load('field_collection_item', $ids);
foreach ($field_collection_items as $item) {
$item->copyTranslations(LANGUAGE_NONE);
$item->save();
}
}
}
This diff is collapsed.
......@@ -30,7 +30,8 @@ function field_collection_item_form($form, &$form_state, $field_collection_item)
// @todo: Fix core and remove the hack.
$form['field_name'] = array('#type' => 'value', '#value' => $field_collection_item->field_name);
field_attach_form('field_collection_item', $field_collection_item, $form, $form_state);
$langcode = entity_language('field_collection_item', $field_collection_item);
field_attach_form('field_collection_item', $field_collection_item, $form, $form_state, $langcode);
$form['actions'] = array('#type' => 'actions', '#weight' => 50);
$form['actions']['submit'] = array(
......@@ -114,7 +115,8 @@ function field_collection_item_add($field_name, $entity_type, $entity_id, $revis
// Check field cardinality.
$field = field_info_field($field_name);
$langcode = LANGUAGE_NONE;
$langcode = !empty($field['translatable']) ? entity_language($entity_type, $entity) : LANGUAGE_NONE;
if (!($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || !isset($entity->{$field_name}[$langcode]) || count($entity->{$field_name}[$langcode]) < $field['cardinality'])) {
drupal_set_message(t('Too many items.'), 'error');
return '';
......@@ -125,7 +127,7 @@ function field_collection_item_add($field_name, $entity_type, $entity_id, $revis
// as during the form-workflow we have multiple field collection item entity
// instances, which we don't want link all with the host.
// That way the link is going to be created when the item is saved.
$field_collection_item->setHostEntity($entity_type, $entity, LANGUAGE_NONE, FALSE);
$field_collection_item->setHostEntity($entity_type, $entity, $langcode, FALSE);
$label = $field_collection_item->translatedInstanceLabel();
$title = ($field['cardinality'] == 1) ? $label : t('Add new !instance_label', array('!instance_label' => $label));
......
This diff is collapsed.
<?php
/**
* @file
* Field Collection Item translation handler for the Entity Translation module.
*/
/**
* Field Collection Item translation handler.
*
* Overrides default behaviours for Field Collection Item properties.
*/
class EntityTranslationFieldCollectionItemHandler extends EntityTranslationDefaultHandler {
/**
* {@inheritdoc}
*/
public function __construct($entity_type, $entity_info, $entity) {
parent::__construct('field_collection_item', $entity_info, $entity);
// Initialize the path scheme for the current bundle, unless we are dealing
// with the "default" bundle.
if ($this->bundle != $entity_info['translation']['entity_translation']['default_scheme']) {
$this->setPathScheme($this->bundle);
}
}
/**
* {@inheritdoc}
*/
public function getAccess($op) {
return field_collection_item_access($op, $this->entity);
}
/**
* {@inheritdoc}
*/
public function getLanguage() {
// Do not use $this->entity->langcode() as this will finally call
// field_collection_entity_language() which again calls us!
// If the current field is untranslatable, try inherit the host entity
// language.
if (($host_entity_type = $this->entity->hostEntityType()) && entity_translation_enabled($host_entity_type) && ($host_entity = $this->entity->hostEntity())) {
$handler = $this->factory->getHandler($host_entity_type, $host_entity);
$langcode = $handler->getFormLanguage();
}
// If the host entity is not translatable, use the default language
// fallback.
else {
$langcode = parent::getLanguage();
}
return $langcode;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment