class FileUpload in Drupal 8
Same name and namespace in other branches
- 9 core/modules/jsonapi/src/Controller/FileUpload.php \Drupal\jsonapi\Controller\FileUpload
Handles file upload requests.
@internal JSON:API maintains no PHP API. The API is the HTTP API. This class may change at any time and could break any dependencies on it.
Hierarchy
- class \Drupal\jsonapi\Controller\FileUpload uses EntityValidationTrait
Expanded class hierarchy of FileUpload
See also
https://www.drupal.org/project/drupal/issues/3032787
1 string reference to 'FileUpload'
- jsonapi.services.yml in core/
modules/ jsonapi/ jsonapi.services.yml - core/modules/jsonapi/jsonapi.services.yml
1 service uses FileUpload
- jsonapi.file_upload in core/
modules/ jsonapi/ jsonapi.services.yml - Drupal\jsonapi\Controller\FileUpload
File
- core/
modules/ jsonapi/ src/ Controller/ FileUpload.php, line 40
Namespace
Drupal\jsonapi\ControllerView source
class FileUpload {
use EntityValidationTrait;
/**
* The current user making the request.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $fieldManager;
/**
* The file uploader.
*
* @var \Drupal\jsonapi\Controller\TemporaryJsonapiFileFieldUploader
*/
protected $fileUploader;
/**
* An HTTP kernel for making subrequests.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $httpKernel;
/**
* Creates a new FileUpload instance.
*
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager
* The entity field manager.
* @param \Drupal\jsonapi\Controller\TemporaryJsonapiFileFieldUploader $file_uploader
* The file uploader.
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
* An HTTP kernel for making subrequests.
*/
public function __construct(AccountInterface $current_user, EntityFieldManagerInterface $field_manager, TemporaryJsonapiFileFieldUploader $file_uploader, HttpKernelInterface $http_kernel) {
$this->currentUser = $current_user;
$this->fieldManager = $field_manager;
$this->fileUploader = $file_uploader;
$this->httpKernel = $http_kernel;
}
/**
* Handles JSON:API file upload requests.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HTTP request object.
* @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
* The JSON:API resource type for the current request.
* @param string $file_field_name
* The file field for which the file is to be uploaded.
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity for which the file is to be uploaded.
*
* @return \Drupal\jsonapi\ResourceResponse
* The response object.
*
* @throws \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException
* Thrown when there are validation errors.
* @throws \Drupal\Core\Entity\EntityStorageException
* Thrown if the upload's target resource could not be saved.
* @throws \Exception
* Thrown if an exception occurs during a subrequest to fetch the newly
* created file entity.
*/
public function handleFileUploadForExistingResource(Request $request, ResourceType $resource_type, $file_field_name, FieldableEntityInterface $entity) {
$file_field_name = $resource_type
->getInternalName($file_field_name);
$field_definition = $this
->validateAndLoadFieldDefinition($resource_type
->getEntityTypeId(), $resource_type
->getBundle(), $file_field_name);
static::ensureFileUploadAccess($this->currentUser, $field_definition, $entity);
$filename = $this->fileUploader
->validateAndParseContentDispositionHeader($request);
$file = $this->fileUploader
->handleFileUploadForField($field_definition, $filename, $this->currentUser);
if ($file instanceof EntityConstraintViolationListInterface) {
$violations = $file;
$message = "Unprocessable Entity: file validation failed.\n";
$message .= implode("\n", array_map(function (ConstraintViolationInterface $violation) {
return PlainTextOutput::renderFromHtml($violation
->getMessage());
}, (array) $violations
->getIterator()));
throw new UnprocessableEntityHttpException($message);
}
if ($resource_type
->getFieldByInternalName($file_field_name)
->hasOne()) {
$entity->{$file_field_name} = $file;
}
else {
$entity
->get($file_field_name)
->appendItem($file);
}
static::validate($entity, [
$file_field_name,
]);
$entity
->save();
$route_parameters = [
'entity' => $entity
->uuid(),
];
$route_name = sprintf('jsonapi.%s.%s.related', $resource_type
->getTypeName(), $resource_type
->getPublicName($file_field_name));
$related_url = Url::fromRoute($route_name, $route_parameters)
->toString(TRUE);
$request = Request::create($related_url
->getGeneratedUrl(), 'GET', [], $request->cookies
->all(), [], $request->server
->all());
return $this->httpKernel
->handle($request, HttpKernelInterface::SUB_REQUEST);
}
/**
* Handles JSON:API file upload requests.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HTTP request object.
* @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
* The JSON:API resource type for the current request.
* @param string $file_field_name
* The file field for which the file is to be uploaded.
*
* @return \Drupal\jsonapi\ResourceResponse
* The response object.
*
* @throws \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException
* Thrown when there are validation errors.
*/
public function handleFileUploadForNewResource(Request $request, ResourceType $resource_type, $file_field_name) {
$file_field_name = $resource_type
->getInternalName($file_field_name);
$field_definition = $this
->validateAndLoadFieldDefinition($resource_type
->getEntityTypeId(), $resource_type
->getBundle(), $file_field_name);
static::ensureFileUploadAccess($this->currentUser, $field_definition);
$filename = $this->fileUploader
->validateAndParseContentDispositionHeader($request);
$file = $this->fileUploader
->handleFileUploadForField($field_definition, $filename, $this->currentUser);
if ($file instanceof EntityConstraintViolationListInterface) {
$violations = $file;
$message = "Unprocessable Entity: file validation failed.\n";
$message .= implode("\n", array_map(function (ConstraintViolationInterface $violation) {
return PlainTextOutput::renderFromHtml($violation
->getMessage());
}, iterator_to_array($violations)));
throw new UnprocessableEntityHttpException($message);
}
// @todo Remove line below in favor of commented line in https://www.drupal.org/project/drupal/issues/2878463.
$self_link = new Link(new CacheableMetadata(), Url::fromRoute('jsonapi.file--file.individual', [
'entity' => $file
->uuid(),
]), 'self');
/* $self_link = new Link(new CacheableMetadata(), $this->entity->toUrl('jsonapi'), ['self']); */
$links = new LinkCollection([
'self' => $self_link,
]);
$relatable_resource_types = $resource_type
->getRelatableResourceTypesByField($resource_type
->getPublicName($file_field_name));
$file_resource_type = reset($relatable_resource_types);
$resource_object = ResourceObject::createFromEntity($file_resource_type, $file);
return new ResourceResponse(new JsonApiDocumentTopLevel(new ResourceObjectData([
$resource_object,
], 1), new NullIncludedData(), $links), 201, []);
}
/**
* Ensures that the given account is allowed to upload a file.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The account for which access should be checked.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field for which the file is to be uploaded.
* @param \Drupal\Core\Entity\FieldableEntityInterface|null $entity
* The entity, if one exists, for which the file is to be uploaded.
*/
protected static function ensureFileUploadAccess(AccountInterface $account, FieldDefinitionInterface $field_definition, FieldableEntityInterface $entity = NULL) {
$access_result = $entity ? TemporaryJsonapiFileFieldUploader::checkFileUploadAccess($account, $field_definition, $entity) : TemporaryJsonapiFileFieldUploader::checkFileUploadAccess($account, $field_definition);
if (!$access_result
->isAllowed()) {
$reason = 'The current user is not permitted to upload a file for this field.';
if ($access_result instanceof AccessResultReasonInterface) {
$reason .= ' ' . $access_result
->getReason();
}
throw new AccessDeniedHttpException($reason);
}
}
/**
* Validates and loads a field definition instance.
*
* @param string $entity_type_id
* The entity type ID the field is attached to.
* @param string $bundle
* The bundle the field is attached to.
* @param string $field_name
* The field name.
*
* @return \Drupal\Core\Field\FieldDefinitionInterface
* The field definition.
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* Thrown when the field does not exist.
* @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException
* Thrown when the target type of the field is not a file, or the current
* user does not have 'edit' access for the field.
*/
protected function validateAndLoadFieldDefinition($entity_type_id, $bundle, $field_name) {
$field_definitions = $this->fieldManager
->getFieldDefinitions($entity_type_id, $bundle);
if (!isset($field_definitions[$field_name])) {
throw new NotFoundHttpException(sprintf('Field "%s" does not exist.', $field_name));
}
/** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
$field_definition = $field_definitions[$field_name];
if ($field_definition
->getSetting('target_type') !== 'file') {
throw new AccessDeniedException(sprintf('"%s" is not a file field', $field_name));
}
return $field_definition;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityValidationTrait:: |
protected static | function | Verifies that an entity does not violate any validation constraints. | |
FileUpload:: |
protected | property | The current user making the request. | |
FileUpload:: |
protected | property | The field manager. | |
FileUpload:: |
protected | property | The file uploader. | |
FileUpload:: |
protected | property | An HTTP kernel for making subrequests. | |
FileUpload:: |
protected static | function | Ensures that the given account is allowed to upload a file. | |
FileUpload:: |
public | function | Handles JSON:API file upload requests. | |
FileUpload:: |
public | function | Handles JSON:API file upload requests. | |
FileUpload:: |
protected | function | Validates and loads a field definition instance. | |
FileUpload:: |
public | function | Creates a new FileUpload instance. |