File entities created by POSTing a base64-encoded image using the REST API are created as temporary files and cannot then be attached to another entity, and worse, are deleted after 6 hours.
This seems to be related to https://www.drupal.org/node/618654 or https://www.drupal.org/node/1028092 which are issues dating back 7 years, but surely this can't still be an unsolved problem.
I'm still getting to grips with D8 so I'm only tentatively poking around, but as far as I can tell the issue seems to be that FileEntityNormalizer.php is responsible for saving the POSTED file data in the denormalize method:
public function denormalize($data, $class, $format = NULL, array $context = array()) {
// Avoid 'data' being treated as a field.
$file_data = $data['data'][0]['value'];
unset($data['data']);
// Decode and save to file.
$file_contents = base64_decode($file_data);
$entity = parent::denormalize($data, $class, $format, $context);
$dirname = drupal_dirname($entity->getFileUri());
file_prepare_directory($dirname, FILE_CREATE_DIRECTORY);
if ($uri = file_unmanaged_save_data($file_contents, $entity->getFileUri())) {
$entity->setFileUri($uri);
}
else {
throw new \RuntimeException(SafeMarkup::format('Failed to write @filename.', array('@filename' => $entity->getFilename())));
}
return $entity;
}
If I understand correctly, using file_unmanaged_save_data is ensuring the created file is temporary. I tried switching out that function for file_save_data which should make it a normal Drupal file, but that results in a 500 error:
Recoverable fatal error: Object of class Drupal\\file_entity\\Entity\\FileEntity could not be converted to string in /core/lib/Drupal/Core/Database/Statement.php on line 59
...and I'm not sure what that means, or how to fix that.
Looking at the code in file_save_data the relevant part that saves a permanent file looks like this:
if ($uri = file_unmanaged_save_data($data, $destination, $replace)) {
// Create a file entity.
$file = File::create([
'uri' => $uri,
'uid' => $user->id(),
'status' => FILE_STATUS_PERMANENT,
]);
...
file->save();
But the denormalize method doesn't seem to deal with file entities, so I can't modify it to set the status to FILE_STATUS_PERMANENT. I tried injecting this code into what looked like the appropriate place in the denormalize method, but I get the same error as when I switched file_unmanaged_save_data for file_save_data.
I'll keep poking around, but it seems like saving a file permanently using the REST API should be doable?
Comment | File | Size | Author |
---|---|---|---|
#20 | file_entity_save_permanent-2756127-19-v0.1.patch | 775 bytes | j1mb0b |
#19 | file_entity_save_permanent-2756127-19.patch | 522 bytes | Fonski |
#11 | file_entity_save_permanent_beta4.patch | 581 bytes | Ibn al-Hazardous |
#5 | 8.x-2.0-beta3_file_entity_save_permanent.patch | 522 bytes | cronos0 |
#2 | file_entity_save_permanent.patch | 647 bytes | scott.whittaker |
Comments
Comment #2
scott.whittaker CreditAttribution: scott.whittaker as a volunteer commentedOK I've got a simple fix for this - add:
$entity->status = FILE_STATUS_PERMANENT;
just before the
return $entity;
in FileEntityNormalizer.denormalize. Patch attached.Comment #3
uwieske CreditAttribution: uwieske commentedI am currently trying to submit a file (plus hal_json data) to Drupal 8.1.x REST API, but I am not able to set the status of this file to PERMANENT. Well actually Ii am not sure whether I am doing it wrongly or whether this feature is (still) simply not possible via the REST interface....?
Has this issue been fixed already? And does it relate to my use case above with Drupal 8.1.x REST API?
I have searched the web for more information on Drupal 8.1.x REST API inner workings with respect to REST, Uploaded File and File status, but I was not successful in getting much valuable information pointing to a solution.
http://stackoverflow.com/questions/38849454/which-drupal-8-1-x-rest-api-...
Comment #4
treasury CreditAttribution: treasury commented#2 works. Thank you @scott.whittaker.
Comment #5
cronos0 CreditAttribution: cronos0 as a volunteer commentedI have rewrite the patch for the last beta release, and correct the path reference for install with composer.
Comment #6
badrange CreditAttribution: badrange at Digia commentedSetting to "Needs review" since there is a patch.
Comment #10
Drupali CreditAttribution: Drupali commented#2 did not work for me. I tried it on drupal 8.3.7.
Is there any progress on this issue ?
Comment #11
Ibn al-Hazardous CreditAttribution: Ibn al-Hazardous commentedI took a stab at updating the patch for beta4.
Comment #12
imclean CreditAttribution: imclean commentedIt looks like this will be included in 8.6.x. See the change record: New "file_upload" REST resource plugin: allows file uploads of any size, creates File entities
Also in 8.6: HAL's FileEntityNormalizer::denormalize() removed
Comment #14
joseph.olstadComment #15
BerdirI'm not sure this is the right fix and if it is a safe thing to do.
Also, core is going into a very different direction in regards to creating file entities over REST, a direction where this will not help I think.
Comment #17
joseph.olstadsee comment #16 as per #15 reverting #13
setting to needs review.
Comment #18
joseph.olstadComment #19
Fonski CreditAttribution: Fonski commentedRe-created the patch from #11 to correct the diff path (atm it was not applicable through composer for example).
Comment #20
j1mb0b CreditAttribution: j1mb0b as a volunteer commentedAdded setSize(). Since after PATCH it doesn't update correctly the file size. Also, it will FILE_EXISTS_REPLACE. Enforcing this is probably not a good idea, but it is suitable for my use-case.
Comment #21
BerdirSorry but I have no intentation of improving the this normalizer further.
Drupal core has an official API for creating files through REST now since 8.6 and you should use that: https://www.drupal.org/node/2941420.