config('file.settings') ->set('make_unused_managed_files_temporary', TRUE) ->save(); $node_storage = $this->container->get('entity_type.manager')->getStorage('node'); $type_name = 'article'; $field_name = $this->randomMachineName(); $this->createFileField($field_name, 'node', $type_name); // Create the same fields for users. $this->createFileField($field_name, 'user', 'user'); $test_file = $this->getTestFile('text'); // Create a new node with the uploaded file. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file exists on disk and in the database. $node = $node_storage->load($nid); $node_file_r1 = File::load($node->{$field_name}->target_id); $node_vid_r1 = $node->getRevisionId(); $this->assertFileExists($node_file_r1->getFileUri()); $this->assertFileEntryExists($node_file_r1, 'File entry exists in database on node creation.'); $this->assertFileIsPermanent($node_file_r1, 'File is permanent.'); // Upload another file to the same node in a new revision. $this->replaceNodeFile($test_file, $field_name, $nid); $node = $node_storage->load($nid); $node_file_r2 = File::load($node->{$field_name}->target_id); $node_vid_r2 = $node->getRevisionId(); $this->assertFileExists($node_file_r2->getFileUri()); $this->assertFileEntryExists($node_file_r2, 'Replacement file entry exists in database after creating new revision.'); $this->assertFileIsPermanent($node_file_r2, 'Replacement file is permanent.'); // Check that the original file is still in place on the first revision. $node = $node_storage->loadRevision($node_vid_r1); $current_file = File::load($node->{$field_name}->target_id); $this->assertEquals($node_file_r1->id(), $current_file->id(), 'Original file still in place after replacing file in new revision.'); $this->assertFileExists($node_file_r1->getFileUri()); $this->assertFileEntryExists($node_file_r1, 'Original file entry still in place after replacing file in new revision'); $this->assertFileIsPermanent($node_file_r1, 'Original file is still permanent.'); // Save a new version of the node without any changes. // Check that the file is still the same as the previous revision. $this->drupalGet('node/' . $nid . '/edit'); $this->submitForm(['revision' => '1'], 'Save'); $node = $node_storage->load($nid); $node_file_r3 = File::load($node->{$field_name}->target_id); $node_vid_r3 = $node->getRevisionId(); $this->assertEquals($node_file_r2->id(), $node_file_r3->id(), 'Previous revision file still in place after creating a new revision without a new file.'); $this->assertFileIsPermanent($node_file_r3, 'New revision file is permanent.'); // Revert to the first revision and check that the original file is active. $this->drupalGet('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert'); $this->submitForm([], 'Revert'); $node = $node_storage->load($nid); $node_file_r4 = File::load($node->{$field_name}->target_id); $this->assertEquals($node_file_r1->id(), $node_file_r4->id(), 'Original revision file still in place after reverting to the original revision.'); $this->assertFileIsPermanent($node_file_r4, 'Original revision file still permanent after reverting to the original revision.'); // Delete the second revision and check that the file is kept (since it is // still being used by the third revision). $this->drupalGet('node/' . $nid . '/revisions/' . $node_vid_r2 . '/delete'); $this->submitForm([], 'Delete'); $this->assertFileExists($node_file_r3->getFileUri()); $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting second revision, since it is being used by the third revision.'); $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting second revision, since it is being used by the third revision.'); // Attach the second file to a user. $user = $this->drupalCreateUser(); $user->$field_name->target_id = $node_file_r3->id(); $user->$field_name->display = 1; $user->save(); $this->drupalGet('user/' . $user->id() . '/edit'); // Delete the third revision and check that the file is not deleted yet. $this->drupalGet('node/' . $nid . '/revisions/' . $node_vid_r3 . '/delete'); $this->submitForm([], 'Delete'); $this->assertFileExists($node_file_r3->getFileUri()); $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting third revision, since it is being used by the user.'); $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting third revision, since it is being used by the user.'); // Delete the user and check that the file is also deleted. $user->delete(); // Call file_cron() to clean up the file. Make sure the changed timestamp // of the file is older than the system.file.temporary_maximum_age // configuration value. We use an UPDATE statement because using the API // would set the timestamp. $connection = Database::getConnection(); $connection->update('file_managed') ->fields([ 'changed' => \Drupal::time()->getRequestTime() - ($this->config('system.file')->get('temporary_maximum_age') + 1), ]) ->condition('fid', $node_file_r3->id()) ->execute(); \Drupal::service('cron')->run(); $this->assertFileDoesNotExist($node_file_r3->getFileUri()); $this->assertFileEntryNotExists($node_file_r3, 'Second file entry is now deleted after deleting third revision, since it is no longer being used by any other nodes.'); // Delete the entire node and check that the original file is deleted. $this->drupalGet('node/' . $nid . '/delete'); $this->submitForm([], 'Delete'); // Call file_cron() to clean up the file. Make sure the changed timestamp // of the file is older than the system.file.temporary_maximum_age // configuration value. We use an UPDATE statement because using the API // would set the timestamp. $connection->update('file_managed') ->fields([ 'changed' => \Drupal::time()->getRequestTime() - ($this->config('system.file')->get('temporary_maximum_age') + 1), ]) ->condition('fid', $node_file_r1->id()) ->execute(); \Drupal::service('cron')->run(); $this->assertFileDoesNotExist($node_file_r1->getFileUri()); $this->assertFileEntryNotExists($node_file_r1, 'Original file entry is deleted after deleting the entire node with two revisions remaining.'); } }