Problem/Motivation
Images uploaded to an image field are lost when the node language is changed (because file usage incorrectly drops down to zero, causing the permanent file to be marked temporary, and then eventually being deleted — after 6 hours by default).
Same for files uploaded to a file field.
Steps to reproduce
- create a content type with an
image
field - enable >=2 languages in site
- set the content translatable (tested setting the file translatable or not)
- create a node with an image and save it
- verify that the uploaded file has its
status
column in thefile_managed
table set to1
,
and it has 1 usage in thefile_usage
table - edit the node and change the language
- expected result: the uploaded file still has its
status
column in thefile_managed
table set to1
, and it has 1 usage in thefile_usage
table - actual result: the uploaded file now has its
status
column in thefile_managed
table set to0
, and it has 0 usage in thefile_usage
table
- expected result: the uploaded file still has its
- run cron 6 hours later (this is the default value of the
temporary_maximum_age
setting insystem.file
) - expected result: the uploaded file is still present (because usage > 0)
- actual result: the uploaded file is absent (because usage = 0)
Note: see #40, where it is explained how this same problem is even reproducible on sites without content_translation
are affected by this, merely having the language
(Interface translation
) module installed and having >1 interface language enabled is sufficient to reproduce this problem for image/file fields on User
entities!
Proposed resolution
Root cause analysis:
\Drupal\file\Plugin\Field\FieldType\FileFieldItemList::delete()
removing file usages:public function delete() { parent::delete(); $entity = $this->getEntity(); // If a translation is deleted only decrement the file usage by one. If the // default translation is deleted remove all file usages within this entity. $count = $entity->isDefaultTranslation() ? 0 : 1; foreach ($this->referencedEntities() as $file) { \Drupal::service('file.usage')->delete($file, 'file', $entity->getEntityTypeId(), $entity->id(), $count); } }
- to delete file usages, it relies on
$entity->isDefaultTranslation()
(i.e.\Drupal\Core\TypedData\TranslatableInterface::isDefaultTranslation()
) to determine whether a translation is being deleted or not $entity->isDefaultTranslation()
behaves incorrectly when the default translation is being changed
Therefore the solution is: fix \Drupal\Core\Entity\ContentEntityBase::isDefaultTranslation()
.
Remaining tasks
TBD
User interface changes
None.
API changes
None.
Data model changes
None.