1<?php
2
3namespace Drupal\file\Plugin\Field\FieldType;
4
5use Drupal\Core\Field\EntityReferenceFieldItemList;
6use Drupal\Core\Form\FormStateInterface;
7
8/**
9 * Represents a configurable entity file field.
10 */
11class FileFieldItemList extends EntityReferenceFieldItemList {
12
13  /**
14   * {@inheritdoc}
15   */
16  public function defaultValuesForm(array &$form, FormStateInterface $form_state) {}
17
18  /**
19   * {@inheritdoc}
20   */
21  public function postSave($update) {
22    $entity = $this->getEntity();
23
24    if (!$update) {
25      // Add a new usage for newly uploaded files.
26      foreach ($this->referencedEntities() as $file) {
27        \Drupal::service('file.usage')->add($file, 'file', $entity->getEntityTypeId(), $entity->id());
28      }
29    }
30    else {
31      // Get current target file entities and file IDs.
32      $files = $this->referencedEntities();
33      $ids = [];
34
35      /** @var \Drupal\file\FileInterface $file */
36      foreach ($files as $file) {
37        $ids[] = $file->id();
38      }
39
40      // On new revisions, all files are considered to be a new usage and no
41      // deletion of previous file usages are necessary.
42      if (!empty($entity->original) && $entity->getRevisionId() != $entity->original->getRevisionId()) {
43        foreach ($files as $file) {
44          \Drupal::service('file.usage')->add($file, 'file', $entity->getEntityTypeId(), $entity->id());
45        }
46        return;
47      }
48
49      // Get the file IDs attached to the field before this update.
50      $field_name = $this->getFieldDefinition()->getName();
51      $original_ids = [];
52      $langcode = $this->getLangcode();
53      $original = $entity->original;
54      if ($original->hasTranslation($langcode)) {
55        $original_items = $original->getTranslation($langcode)->{$field_name};
56        foreach ($original_items as $item) {
57          $original_ids[] = $item->target_id;
58        }
59      }
60
61      // Decrement file usage by 1 for files that were removed from the field.
62      $removed_ids = array_filter(array_diff($original_ids, $ids));
63      $removed_files = \Drupal::entityTypeManager()->getStorage('file')->loadMultiple($removed_ids);
64      foreach ($removed_files as $file) {
65        \Drupal::service('file.usage')->delete($file, 'file', $entity->getEntityTypeId(), $entity->id());
66      }
67
68      // Add new usage entries for newly added files.
69      foreach ($files as $file) {
70        if (!in_array($file->id(), $original_ids)) {
71          \Drupal::service('file.usage')->add($file, 'file', $entity->getEntityTypeId(), $entity->id());
72        }
73      }
74    }
75  }
76
77  /**
78   * {@inheritdoc}
79   */
80  public function delete() {
81    parent::delete();
82    $entity = $this->getEntity();
83
84    // If a translation is deleted only decrement the file usage by one. If the
85    // default translation is deleted remove all file usages within this entity.
86    $count = $entity->isDefaultTranslation() ? 0 : 1;
87    foreach ($this->referencedEntities() as $file) {
88      \Drupal::service('file.usage')->delete($file, 'file', $entity->getEntityTypeId(), $entity->id(), $count);
89    }
90  }
91
92  /**
93   * {@inheritdoc}
94   */
95  public function deleteRevision() {
96    parent::deleteRevision();
97    $entity = $this->getEntity();
98
99    // Decrement the file usage by 1.
100    foreach ($this->referencedEntities() as $file) {
101      \Drupal::service('file.usage')->delete($file, 'file', $entity->getEntityTypeId(), $entity->id());
102    }
103  }
104
105}
106