Problem/Motivation

Files uploaded to a field of the type provided are removed on cron runs.
The record in the file_managed table has status = 0

After the cron run, the package no longer renders, because the reference file entity has been deleted.

Is this intentional? Why would this happen?

Comments

markusa created an issue. See original summary.

markusa’s picture

I'm trying to get this to work, here's a patch, but its not quite right.

This will create a file_usage entry when you save the node the xAPI Package field is attached to.
Doing this, the file_managed record gets status=1

This code does not work on file delete / node save. The file_usage record is not deleted, the reference to the file is removed as normal, but the file is still status=1.

diff --git a/src/Plugin/Field/FieldType/XapiItem.php b/src/Plugin/Field/FieldType/XapiItem.php
index 99a889c..ee8dcfc 100644
--- a/src/Plugin/Field/FieldType/XapiItem.php
+++ b/src/Plugin/Field/FieldType/XapiItem.php
@@ -75,6 +75,10 @@ final class XapiItem extends FileItem {
     }
 
     $filesystem->remove($path);
+    // Delete file usage.
+    $file = $this->entity;
+    $entity_type = $this->getParent()->getEntity()->getEntityTypeId();
+    \Drupal::service('file.usage')->delete($file, 'lms_xapi', $entity_type, $this->getParent()->getEntity()->id());
   }
 
   /**
@@ -120,6 +124,49 @@ final class XapiItem extends FileItem {
     parent::preSave();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave($update) {
+    $entity = $this->getParent()->getEntity();
+    $entity_type = $entity->getEntityTypeId();
+    $file = $this->entity;
+
+    if (!$update) {
+      \Drupal::service('file.usage')->add($file, 'lms_xapi', $entity_type, $entity->id());
+    }
+    else {
+      if (!empty($entity->original) && $entity->getRevisionId() != $entity->original->getRevisionId()) {
+        \Drupal::service('file.usage')->add($file, 'lms_xapi', $entity->getEntityTypeId(), $entity->id());
+        return;
+      }
+      $ids = [$file->id()];
+      // Get the file IDs attached to the field before this update.
+      $field_name = $this->getFieldDefinition()->getName();
+      $original_ids = [];
+      $langcode = $this->getLangcode();
+      $original = $entity->original;
+      if ($original->hasTranslation($langcode)) {
+        $original_items = $original->getTranslation($langcode)->{$field_name};
+        foreach ($original_items as $item) {
+          $original_ids[] = $item->target_id;
+        }
+      }
+
+      // Decrement file usage by 1 for files that were removed from the field.
+      $removed_ids = array_filter(array_diff($original_ids, $ids));
+      $removed_files = \Drupal::entityTypeManager()->getStorage('file')->loadMultiple($removed_ids);
+      if (!empty($removed_files)) {
+        foreach ($removed_files as $file) {
+          \Drupal::service('file.usage')->delete($file, 'lms_xapi', $entity->getEntityTypeId(), $entity->id());
+        }
+      }
+      if (!in_array($file->id(), $original_ids)) {
+        \Drupal::service('file.usage')->add($file, 'lms_xapi', $entity->getEntityTypeId(), $entity->id());
+      }
+    }
+  }
+
   /**
    * Get full path of the extracted package.
    */

markusa’s picture

After patch, the status = 1

mysql> select * from node__field_xapi_package;
+--------------+---------+-----------+-------------+----------+-------+------------------------------+----------------------------+--------------------------------+
| bundle       | deleted | entity_id | revision_id | langcode | delta | field_xapi_package_target_id | field_xapi_package_display | field_xapi_package_description |
+--------------+---------+-----------+-------------+----------+-------+------------------------------+----------------------------+--------------------------------+
| xapi_package |       0 |      3393 |       15992 | en       |     0 |                        70211 |                          1 |                                |
+--------------+---------+-----------+-------------+----------+-------+------------------------------+----------------------------+--------------------------------+
1 row in set (0.00 sec)

mysql> select fid, status from file_managed where fid=70211;
+-------+--------+
| fid   | status |
+-------+--------+
| 70211 |      1 |
+-------+--------+
1 row in set (0.00 sec)

mysql> select * from file_usage where fid=70211;
+-------+----------+------+------+-------+
| fid   | module   | type | id   | count |
+-------+----------+------+------+-------+
| 70211 | lms_xapi | node | 3393 |     1 |
+-------+----------+------+------+-------+
1 row in set (0.01 sec)

It should manage replacing a file with another as well.

graber’s picture

Edge case as file usage doesn't delete files by default since a long time. Requires fixing nevertheless. The fix is much more simple though.

  • dc1cfed2 committed on 1.0.x
    #3553650: Make XapiItem use FileFieldItemList.
    
graber’s picture

Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

markusa’s picture

Your commit still doesn't work.

After uploading a file and saving the node, the record in the file_managed table has status=0
no file_usage records created.
The file is temporary and deleted on cron runs.

mysql> select * from file_usage where fid=69366;
Empty set (0.00 sec)
mysql> select fid, status from file_managed where fid=69366;
+-------+--------+
| fid   | status |
+-------+--------+
| 69366 |      0 |
+-------+--------+
1 row in set (0.00 sec)
markusa’s picture

Whoops never mind, had to clear those caches :) Thank you!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.