diff --git a/modules/foxml_file_validation/README.md b/modules/foxml_file_validation/README.md new file mode 100644 index 0000000..481b653 --- /dev/null +++ b/modules/foxml_file_validation/README.md @@ -0,0 +1,23 @@ +# FOXML File Validation + +## Introduction + +In migrations, we provide URIs in the `foxml://` scheme which do not have +meaningful file extensions, such as: + +- `foxml://object/some:pid`; or, +- `foxml://datastream/some:pid+DSID+DSID.0` + +Given these are served from a dedicated endpoint and the usual extension +validation does not have anything meaningful to work with, this module wraps +the base `FileExtension` validation such that it is bypassed when the `uri` of +the underlying file entity has the `foxml://` scheme. File _not_ in the +`foxml://` scheme should continue to validate extensions unchanged. + +## Installation + +Enable the (sub)module. + +## Configuration + +None. diff --git a/modules/foxml_file_validation/foxml_file_validation.info.yml b/modules/foxml_file_validation/foxml_file_validation.info.yml new file mode 100644 index 0000000..3fe3058 --- /dev/null +++ b/modules/foxml_file_validation/foxml_file_validation.info.yml @@ -0,0 +1,8 @@ +--- +name: 'FOXML File Validation' +description: "Extended file validation to allow " +type: module +package: DGI +core_version_requirement: ^10.2 +dependencies: + - foxml:foxml diff --git a/modules/foxml_file_validation/foxml_file_validation.module b/modules/foxml_file_validation/foxml_file_validation.module new file mode 100644 index 0000000..dc09401 --- /dev/null +++ b/modules/foxml_file_validation/foxml_file_validation.module @@ -0,0 +1,16 @@ +options = $options; + } + + /** + * {@inheritDoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + constraintManager: $container->get('validation.constraint'), + options: $configuration, + ); + } + + /** + * Get the wrapped constraint. + * + * @return \Symfony\Component\Validator\Constraint + * The wrapped constraint. + */ + public function getWrappedConstraint() : Constraint { + return $this->wrapped ??= $this->constraintManager->create('FoxmlFileValidationOriginalFileExtension', $this->options); + } + +} diff --git a/modules/foxml_file_validation/src/Plugin/Validation/Constraint/FoxmlFileExtensionBypassConstraintValidator.php b/modules/foxml_file_validation/src/Plugin/Validation/Constraint/FoxmlFileExtensionBypassConstraintValidator.php new file mode 100644 index 0000000..0ffde6e --- /dev/null +++ b/modules/foxml_file_validation/src/Plugin/Validation/Constraint/FoxmlFileExtensionBypassConstraintValidator.php @@ -0,0 +1,73 @@ +assertValueIsFile($value); + if (!$constraint instanceof FoxmlFileExtensionBypassConstraint) { + throw new UnexpectedTypeException($constraint, FoxmlFileExtensionBypassConstraint::class); + } + + if ($this->streamWrapperManager::getScheme($file->getFileUri()) === 'foxml') { + return; + } + + $wrapped_constraint = $constraint->getWrappedConstraint(); + $wrapped_validator = $this->getConstraintValueFactory()->getInstance($wrapped_constraint); + $wrapped_validator->initialize($this->context); + $wrapped_validator->validate($value, $wrapped_constraint); + } + + /** + * {@inheritDoc} + */ + public static function create(ContainerInterface $container) : static { + return new static( + $container->get('stream_wrapper_manager'), + $container->get('class_resolver'), + ); + } + + /** + * Lazily instantiate constraint validator factory. + * + * @return \Drupal\Core\Validation\ConstraintValidatorFactory + * Constraint validator factory service. + */ + protected function getConstraintValueFactory() : ConstraintValidatorFactory { + return $this->constraintValidatorFactory ??= new ConstraintValidatorFactory($this->classResolver); + } + +}