diff --git a/src/Controller/MediaSourceController.php b/src/Controller/MediaSourceController.php index 29ff9412..a7e5221a 100644 --- a/src/Controller/MediaSourceController.php +++ b/src/Controller/MediaSourceController.php @@ -231,23 +231,41 @@ class MediaSourceController extends ControllerBase { public function attachToMedia( Media $media, string $destination_field, - Request $request) { + Request $request + ) { $content_location = $request->headers->get('Content-Location', ""); - $contents = $request->getContent(); - if ($contents) { - $file = file_save_data($contents, $content_location, FileSystemInterface::EXISTS_REPLACE); - if ($media->hasField($destination_field)) { - $media->{$destination_field}->setValue([ - 'target_id' => $file->id(), - ]); - $media->save(); - } - else { - $this->getLogger('islandora')->warning("Field $destination_field is not defined in Media Type {$media->bundle()}"); - } + if (empty($content_location)) { + throw new BadRequestHttpException("Missing Content-Location header"); + } + + $content_type = $request->headers->get('Content-Type', ""); + if (empty($content_type)) { + throw new BadRequestHttpException("Missing Content-Type header"); + } + + // Since we create both a Media and its File, + // start a transaction. + $transaction = $this->database->startTransaction(); + + try { + $this->service->putToMedia( + $media, + $destination_field, + $request->getContent(TRUE), + $content_type, + $content_location + ); + // Should only see this with a GET request for testing. + return new Response("

Complete

"); + } + catch (HttpException $e) { + $transaction->rollBack(); + throw $e; + } + catch (\Exception $e) { + $transaction->rollBack(); + throw new HttpException(500, $e->getMessage()); } - // Should only see this with a GET request for testing. - return new Response("

Complete

"); } /** diff --git a/src/MediaSource/MediaSourceService.php b/src/MediaSource/MediaSourceService.php index dc6d4c5a..de346115 100644 --- a/src/MediaSource/MediaSourceService.php +++ b/src/MediaSource/MediaSourceService.php @@ -318,4 +318,68 @@ class MediaSourceService { } + /** + * Creates a new File using the provided resource, adding it to a Media. + * + * @param \Drupal\media\MediaInterface $media + * The Media that will receive the new file. + * @param string $destination_field + * The field on the media where the file will go. + * @param resource $resource + * New file contents as a resource. + * @param string $mimetype + * New mimetype of contents. + * @param string $content_location + * Drupal/PHP stream wrapper for where to upload the binary. + * + * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + * @throws \Symfony\Component\HttpKernel\Exception\HttpException + */ + public function putToMedia( + MediaInterface $media, + $destination_field, + $resource, + $mimetype, + $content_location + ) { + if ($media->hasField($destination_field)) { + // Construct the File. + $file = $this->entityTypeManager->getStorage('file')->create([ + 'uid' => $this->account->id(), + 'uri' => $content_location, + 'filename' => $this->fileSystem->basename($content_location), + 'filemime' => $mimetype, + 'status' => FILE_STATUS_PERMANENT, + ]); + + // Validate file extension. + $bundle = $media->bundle(); + $destination_field_config = $this->entityTypeManager->getStorage('field_config')->load("media.$bundle.$destination_field"); + $valid_extensions = $destination_field_config->getSetting('file_extensions'); + $errors = file_validate_extensions($file, $valid_extensions); + + if (!empty($errors)) { + throw new BadRequestHttpException("Invalid file extension. Valid types are $valid_extensions"); + } + + $directory = $this->fileSystem->dirname($content_location); + if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { + throw new HttpException(500, "The destination directory does not exist, could not be created, or is not writable"); + } + + // Copy over the file content. + $this->updateFile($file, $resource, $mimetype); + $file->save(); + + // Update the media. + $media->{$destination_field}->setValue([ + 'target_id' => $file->id(), + ]); + $media->save(); + } + else { + throw new BadRequestHttpException("Media does not have destination field $destination_field"); + } + } + }