Chris@4
|
1 <?php
|
Chris@4
|
2
|
Chris@4
|
3 namespace Drupal\Tests\file\Functional;
|
Chris@4
|
4
|
Chris@5
|
5 use Drupal\Core\Database\Database;
|
Chris@4
|
6 use Drupal\file\Entity\File;
|
Chris@4
|
7
|
Chris@4
|
8 /**
|
Chris@4
|
9 * Tests creating and deleting revisions with files attached.
|
Chris@4
|
10 *
|
Chris@4
|
11 * @group file
|
Chris@4
|
12 */
|
Chris@4
|
13 class FileFieldRevisionTest extends FileFieldTestBase {
|
Chris@4
|
14
|
Chris@4
|
15 /**
|
Chris@4
|
16 * Tests creating multiple revisions of a node and managing attached files.
|
Chris@4
|
17 *
|
Chris@4
|
18 * Expected behaviors:
|
Chris@4
|
19 * - Adding a new revision will make another entry in the field table, but
|
Chris@4
|
20 * the original file will not be duplicated.
|
Chris@4
|
21 * - Deleting a revision should not delete the original file if the file
|
Chris@4
|
22 * is in use by another revision.
|
Chris@4
|
23 * - When the last revision that uses a file is deleted, the original file
|
Chris@4
|
24 * should be deleted also.
|
Chris@4
|
25 */
|
Chris@4
|
26 public function testRevisions() {
|
Chris@4
|
27 // This test expects unused managed files to be marked as a temporary file
|
Chris@4
|
28 // and then deleted up by file_cron().
|
Chris@4
|
29 $this->config('file.settings')
|
Chris@4
|
30 ->set('make_unused_managed_files_temporary', TRUE)
|
Chris@4
|
31 ->save();
|
Chris@4
|
32 $node_storage = $this->container->get('entity.manager')->getStorage('node');
|
Chris@4
|
33 $type_name = 'article';
|
Chris@4
|
34 $field_name = strtolower($this->randomMachineName());
|
Chris@4
|
35 $this->createFileField($field_name, 'node', $type_name);
|
Chris@4
|
36 // Create the same fields for users.
|
Chris@4
|
37 $this->createFileField($field_name, 'user', 'user');
|
Chris@4
|
38
|
Chris@4
|
39 $test_file = $this->getTestFile('text');
|
Chris@4
|
40
|
Chris@4
|
41 // Create a new node with the uploaded file.
|
Chris@4
|
42 $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
|
Chris@4
|
43
|
Chris@4
|
44 // Check that the file exists on disk and in the database.
|
Chris@4
|
45 $node_storage->resetCache([$nid]);
|
Chris@4
|
46 $node = $node_storage->load($nid);
|
Chris@4
|
47 $node_file_r1 = File::load($node->{$field_name}->target_id);
|
Chris@4
|
48 $node_vid_r1 = $node->getRevisionId();
|
Chris@4
|
49 $this->assertFileExists($node_file_r1, 'New file saved to disk on node creation.');
|
Chris@4
|
50 $this->assertFileEntryExists($node_file_r1, 'File entry exists in database on node creation.');
|
Chris@4
|
51 $this->assertFileIsPermanent($node_file_r1, 'File is permanent.');
|
Chris@4
|
52
|
Chris@4
|
53 // Upload another file to the same node in a new revision.
|
Chris@4
|
54 $this->replaceNodeFile($test_file, $field_name, $nid);
|
Chris@4
|
55 $node_storage->resetCache([$nid]);
|
Chris@4
|
56 $node = $node_storage->load($nid);
|
Chris@4
|
57 $node_file_r2 = File::load($node->{$field_name}->target_id);
|
Chris@4
|
58 $node_vid_r2 = $node->getRevisionId();
|
Chris@4
|
59 $this->assertFileExists($node_file_r2, 'Replacement file exists on disk after creating new revision.');
|
Chris@4
|
60 $this->assertFileEntryExists($node_file_r2, 'Replacement file entry exists in database after creating new revision.');
|
Chris@4
|
61 $this->assertFileIsPermanent($node_file_r2, 'Replacement file is permanent.');
|
Chris@4
|
62
|
Chris@4
|
63 // Check that the original file is still in place on the first revision.
|
Chris@4
|
64 $node = node_revision_load($node_vid_r1);
|
Chris@4
|
65 $current_file = File::load($node->{$field_name}->target_id);
|
Chris@4
|
66 $this->assertEqual($node_file_r1->id(), $current_file->id(), 'Original file still in place after replacing file in new revision.');
|
Chris@4
|
67 $this->assertFileExists($node_file_r1, 'Original file still in place after replacing file in new revision.');
|
Chris@4
|
68 $this->assertFileEntryExists($node_file_r1, 'Original file entry still in place after replacing file in new revision');
|
Chris@4
|
69 $this->assertFileIsPermanent($node_file_r1, 'Original file is still permanent.');
|
Chris@4
|
70
|
Chris@4
|
71 // Save a new version of the node without any changes.
|
Chris@4
|
72 // Check that the file is still the same as the previous revision.
|
Chris@4
|
73 $this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save'));
|
Chris@4
|
74 $node_storage->resetCache([$nid]);
|
Chris@4
|
75 $node = $node_storage->load($nid);
|
Chris@4
|
76 $node_file_r3 = File::load($node->{$field_name}->target_id);
|
Chris@4
|
77 $node_vid_r3 = $node->getRevisionId();
|
Chris@4
|
78 $this->assertEqual($node_file_r2->id(), $node_file_r3->id(), 'Previous revision file still in place after creating a new revision without a new file.');
|
Chris@4
|
79 $this->assertFileIsPermanent($node_file_r3, 'New revision file is permanent.');
|
Chris@4
|
80
|
Chris@4
|
81 // Revert to the first revision and check that the original file is active.
|
Chris@4
|
82 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', [], t('Revert'));
|
Chris@4
|
83 $node_storage->resetCache([$nid]);
|
Chris@4
|
84 $node = $node_storage->load($nid);
|
Chris@4
|
85 $node_file_r4 = File::load($node->{$field_name}->target_id);
|
Chris@4
|
86 $this->assertEqual($node_file_r1->id(), $node_file_r4->id(), 'Original revision file still in place after reverting to the original revision.');
|
Chris@4
|
87 $this->assertFileIsPermanent($node_file_r4, 'Original revision file still permanent after reverting to the original revision.');
|
Chris@4
|
88
|
Chris@4
|
89 // Delete the second revision and check that the file is kept (since it is
|
Chris@4
|
90 // still being used by the third revision).
|
Chris@4
|
91 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r2 . '/delete', [], t('Delete'));
|
Chris@4
|
92 $this->assertFileExists($node_file_r3, 'Second file is still available after deleting second revision, since it is being used by the third revision.');
|
Chris@4
|
93 $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting second revision, since it is being used by the third revision.');
|
Chris@4
|
94 $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting second revision, since it is being used by the third revision.');
|
Chris@4
|
95
|
Chris@4
|
96 // Attach the second file to a user.
|
Chris@4
|
97 $user = $this->drupalCreateUser();
|
Chris@4
|
98 $user->$field_name->target_id = $node_file_r3->id();
|
Chris@4
|
99 $user->$field_name->display = 1;
|
Chris@4
|
100 $user->save();
|
Chris@4
|
101 $this->drupalGet('user/' . $user->id() . '/edit');
|
Chris@4
|
102
|
Chris@4
|
103 // Delete the third revision and check that the file is not deleted yet.
|
Chris@4
|
104 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r3 . '/delete', [], t('Delete'));
|
Chris@4
|
105 $this->assertFileExists($node_file_r3, 'Second file is still available after deleting third revision, since it is being used by the user.');
|
Chris@4
|
106 $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting third revision, since it is being used by the user.');
|
Chris@4
|
107 $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting third revision, since it is being used by the user.');
|
Chris@4
|
108
|
Chris@4
|
109 // Delete the user and check that the file is also deleted.
|
Chris@4
|
110 $user->delete();
|
Chris@4
|
111 // TODO: This seems like a bug in File API. Clearing the stat cache should
|
Chris@4
|
112 // not be necessary here. The file really is deleted, but stream wrappers
|
Chris@4
|
113 // doesn't seem to think so unless we clear the PHP file stat() cache.
|
Chris@4
|
114 clearstatcache($node_file_r1->getFileUri());
|
Chris@4
|
115 clearstatcache($node_file_r2->getFileUri());
|
Chris@4
|
116 clearstatcache($node_file_r3->getFileUri());
|
Chris@4
|
117 clearstatcache($node_file_r4->getFileUri());
|
Chris@4
|
118
|
Chris@4
|
119 // Call file_cron() to clean up the file. Make sure the changed timestamp
|
Chris@4
|
120 // of the file is older than the system.file.temporary_maximum_age
|
Chris@5
|
121 // configuration value. We use an UPDATE statement because using the API
|
Chris@5
|
122 // would set the timestamp.
|
Chris@5
|
123 $connection = Database::getConnection();
|
Chris@5
|
124 $connection->update('file_managed')
|
Chris@4
|
125 ->fields([
|
Chris@4
|
126 'changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1),
|
Chris@4
|
127 ])
|
Chris@4
|
128 ->condition('fid', $node_file_r3->id())
|
Chris@4
|
129 ->execute();
|
Chris@4
|
130 \Drupal::service('cron')->run();
|
Chris@4
|
131
|
Chris@4
|
132 $this->assertFileNotExists($node_file_r3, 'Second file is now deleted after deleting third revision, since it is no longer being used by any other nodes.');
|
Chris@4
|
133 $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.');
|
Chris@4
|
134
|
Chris@4
|
135 // Delete the entire node and check that the original file is deleted.
|
Chris@4
|
136 $this->drupalPostForm('node/' . $nid . '/delete', [], t('Delete'));
|
Chris@4
|
137 // Call file_cron() to clean up the file. Make sure the changed timestamp
|
Chris@4
|
138 // of the file is older than the system.file.temporary_maximum_age
|
Chris@5
|
139 // configuration value. We use an UPDATE statement because using the API
|
Chris@5
|
140 // would set the timestamp.
|
Chris@5
|
141 $connection->update('file_managed')
|
Chris@4
|
142 ->fields([
|
Chris@4
|
143 'changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1),
|
Chris@4
|
144 ])
|
Chris@4
|
145 ->condition('fid', $node_file_r1->id())
|
Chris@4
|
146 ->execute();
|
Chris@4
|
147 \Drupal::service('cron')->run();
|
Chris@4
|
148 $this->assertFileNotExists($node_file_r1, 'Original file is deleted after deleting the entire node with two revisions remaining.');
|
Chris@4
|
149 $this->assertFileEntryNotExists($node_file_r1, 'Original file entry is deleted after deleting the entire node with two revisions remaining.');
|
Chris@4
|
150 }
|
Chris@4
|
151
|
Chris@4
|
152 }
|