Unverified Commit 37737af8 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2311679 by kim.pepper, mondrake, bhanu951, arla, alexpott, ParisLiakos,...

Issue #2311679 by kim.pepper, mondrake, bhanu951, arla, alexpott, ParisLiakos, yogeshmpawar, pcambra, godotislate, mfb, berdir: Separate MIME type mapping from ExtensionMimeTypeGuesser
parent e3894f6a
Loading
Loading
Loading
Loading
Loading
+0 −18
Original line number Diff line number Diff line
@@ -7429,18 +7429,6 @@
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/File/HtaccessWriterInterface.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Core\\\\File\\\\MimeType\\\\ExtensionMimeTypeGuesser\\:\\:setMapping\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Core\\\\File\\\\MimeType\\\\MimeTypeGuesser\\:\\:registerWithSymfonyGuesser\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Core\\\\FileTransfer\\\\ChmodInterface\\:\\:chmodJailed\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
@@ -9399,12 +9387,6 @@
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Core\\\\ProxyClass\\\\File\\\\MimeType\\\\ExtensionMimeTypeGuesser\\:\\:setMapping\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/lib/Drupal/Core/ProxyClass/File/MimeType/ExtensionMimeTypeGuesser.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Core\\\\ProxyClass\\\\File\\\\MimeType\\\\MimeTypeGuesser\\:\\:addMimeTypeGuesser\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
+8 −1
Original line number Diff line number Diff line
@@ -1805,10 +1805,17 @@ services:
    lazy: true
  file.mime_type.guesser.extension:
    class: Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser
    arguments: ['@module_handler']
    arguments: ['@Drupal\Core\File\MimeType\MimeTypeMapInterface', '@file_system']
    tags:
      - { name: mime_type_guesser }
    lazy: true
  Drupal\Core\File\MimeType\MimeTypeMapFactory:
    autowire: true
    public: false
  Drupal\Core\File\MimeType\MimeTypeMapInterface:
    factory: ['@Drupal\Core\File\MimeType\MimeTypeMapFactory', create]
  Drupal\Core\File\EventSubscriber\LegacyMimeTypeMapLoadedSubscriber:
    autowire: true
  # Currently needs to be public as it is called by
  # \Drupal\Core\Render\Element\StatusMessages.
  # @todo Consider making this service private again after
+19 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\File\Event;

use Drupal\Core\File\MimeType\MimeTypeMapInterface;
use Symfony\Contracts\EventDispatcher\Event;

/**
 * Event that is fired when the MIME type map is loaded.
 */
final class MimeTypeMapLoadedEvent extends Event {

  public function __construct(
    public readonly MimeTypeMapInterface $map,
  ) {}

}
+56 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\File\EventSubscriber;

use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\Event\MimeTypeMapLoadedEvent;
use Drupal\Core\File\MimeType\MimeTypeMap;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Modifies the MIME type map by calling hook_file_mimetype_mapping_alter().
 *
 * This event subscriber provides BC support for the deprecated
 * hook_file_mimetype_mapping_alter() and will be removed in drupal:12.0.0.
 *
 * @internal
 *
 * @see https://www.drupal.org/node/3494040
 */
final class LegacyMimeTypeMapLoadedSubscriber implements
  EventSubscriberInterface {

  public function __construct(
    protected readonly ModuleHandlerInterface $moduleHandler,
  ) {}

  /**
   * Handle the event by calling deprecated hook_file_mimetype_mapping_alter().
   */
  public function onMimeTypeMapLoaded(MimeTypeMapLoadedEvent $event): void {
    if (!$event->map instanceof MimeTypeMap) {
      return;
    }
    // @phpstan-ignore-next-line method.deprecated
    $mapping = $event->map->getMapping();
    $this->moduleHandler->alterDeprecated(
      'This hook is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Implement a \Drupal\Core\File\Event\MimeTypeMapLoadedEvent listener instead. See https://www.drupal.org/node/3494040',
      'file_mimetype_mapping',
      $mapping,
    );
    // @phpstan-ignore-next-line method.deprecated
    $event->map->setMapping($mapping);
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
      MimeTypeMapLoadedEvent::class => 'onMimeTypeMapLoaded',
    ];
  }

}
+96 −17
Original line number Diff line number Diff line
@@ -2,19 +2,28 @@

namespace Drupal\Core\File\MimeType;

use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\Event\MimeTypeMapLoadedEvent;
use Drupal\Core\File\FileSystemInterface;
use Symfony\Component\Mime\MimeTypeGuesserInterface;

/**
 * Makes possible to guess the MIME type of a file using its extension.
 */
class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface {
  use DeprecatedServicePropertyTrait;

