Change record status: 
Project: 
Introduced in branch: 
10.2.x
Introduced in version: 
10.2.0
Description: 

API Changes

file_validate and related functions are deprecated and replaced with Constraint plugins and a 'file.validator' service.

Before:

$validators = ['file_name_length' => []];
/** @var string[] $errors */
$errors = file_validate($file, $validators)

After:

$validators = ['FileNameLength' => []];
/** @var \Drupal\file\Validation\FileValidatorInterface $file_validator */
$file_validator = \Drupal::service('file.validator');
/** @var \Symfony\Component\Validator\ConstraintViolationListInterface $violations */
$violations = $file_validator->validate($file, $validators);

Constraints and their validators are located in the \Drupal\file\Plugin\Validation\Constraint namespace.

Form API changes

The Form API file validation structure for #upload_validators has changed from taking a function name and a list of arguments, to a Constraint Plugin ID and an associative array of options. Passing arbitrary data as part of #upload_validators has been deprecated in 10.2.x and will be disallowed in 11.x. A valid validator plugin ID must be provided.

The following examples show the mapping from file_validate_* functions to constraint plugins.

Before After
'file_validate_extensions' => ['gif png jpg jpeg'] 'FileExtension' => ['extensions' => 'gif png jpg jpeg']
'file_validate_size' => [$max_filesize] 'FileSizeLimit' => ['fileLimit' => $max_filesize]
'file_validate_name_length' => [] 'FileNameLength' => []
'file_validate_is_image' => [] 'FileIsImage' => []
'file_validate_image_resolution' => [$max_dimensions] 'FileImageDimensions' => ['maxDimensions' => $max_dimensions]

In addition a new constraint FileExtensionSecure is always called by FileValidator::validate() to block insecure file uploads.

You can write your own constraint and validator plugin. It will be loaded using the standard plugin discovery mechanism.

Hook Deprecation and New Event

hook_file_validate is deprecated and replaced with a \Drupal\file\Validation\FileValidationEvent that is dispatched by \Drupal\file\Validation\FileValidator::validate() .

Implement an EventSubscriber to add your custom validation code that can add to the ConstraintViolationList.

Additional Changes

The method signature for \Drupal\ckeditor5\Controller\CKEditor5ImageController::prepareFilename() has changed from:

protected function prepareFilename($filename, array &$validators)
to:
protected function prepareFilename(string $filename, string $allowed_extensions): string

Impacts: 
Module developers

Comments

shelane’s picture

The before and after listed above are not equivalent. The actual file_validate function processes the errors from the service and returns an array. So, if that's the data you were expecting, you will now get errors related to the returned data. So the after really needs to look like this to be equivalent:

$validators = ['FileNameLength' => []];
/** @var \Drupal\file\Validation\FileValidatorInterface $file_validator */
$file_validator = \Drupal::service('file.validator');
/** @var \Symfony\Component\Validator\ConstraintViolationListInterface $violations */
$violations = $file_validator->validate($file, $validators);

$errors = [];
foreach ($violations as $violation) {
  $errors[] = $violation->getMessage();
}
abhinavp’s picture

Helpful

klemendev’s picture

Seems ClamAV module broke in some cases - https://www.drupal.org/project/clamav/issues/3503176 - after replacing hook_file_validate with FileValidationEvent