From c8cc155dadc8cc9afa257106f739f4e8a4c3e669 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Mon, 21 Sep 2020 15:56:32 +0100 Subject: [PATCH] Issue #3055193 by catch, martin107, jungle, mikelutz, longwave, andypost, alexpott, mondrake, tim.plunkett, larowlan: [Symfony 5] The "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\MimeTypes" instead --- core/core.services.yml | 2 - core/lib/Drupal/Core/CoreServiceProvider.php | 2 + .../Compiler/MimeTypePass.php | 77 +++++++++++++++++++ .../MimeType/ExtensionMimeTypeGuesser.php | 20 ++++- .../Core/File/MimeType/MimeTypeGuesser.php | 51 ++++++++++-- core/lib/Drupal/Core/File/file.api.php | 7 +- .../MimeType/ExtensionMimeTypeGuesser.php | 18 ++++- .../File/MimeType/MimeTypeGuesser.php | 26 ++++++- core/modules/file/file.module | 10 ++- core/modules/file/src/Entity/File.php | 10 ++- .../FieldFormatter/FileMediaFormatterBase.php | 12 ++- .../rest/resource/FileUploadResource.php | 16 ++-- .../src/Plugin/Field/FieldType/ImageItem.php | 10 ++- .../TemporaryJsonapiFileFieldUploader.php | 16 ++-- .../responsive_image/responsive_image.module | 8 +- .../system/src/Form/ThemeSettingsForm.php | 16 ++-- .../KernelTests/Core/File/MimeTypeTest.php | 29 +++++-- .../Compiler/MimeTypePassTest.php | 63 +++++++++++++++ .../Listeners/DeprecationListenerTrait.php | 1 + 19 files changed, 350 insertions(+), 44 deletions(-) create mode 100644 core/lib/Drupal/Core/DependencyInjection/Compiler/MimeTypePass.php create mode 100644 core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/MimeTypePassTest.php diff --git a/core/core.services.yml b/core/core.services.yml index 88e760c4892f..5d01d8766705 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1656,8 +1656,6 @@ services: file.mime_type.guesser: class: Drupal\Core\File\MimeType\MimeTypeGuesser arguments: ['@stream_wrapper_manager'] - tags: - - { name: service_collector, tag: mime_type_guesser, call: addGuesser } lazy: true file.mime_type.guesser.extension: class: Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index e07046ae0ab8..8eb6c04d695c 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -19,6 +19,7 @@ use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; +use Drupal\Core\DependencyInjection\Compiler\MimeTypePass; use Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterEventSubscribersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass; @@ -73,6 +74,7 @@ public function register(ContainerBuilder $container) { // Collect tagged handler services as method calls on consumer services. $container->addCompilerPass(new TaggedHandlersPass()); + $container->addCompilerPass(new MimeTypePass()); $container->addCompilerPass(new RegisterStreamWrappersPass()); $container->addCompilerPass(new GuzzleMiddlewarePass()); diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/MimeTypePass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/MimeTypePass.php new file mode 100644 index 000000000000..f20edc0956d6 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/MimeTypePass.php @@ -0,0 +1,77 @@ +<?php + +namespace Drupal\Core\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\LogicException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface as LegacyMimeTypeGuesserInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface; + +/** + * Adds @mime_type_guesser tagged services to handle forwards compatibility. + * + * @internal + * + * @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. No direct + * replacement is provided. + * + * @see https://www.drupal.org/node/3133341 + */ +class MimeTypePass implements CompilerPassInterface { + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) { + $consumer = $container->getDefinition('file.mime_type.guesser'); + + $tag = 'mime_type_guesser'; + $interface = MimeTypeGuesserInterface::class; + $deprecated_interface = LegacyMimeTypeGuesserInterface::class; + + // Find all tagged handlers. + $handlers = []; + foreach ($container->findTaggedServiceIds($tag) as $id => $attributes) { + // Validate the interface. + $handler = $container->getDefinition($id); + if (!is_subclass_of($handler->getClass(), $interface)) { + // Special handling for $deprecated_interface. + if (!is_subclass_of($handler->getClass(), $deprecated_interface)) { + throw new LogicException("Service '$id' does not implement $interface."); + } + } + $handlers[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $interfaces[$id] = $handler->getClass(); + } + if (empty($handlers)) { + throw new LogicException(sprintf("At least one service tagged with '%s' is required.", $tag)); + } + + // Sort all handlers by priority. + arsort($handlers, SORT_NUMERIC); + + // Add a method call for each handler to the consumer service + // definition. + foreach ($handlers as $id => $priority) { + $arguments = []; + $arguments[0] = new Reference($id); + if (isset($priority_pos)) { + $arguments[$priority_pos] = $priority; + } + if (isset($id_pos)) { + $arguments[$id_pos] = $id; + } + // Sort the arguments by position. + ksort($arguments); + if (is_subclass_of($interfaces[$id], $interface)) { + $consumer->addMethodCall('addMimeTypeGuesser', $arguments); + } + else { + $consumer->addMethodCall('addGuesser', $arguments); + } + } + } + +} diff --git a/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php b/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php index 056f62792faa..b0798000aac0 100644 --- a/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php +++ b/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php @@ -3,12 +3,13 @@ namespace Drupal\Core\File\MimeType; use Drupal\Core\Extension\ModuleHandlerInterface; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; +use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface as LegacyMimeTypeGuesserInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Makes possible to guess the MIME type of a file using its extension. */ -class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface { +class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface, LegacyMimeTypeGuesserInterface { /** * Default MIME extension mapping. @@ -889,6 +890,14 @@ public function __construct(ModuleHandlerInterface $module_handler) { * {@inheritdoc} */ public function guess($path) { + @trigger_error(__METHOD__ . '() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use ::guessMimeType() instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + return $this->guessMimeType($path); + } + + /** + * {@inheritdoc} + */ + public function guessMimeType($path): ?string { if ($this->mapping === NULL) { $mapping = $this->defaultMapping; // Allow modules to alter the default mapping. @@ -927,4 +936,11 @@ public function setMapping(array $mapping = NULL) { $this->mapping = $mapping; } + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool { + return TRUE; + } + } diff --git a/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php index ff149b8f9510..d42f7ab90158 100644 --- a/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php +++ b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php @@ -5,12 +5,13 @@ use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser as SymfonyMimeTypeGuesser; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; +use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface as LegacyMimeTypeGuesserInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface as MimeTypeGuesserInterface; /** * Defines a MIME type guesser that also supports stream wrapper paths. */ -class MimeTypeGuesser implements MimeTypeGuesserInterface { +class MimeTypeGuesser implements LegacyMimeTypeGuesserInterface, MimeTypeGuesserInterface { /** * An array of arrays of registered guessers keyed by priority. @@ -51,7 +52,7 @@ public function __construct(StreamWrapperManagerInterface $stream_wrapper_manage /** * {@inheritdoc} */ - public function guess($path) { + public function guessMimeType(string $path) : ?string { if ($wrapper = $this->streamWrapperManager->getViaUri($path)) { // Get the real path from the stream wrapper, if available. Files stored // in remote file systems will not have one. @@ -67,13 +68,40 @@ public function guess($path) { } foreach ($this->sortedGuessers as $guesser) { - $mime_type = $guesser->guess($path); + $mime_type = $guesser->guessMimeType($path); if ($mime_type !== NULL) { return $mime_type; } } } + /** + * {@inheritdoc} + */ + public function guess($path) { + @trigger_error(__METHOD__ . '() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use ::guessMimeType() instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + return $this->guessMimeType($path); + } + + /** + * Appends a MIME type guesser to the guessers chain. + * + * @param \Symfony\Component\Mime\MimeTypeGuesserInterface $guesser + * The guesser to be appended. + * @param int $priority + * The priority of the guesser being added. + * + * @return $this + */ + public function addMimeTypeGuesser(MimeTypeGuesserInterface $guesser, $priority = 0) { + if ($guesser->isGuesserSupported()) { + $this->guessers[$priority][] = $guesser; + // Mark sorted guessers for rebuild. + $this->sortedGuessers = NULL; + } + return $this; + } + /** * Appends a MIME type guesser to the guessers chain. * @@ -83,14 +111,27 @@ public function guess($path) { * The priority of the guesser being added. * * @return $this + * + * @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use + * ::addMimeTypeGuesser() instead. + * + * @see https://www.drupal.org/node/3133341 */ - public function addGuesser(MimeTypeGuesserInterface $guesser, $priority = 0) { + public function addGuesser(LegacyMimeTypeGuesserInterface $guesser, $priority = 0) { + @trigger_error(__METHOD__ . ' is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use ::addMimeTypeGuesser() instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); $this->guessers[$priority][] = $guesser; // Mark sorted guessers for rebuild. $this->sortedGuessers = NULL; return $this; } + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool { + return TRUE; + } + /** * Sorts guessers according to priority. * diff --git a/core/lib/Drupal/Core/File/file.api.php b/core/lib/Drupal/Core/File/file.api.php index 6c5236fec9f7..26501ff8a776 100644 --- a/core/lib/Drupal/Core/File/file.api.php +++ b/core/lib/Drupal/Core/File/file.api.php @@ -108,8 +108,9 @@ function hook_file_url_alter(&$uri) { /** * Alter MIME type mappings used to determine MIME type from a file extension. * - * Invoked by \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::guess(). It - * is used to allow modules to add to or modify the default mapping from + * Invoked by + * \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::guessMimeType(). It is + * used to allow modules to add to or modify the default mapping from * \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::$defaultMapping. * * @param $mapping @@ -117,7 +118,7 @@ function hook_file_url_alter(&$uri) { * The array has 'mimetypes' and 'extensions' elements, each of which is an * array. * - * @see \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::guess() + * @see \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::guessMimeType() * @see \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser::$defaultMapping */ function hook_file_mimetype_mapping_alter(&$mapping) { diff --git a/core/lib/Drupal/Core/ProxyClass/File/MimeType/ExtensionMimeTypeGuesser.php b/core/lib/Drupal/Core/ProxyClass/File/MimeType/ExtensionMimeTypeGuesser.php index ccaa8cc0c4ee..d3f3fef6ebbc 100644 --- a/core/lib/Drupal/Core/ProxyClass/File/MimeType/ExtensionMimeTypeGuesser.php +++ b/core/lib/Drupal/Core/ProxyClass/File/MimeType/ExtensionMimeTypeGuesser.php @@ -12,7 +12,7 @@ * * @see \Drupal\Component\ProxyBuilder */ - class ExtensionMimeTypeGuesser implements \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface + class ExtensionMimeTypeGuesser implements \Symfony\Component\Mime\MimeTypeGuesserInterface, \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface { use \Drupal\Core\DependencyInjection\DependencySerializationTrait; @@ -75,6 +75,14 @@ public function guess($path) return $this->lazyLoadItself()->guess($path); } + /** + * {@inheritdoc} + */ + public function guessMimeType($path): string + { + return $this->lazyLoadItself()->guessMimeType($path); + } + /** * {@inheritdoc} */ @@ -83,6 +91,14 @@ public function setMapping(array $mapping = NULL) return $this->lazyLoadItself()->setMapping($mapping); } + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + return $this->lazyLoadItself()->isGuesserSupported(); + } + } } diff --git a/core/lib/Drupal/Core/ProxyClass/File/MimeType/MimeTypeGuesser.php b/core/lib/Drupal/Core/ProxyClass/File/MimeType/MimeTypeGuesser.php index 02f21c5230aa..bbc8b16e32ea 100644 --- a/core/lib/Drupal/Core/ProxyClass/File/MimeType/MimeTypeGuesser.php +++ b/core/lib/Drupal/Core/ProxyClass/File/MimeType/MimeTypeGuesser.php @@ -12,7 +12,7 @@ * * @see \Drupal\Component\ProxyBuilder */ - class MimeTypeGuesser implements \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface + class MimeTypeGuesser implements \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface, \Symfony\Component\Mime\MimeTypeGuesserInterface { use \Drupal\Core\DependencyInjection\DependencySerializationTrait; @@ -67,6 +67,14 @@ protected function lazyLoadItself() return $this->service; } + /** + * {@inheritdoc} + */ + public function guessMimeType(string $path): string + { + return $this->lazyLoadItself()->guessMimeType($path); + } + /** * {@inheritdoc} */ @@ -75,6 +83,14 @@ public function guess($path) return $this->lazyLoadItself()->guess($path); } + /** + * {@inheritdoc} + */ + public function addMimeTypeGuesser($guesser, $priority = 0) + { + return $this->lazyLoadItself()->addMimeTypeGuesser($guesser, $priority); + } + /** * {@inheritdoc} */ @@ -83,6 +99,14 @@ public function addGuesser(\Symfony\Component\HttpFoundation\File\MimeType\MimeT return $this->lazyLoadItself()->addGuesser($guesser, $priority); } + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + return $this->lazyLoadItself()->isGuesserSupported(); + } + /** * {@inheritdoc} */ diff --git a/core/modules/file/file.module b/core/modules/file/file.module index d63f1e856d92..18eecb71257f 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -23,6 +23,7 @@ use Drupal\Component\Utility\Unicode; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Template\Attribute; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * The regex pattern used when checking for insecure file types. @@ -945,7 +946,14 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va 'uri' => $file_info->getRealPath(), 'filesize' => $file_info->getSize(), ]; - $values['filemime'] = \Drupal::service('file.mime_type.guesser')->guess($values['filename']); + $guesser = \Drupal::service('file.mime_type.guesser'); + if ($guesser instanceof MimeTypeGuesserInterface) { + $values['filemime'] = $guesser->guessMimeType($values['filename']); + } + else { + $values['filemime'] = $guesser->guess($values['filename']); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } $file = File::create($values); $extensions = ''; diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php index 6332ca32aaef..e707b9ae4f84 100644 --- a/core/modules/file/src/Entity/File.php +++ b/core/modules/file/src/Entity/File.php @@ -10,6 +10,7 @@ use Drupal\Core\File\Exception\FileException; use Drupal\file\FileInterface; use Drupal\user\EntityOwnerTrait; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Defines the file entity class. @@ -160,7 +161,14 @@ public static function preCreate(EntityStorageInterface $storage, array &$values // Automatically detect filemime if not set. if (!isset($values['filemime']) && isset($values['uri'])) { - $values['filemime'] = \Drupal::service('file.mime_type.guesser')->guess($values['uri']); + $guesser = \Drupal::service('file.mime_type.guesser'); + if ($guesser instanceof MimeTypeGuesserInterface) { + $values['filemime'] = $guesser->guessMimeType($values['uri']); + } + else { + $values['filemime'] = $guesser->guess($values['uri']); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } } } diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/FileMediaFormatterBase.php b/core/modules/file/src/Plugin/Field/FieldFormatter/FileMediaFormatterBase.php index 72192d6295ec..d69ab74005ab 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/FileMediaFormatterBase.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/FileMediaFormatterBase.php @@ -8,6 +8,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Template\Attribute; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Base class for media file formatter. @@ -75,13 +76,18 @@ public static function isApplicable(FieldDefinitionInterface $field_definition) if (!parent::isApplicable($field_definition)) { return FALSE; } - /** @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $extension_mime_type_guesser */ + /** @var \Symfony\Component\Mime\MimeTypeGuesserInterface $extension_mime_type_guesser */ $extension_mime_type_guesser = \Drupal::service('file.mime_type.guesser.extension'); $extension_list = array_filter(preg_split('/\s+/', $field_definition->getSetting('file_extensions'))); foreach ($extension_list as $extension) { - $mime_type = $extension_mime_type_guesser->guess('fakedFile.' . $extension); - + if ($extension_mime_type_guesser instanceof MimeTypeGuesserInterface) { + $mime_type = $extension_mime_type_guesser->guessMimeType('fakedFile.' . $extension); + } + else { + $mime_type = $extension_mime_type_guesser->guess('fakedFile.' . $extension); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } if (static::mimeTypeApplies($mime_type)) { return TRUE; } diff --git a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php index 9127da760440..1aaa5a753bad 100644 --- a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php +++ b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php @@ -23,11 +23,11 @@ use Drupal\rest\RequestHandler; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; +use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Routing\Route; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -103,7 +103,7 @@ class FileUploadResource extends ResourceBase { /** * The MIME type guesser. * - * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface + * @var \Symfony\Component\Mime\MimeTypeGuesserInterface */ protected $mimeTypeGuesser; @@ -147,7 +147,7 @@ class FileUploadResource extends ResourceBase { * The entity field manager. * @param \Drupal\Core\Session\AccountInterface $current_user * The currently authenticated user. - * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser + * @param \Symfony\Component\Mime\MimeTypeGuesserInterface $mime_type_guesser * The MIME type guesser. * @param \Drupal\Core\Utility\Token $token * The token replacement instance. @@ -156,7 +156,7 @@ class FileUploadResource extends ResourceBase { * @param \Drupal\Core\Config\Config $system_file_config * The system file configuration. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, $serializer_formats, LoggerInterface $logger, FileSystemInterface $file_system, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, AccountInterface $current_user, MimeTypeGuesserInterface $mime_type_guesser, Token $token, LockBackendInterface $lock, Config $system_file_config) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, $serializer_formats, LoggerInterface $logger, FileSystemInterface $file_system, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, AccountInterface $current_user, $mime_type_guesser, Token $token, LockBackendInterface $lock, Config $system_file_config) { parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger); $this->fileSystem = $file_system; $this->entityTypeManager = $entity_type_manager; @@ -254,7 +254,13 @@ public function post(Request $request, $entity_type_id, $bundle, $field_name) { $file = File::create([]); $file->setOwnerId($this->currentUser->id()); $file->setFilename($prepared_filename); - $file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename)); + if ($this->mimeTypeGuesser instanceof MimeTypeGuesserInterface) { + $file->setMimeType($this->mimeTypeGuesser->guessMimeType($prepared_filename)); + } + else { + $file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename)); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } $file->setFileUri($file_uri); // Set the size. This is done in File::preSave() but we validate the file // before it is saved. diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php index e462dc6f7258..8f80ef6f46de 100644 --- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php +++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php @@ -13,6 +13,7 @@ use Drupal\Core\TypedData\DataDefinition; use Drupal\file\Entity\File; use Drupal\file\Plugin\Field\FieldType\FileItem; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Plugin implementation of the 'image' field type. @@ -351,7 +352,14 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin $image = File::create(); $image->setFileUri($path); $image->setOwnerId(\Drupal::currentUser()->id()); - $image->setMimeType(\Drupal::service('file.mime_type.guesser')->guess($path)); + $guesser = \Drupal::service('file.mime_type.guesser'); + if ($guesser instanceof MimeTypeGuesserInterface) { + $image->setMimeType($guesser->guessMimeType($path)); + } + else { + $image->setMimeType($guesser->guess($path)); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } $image->setFileName($file_system->basename($path)); $destination_dir = static::doGetUploadLocation($settings); $file_system->prepareDirectory($destination_dir, FileSystemInterface::CREATE_DIRECTORY); diff --git a/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php b/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php index 5d63fb9bbe7f..8ebeaf870df8 100644 --- a/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php +++ b/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php @@ -21,10 +21,10 @@ use Drupal\file\Entity\File; use Drupal\file\Plugin\Field\FieldType\FileFieldItemList; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\HttpException; +use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Validator\ConstraintViolation; /** @@ -73,7 +73,7 @@ class TemporaryJsonapiFileFieldUploader { /** * The MIME type guesser. * - * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface + * @var \Symfony\Component\Mime\MimeTypeGuesserInterface */ protected $mimeTypeGuesser; @@ -105,7 +105,7 @@ class TemporaryJsonapiFileFieldUploader { * A logger instance. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system service. - * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser + * @param \Symfony\Component\Mime\MimeTypeGuesserInterface $mime_type_guesser * The MIME type guesser. * @param \Drupal\Core\Utility\Token $token * The token replacement instance. @@ -114,7 +114,7 @@ class TemporaryJsonapiFileFieldUploader { * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. */ - public function __construct(LoggerInterface $logger, FileSystemInterface $file_system, MimeTypeGuesserInterface $mime_type_guesser, Token $token, LockBackendInterface $lock, ConfigFactoryInterface $config_factory) { + public function __construct(LoggerInterface $logger, FileSystemInterface $file_system, $mime_type_guesser, Token $token, LockBackendInterface $lock, ConfigFactoryInterface $config_factory) { $this->logger = $logger; $this->fileSystem = $file_system; $this->mimeTypeGuesser = $mime_type_guesser; @@ -173,7 +173,13 @@ public function handleFileUploadForField(FieldDefinitionInterface $field_definit $file = File::create([]); $file->setOwnerId($owner->id()); $file->setFilename($prepared_filename); - $file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename)); + if ($this->mimeTypeGuesser instanceof MimeTypeGuesserInterface) { + $file->setMimeType($this->mimeTypeGuesser->guessMimeType($prepared_filename)); + } + else { + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + $file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename)); + } $file->setFileUri($file_uri); // Set the size. This is done in File::preSave() but we validate the file // before it is saved. diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module index 36ea84d2b15f..566737104240 100644 --- a/core/modules/responsive_image/responsive_image.module +++ b/core/modules/responsive_image/responsive_image.module @@ -13,6 +13,7 @@ use Drupal\responsive_image\Entity\ResponsiveImageStyle; use Drupal\responsive_image\ResponsiveImageStyleInterface; use Drupal\breakpoint\BreakpointInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Implements hook_help(). @@ -477,7 +478,12 @@ function responsive_image_get_mime_type($image_style_name, $extension) { else { $fake_path = 'responsive_image.' . ImageStyle::load($image_style_name)->getDerivativeExtension($extension); } - return Drupal::service('file.mime_type.guesser.extension')->guess($fake_path); + $guesser = \Drupal::service('file.mime_type.guesser.extension'); + if (!$guesser instanceof MimeTypeGuesserInterface) { + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + return $guesser->guess($fake_path); + } + return $guesser->guessMimeType($fake_path); } /** diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php index 46885f25f7cd..e863c0f80594 100644 --- a/core/modules/system/src/Form/ThemeSettingsForm.php +++ b/core/modules/system/src/Form/ThemeSettingsForm.php @@ -10,12 +10,12 @@ use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\StreamWrapperManager; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Theme\ThemeManagerInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface; /** * Displays theme configuration for entire site and individual themes. @@ -41,7 +41,7 @@ class ThemeSettingsForm extends ConfigFormBase { /** * The MIME type guesser. * - * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface + * @var \Symfony\Component\Mime\MimeTypeGuesserInterface */ protected $mimeTypeGuesser; @@ -75,14 +75,14 @@ class ThemeSettingsForm extends ConfigFormBase { * The module handler instance to use. * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. - * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser + * @param \Symfony\Component\Mime\MimeTypeGuesserInterface $mime_type_guesser * The MIME type guesser instance to use. * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager * The theme manager. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system. */ - public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, MimeTypeGuesserInterface $mime_type_guesser, ThemeManagerInterface $theme_manager, FileSystemInterface $file_system) { + public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, $mime_type_guesser, ThemeManagerInterface $theme_manager, FileSystemInterface $file_system) { parent::__construct($config_factory); $this->moduleHandler = $module_handler; @@ -494,7 +494,13 @@ public function submitForm(array &$form, FormStateInterface $form_state) { } if (empty($values['default_favicon']) && !empty($values['favicon_path'])) { - $values['favicon_mimetype'] = $this->mimeTypeGuesser->guess($values['favicon_path']); + if ($this->mimeTypeGuesser instanceof MimeTypeGuesserInterface) { + $values['favicon_mimetype'] = $this->mimeTypeGuesser->guessMimeType($values['favicon_path']); + } + else { + $values['favicon_mimetype'] = $this->mimeTypeGuesser->guess($values['favicon_path']); + @trigger_error('\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Implement \Symfony\Component\Mime\MimeTypeGuesserInterface instead. See https://www.drupal.org/node/3133341', E_USER_DEPRECATED); + } } theme_settings_convert_to_config($values, $config)->save(); diff --git a/core/tests/Drupal/KernelTests/Core/File/MimeTypeTest.php b/core/tests/Drupal/KernelTests/Core/File/MimeTypeTest.php index 40f278b2b99f..1099dd0656df 100644 --- a/core/tests/Drupal/KernelTests/Core/File/MimeTypeTest.php +++ b/core/tests/Drupal/KernelTests/Core/File/MimeTypeTest.php @@ -2,8 +2,6 @@ namespace Drupal\KernelTests\Core\File; -use Drupal\Component\Render\FormattableMarkup; - /** * Tests filename mimetype detection. * @@ -46,13 +44,13 @@ public function testFileMimeTypeDetection() { foreach ($test_case as $input => $expected) { // Test stream [URI]. foreach ($prefixes as $prefix) { - $output = $guesser->guess($prefix . $input); - $this->assertIdentical($output, $expected, new FormattableMarkup('Mimetype for %input is %output (expected: %expected).', ['%input' => $prefix . $input, '%output' => $output, '%expected' => $expected])); + $output = $guesser->guessMimeType($prefix . $input); + $this->assertSame($expected, $output); } // Test normal path equivalent - $output = $guesser->guess($input); - $this->assertIdentical($output, $expected, new FormattableMarkup('Mimetype (using default mappings) for %input is %output (expected: %expected).', ['%input' => $input, '%output' => $output, '%expected' => $expected])); + $output = $guesser->guessMimeType($input); + $this->assertSame($expected, $output); } // Now test the extension guesser by passing in a custom mapping. @@ -86,9 +84,24 @@ public function testFileMimeTypeDetection() { $extension_guesser->setMapping($mapping); foreach ($test_case as $input => $expected) { - $output = $extension_guesser->guess($input); - $this->assertIdentical($output, $expected, new FormattableMarkup('Mimetype (using passed-in mappings) for %input is %output (expected: %expected).', ['%input' => $input, '%output' => $output, '%expected' => $expected])); + $output = $extension_guesser->guessMimeType($input); + $this->assertSame($expected, $output); } } + /** + * Test deprecations. + * + * @group legacy + * @expectedDeprecation The "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\MimeTypes" instead. + * @expectedDeprecation The "Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\FileBinaryMimeTypeGuesser" instead. + * @expectedDeprecation The "Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\FileinfoMimeTypeGuesser" instead. + * @expectedDeprecation Drupal\Core\File\MimeType\MimeTypeGuesser::guess() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use ::guessMimeType() instead. See https://www.drupal.org/node/3133341 + */ + public function testFileMimeTypeDetectionDeprecation() { + $guesser = $this->container->get('file.mime_type.guesser'); + $output = $guesser->guess('public://test.jar'); + $this->assertSame('application/java-archive', $output); + } + } diff --git a/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/MimeTypePassTest.php b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/MimeTypePassTest.php new file mode 100644 index 000000000000..6526135f89ec --- /dev/null +++ b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/MimeTypePassTest.php @@ -0,0 +1,63 @@ +<?php + +namespace Drupal\Tests\Core\DependencyInjection\Compiler; + +use Drupal\Core\DependencyInjection\Compiler\MimeTypePass; +use Drupal\Tests\UnitTestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface as LegacyMimeTypeGuesserInterface; +use Symfony\Component\Mime\MimeTypeGuesserInterface; +use Drupal\Core\File\MimeType\MimeTypeGuesser; + +/** + * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\MimeTypePass + * @group DependencyInjection + * @group legacy + * @runInSeparateProcess + */ +class MimeTypePassTest extends UnitTestCase { + + protected function buildContainer($environment = 'dev') { + $container = new ContainerBuilder(); + $container->setParameter('kernel.environment', $environment); + return $container; + } + + /** + * Tests backwards compatibility shim for MimeTypeGuesser interface changes. + * + * @expectedDeprecation The "Drupal\Tests\Core\DependencyInjection\Compiler\LegacyMimeTypeGuesser" class implements "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface" that is deprecated since Symfony 4.3, use {@link MimeTypesInterface} instead. + */ + public function testProcessLegacy() { + $container = $this->buildContainer(); + $container + ->register('file.mime_type.guesser', MimeTypeGuesser::class); + + $container + ->register('handler1', __NAMESPACE__ . '\NewMimeTypeGuesser') + ->addTag('mime_type_guesser'); + $container + ->register('handler2', __NAMESPACE__ . '\LegacyMimeTypeGuesser') + ->addTag('mime_type_guesser'); + + $handler_pass = new MimeTypePass(); + $handler_pass->process($container); + $method_calls = $container->getDefinition('file.mime_type.guesser')->getMethodCalls(); + $this->assertCount(2, $method_calls); + } + +} + +class NewMimeTypeGuesser implements MimeTypeGuesserInterface { + + public function guessMimeType(string $string): string {} + + public function isGuesserSupported(): bool {} + +} + +class LegacyMimeTypeGuesser implements LegacyMimeTypeGuesserInterface { + + public function guess($string) {} + +} diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php index 1895054764e9..64ffefb87ea1 100644 --- a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php +++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php @@ -107,6 +107,7 @@ public static function getSkippedDeprecations() { 'The "Drupal\Core\File\MimeType\MimeTypeGuesser" class implements "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface" that is deprecated since Symfony 4.3, use {@link MimeTypesInterface} instead.', 'The "Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\FileBinaryMimeTypeGuesser" instead.', 'The "Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\FileinfoMimeTypeGuesser" instead.', + 'The "Drupal\Tests\Core\DependencyInjection\Compiler\LegacyMimeTypeGuesser" class implements "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface" that is deprecated since Symfony 4.3, use {@link MimeTypesInterface} instead.', 'The "Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher::dispatch()" method will require a new "string|null $eventName" argument in the next major version of its interface "Symfony\Contracts\EventDispatcher\EventDispatcherInterface", not defining it is deprecated.', 'The "Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher::dispatch()" method will require a new "string|null $eventName" argument in the next major version of its parent class "Symfony\Contracts\EventDispatcher\EventDispatcherInterface", not defining it is deprecated.', 'Passing a command as string when creating a "Symfony\Component\Process\Process" instance is deprecated since Symfony 4.2, pass it as an array of its arguments instead, or use the "Process::fromShellCommandline()" constructor if you need features provided by the shell.', -- GitLab