  /**
   * Default MIME extension mapping.
   *
   * @var array
   *   Array of mimetypes correlated to the extensions that relate to them.
   *
   * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Pass a
   *   MimeTypeMapInterface $map to the constructor instead.
   *
   * @see https://www.drupal.org/node/3494040
   */
  protected $defaultMapping = [
    // cspell:disable
@@ -877,39 +886,86 @@ class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface {
   * The MIME types mapping array after going through the module handler.
   *
   * @var array
   *
   * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Pass a
   *   MimeTypeMapInterface $map to the constructor instead.
   *
   * @see https://www.drupal.org/node/3494040
   */
  protected $mapping;

  /**
   * The module handler.
   * Deprecated service properties.
   *
   * @var string[]
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   * @see https://www.drupal.org/node/3494040
   */
  protected $moduleHandler;
  protected $deprecatedProperties = [
    'moduleHandler' => 'module_handler',
  ];

  /**
   * The MIME type map.
   */
  protected MimeTypeMapInterface $map;

  /**
   * The file system.
   */
  protected FileSystemInterface $fileSystem;

  /**
   * Constructs a new ExtensionMimeTypeGuesser.
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface|\Drupal\Core\File\MimeType\MimeTypeMapInterface $map
   *   The MIME type map.
   * @param \Drupal\Core\File\FileSystemInterface|null $fileSystem
   *   The file system.
   */
  public function __construct(ModuleHandlerInterface $module_handler) {
    $this->moduleHandler = $module_handler;
  public function __construct(
    MimeTypeMapInterface|ModuleHandlerInterface $map,
    ?FileSystemInterface $fileSystem = NULL,
  ) {
    if ($map instanceof ModuleHandlerInterface) {
      @trigger_error(
        'Calling ' . __METHOD__ . '() with the $map argument as an instance of \Drupal\Core\Extension\ModuleHandlerInterface is deprecated in drupal:11.2.0 and an instance of \Drupal\Core\File\MimeType\MimeTypeMapInterface is required in drupal:12.0.0. See https://www.drupal.org/node/3494040',
        E_USER_DEPRECATED
      );
      $map = \Drupal::service(MimeTypeMapInterface::class);
    }
    $this->map = $map;
    if (!$fileSystem) {
      @trigger_error(
        'Calling ' . __METHOD__ . '() without the $fileSystem argument is deprecated in drupal:11.2.0 and is required in drupal:12.0.0. See https://www.drupal.org/node/3494040',
        E_USER_DEPRECATED
      );
      $fileSystem = \Drupal::service(FileSystemInterface::class);
    }
    $this->fileSystem = $fileSystem;
  }

  /**
   * {@inheritdoc}
   */
  public function guessMimeType($path): ?string {
    if ($this->mapping === NULL) {
      $mapping = $this->defaultMapping;
      // Allow modules to alter the default mapping.
      $this->moduleHandler->alter('file_mimetype_mapping', $mapping);
      $this->mapping = $mapping;
    if (!isset($this->fileSystem)) {
      @trigger_error(
        'Calling ' . __METHOD__ . '() without the file_system service already injected is deprecated in drupal:11.2.0 and throws an exception in drupal:12.0.0. See https://www.drupal.org/node/3494040',
        E_USER_DEPRECATED
      );
      $this->fileSystem = \Drupal::service(FileSystemInterface::class);
    }
    if (!isset($this->map)) {
      @trigger_error(
        'Calling ' . __METHOD__ . '() without the MimeTypeMapInterface service already injected is deprecated in drupal:11.2.0 and throws an exception in drupal:12.0.0. See https://www.drupal.org/node/3494040',
        E_USER_DEPRECATED
      );
      $this->map = \Drupal::service(MimeTypeMapInterface::class);
    }

    $extension = '';
    $file_parts = explode('.', \Drupal::service('file_system')->basename($path));
    $file_parts = explode('.', $this->fileSystem->basename($path));

    // Remove the first part: a full filename should not match an extension,
    // then iterate over the file parts, trying to find a match.
@@ -919,8 +975,8 @@ public function guessMimeType($path): ?string {
    // empty.
    while (array_shift($file_parts) !== NULL) {
      $extension = strtolower(implode('.', $file_parts));
      if (isset($this->mapping['extensions'][$extension])) {
        return $this->mapping['mimetypes'][$this->mapping['extensions'][$extension]];
      if ($mimeType = $this->map->getMimeTypeForExtension($extension)) {
        return $mimeType;
      }
    }

@@ -932,9 +988,32 @@ public function guessMimeType($path): ?string {
   *
   * @param array|null $mapping
   *   Passing a NULL mapping will cause guess() to use self::$defaultMapping.
   *
   * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
   *   \Drupal\Core\File\MimeType\MimeTypeMapInterface::addMapping() instead.
   *
   * @see https://www.drupal.org/node/3494040
   */
  public function setMapping(?array $mapping = NULL) {
    $this->mapping = $mapping;
  public function setMapping(?array $mapping = NULL): void {
    @trigger_error(
      __METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal\Core\File\MimeType\MimeTypeMapInterface::addMapping() instead or define your own MimeTypeMapInterface implementation. See https://www.drupal.org/node/3494040',
      E_USER_DEPRECATED
    );
    // Convert the mapping to be keyed by type.
    $typeMapping = [];
    foreach ($mapping['mimetypes'] as $index => $mimetype) {
      $typeMapping[$mimetype] = array_keys($mapping['extensions'], $index);
    }

    $this->map = new MimeTypeMap();
    foreach ($typeMapping as $type => $extensions) {
      foreach ($extensions as $extension) {
        $this->map->addMapping($type, $extension);
      }
    }
    \Drupal::service('event_dispatcher')->dispatch(
      new MimeTypeMapLoadedEvent($this->map)
    );
  }

  /**
Loading