diff --git a/composer.json b/composer.json index 83a021ced9575418efe97a7b284a1c01e0db084a..a84d6fd25c8d1cd2204168ccdc57d0e8d7c916d0 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "description": "Provides an extensive MIME types management API", "require": { "drupal/core": "^10.2 || ^11", - "fileeye/mimemap": "^2.2" + "fileeye/mimemap": "^2.2.1" }, "autoload": { "psr-4": { diff --git a/resources/drupal_map_build.yml b/resources/drupal_map_build.yml index 62bc8d5119b1b354481c13eb269a63654d9f65f3..95d0968f513e69583e937fa536fddaa310b253b4 100644 --- a/resources/drupal_map_build.yml +++ b/resources/drupal_map_build.yml @@ -325,3 +325,4 @@ - [setExtensionDefaultType, [wav, audio/x-wav]] - [setExtensionDefaultType, [odb, application/vnd.oasis.opendocument.database]] - [setExtensionDefaultType, [sds, application/vnd.stardivision.chart]] + - [setExtensionDefaultType, [sct, text/scriptlet]] diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php index 8d392eaca4687c11679be0037dc346e2cdb4fd07..daf6f2833d2b49cd325ad45efffd988a3300e182 100644 --- a/src/Form/SettingsForm.php +++ b/src/Form/SettingsForm.php @@ -168,7 +168,16 @@ class SettingsForm extends ConfigFormBase { } // Mapping gaps. - if ($gaps = $this->determineMapGaps()) { + // @todo BC starts. Resolve in sophron:3.0.0. + if (method_exists($this->mimeMapManager, 'determineMapGaps')) { + $gaps = $this->mimeMapManager->determineMapGaps($this->mimeMapManager->getMapClass()); + } + else { + // @phpstan-ignore method.deprecated + $gaps = $this->determineMapGaps(); + } + // @todo BC ends. + if ($gaps !== []) { $form['mapping']['gaps'] = [ '#type' => 'details', '#collapsible' => TRUE, @@ -317,8 +326,15 @@ class SettingsForm extends ConfigFormBase { * @return array * An array of simple arrays, each having a file extension, its Drupal MIME * type guess, and a gap information. + * + * @deprecated in sophron:2.2.0 and is removed from sophron:3.0.0. Use + * MimeMapManager::determineMapGaps() instead. + * + * @see https://www.drupal.org/project/sophron/issues/3494318 */ protected function determineMapGaps(): array { + @trigger_error(__METHOD__ . '() is deprecated in sophron:2.2.0 and is removed from sophron:3.0.0. Use MimeMapManager::determineMapGaps() instead. See https://www.drupal.org/project/sophron/issues/3494318', E_USER_DEPRECATED); + $core_extended_guesser = new CoreExtensionMimeTypeGuesserExtended(); $extensions = $core_extended_guesser->listExtensions(); diff --git a/src/Map/DrupalMap.php b/src/Map/DrupalMap.php index 12072f385840add9ebdb912703b6b787e87f0a0c..8b4af07fbf276a784f5b638b6d7137f4f457268f 100644 --- a/src/Map/DrupalMap.php +++ b/src/Map/DrupalMap.php @@ -3259,7 +3259,6 @@ class DrupalMap extends AbstractMap { 5 => 'efi', 6 => 'ocx', 7 => 'sys', - 8 => 'lib', ), ), 'application/vnd.mif' => @@ -4193,7 +4192,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'OpenOffice.org extension', + 0 => 'LibreOffice extension', ), 'e' => array ( @@ -4652,7 +4651,10 @@ class DrupalMap extends AbstractMap { ), 'e' => array ( - 0 => 'sqsh', + 0 => 'sfs', + 1 => 'sqfs', + 2 => 'sqsh', + 3 => 'squashfs', ), ), 'application/vnd.stardivision.calc' => @@ -4773,7 +4775,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Calc spreadsheet', + 0 => 'OpenOffice.org 1.0 Calc spreadsheet', ), 'e' => array ( @@ -4784,7 +4786,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Calc template', + 0 => 'OpenOffice.org 1.0 Calc template', ), 'e' => array ( @@ -4795,7 +4797,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Draw drawing', + 0 => 'OpenOffice.org 1.0 Draw drawing', ), 'e' => array ( @@ -4806,7 +4808,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Draw template', + 0 => 'OpenOffice.org 1.0 Draw template', ), 'e' => array ( @@ -4817,7 +4819,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Impress presentation', + 0 => 'OpenOffice.org 1.0 Impress presentation', ), 'e' => array ( @@ -4828,7 +4830,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Impress template', + 0 => 'OpenOffice.org 1.0 Impress template', ), 'e' => array ( @@ -4839,7 +4841,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Math formula', + 0 => 'OpenOffice.org 1.0 Math formula', ), 'e' => array ( @@ -4850,7 +4852,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Writer document', + 0 => 'OpenOffice.org 1.0 Writer document', ), 'e' => array ( @@ -4861,7 +4863,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Writer global document', + 0 => 'OpenOffice.org 1.0 Writer global document', ), 'e' => array ( @@ -4872,7 +4874,7 @@ class DrupalMap extends AbstractMap { array ( 'desc' => array ( - 0 => 'LibreOffice Writer template', + 0 => 'OpenOffice.org 1.0 Writer template', ), 'e' => array ( @@ -5424,6 +5426,7 @@ class DrupalMap extends AbstractMap { array ( 0 => 'a', 1 => 'ar', + 2 => 'lib', ), ), 'application/x-arj' => @@ -7877,6 +7880,19 @@ class DrupalMap extends AbstractMap { 0 => 'pce', ), ), + 'application/x-pcapng' => + array ( + 'desc' => + array ( + 0 => 'PCAPNG packet capture', + 1 => 'PCAPNG: PCAP Next Generation', + ), + 'e' => + array ( + 0 => 'pcapng', + 1 => 'ntar', + ), + ), 'application/x-perl' => array ( 'a' => @@ -11315,6 +11331,14 @@ class DrupalMap extends AbstractMap { ), 'image/vnd.fpx' => array ( + 'a' => + array ( + 0 => 'image/x-fpx', + ), + 'desc' => + array ( + 0 => 'FlashPix image', + ), 'e' => array ( 0 => 'fpx', @@ -11759,6 +11783,19 @@ class DrupalMap extends AbstractMap { 2 => 'jpc', ), ), + 'image/x-kiss-cel' => + array ( + 'desc' => + array ( + 0 => 'KiSS cel', + 1 => 'KiSS: Kisekae Set System', + ), + 'e' => + array ( + 0 => 'cel', + 1 => 'kcf', + ), + ), 'image/x-kodak-dcr' => array ( 'desc' => @@ -11936,6 +11973,17 @@ class DrupalMap extends AbstractMap { 0 => 'pef', ), ), + 'image/x-pfm' => + array ( + 'desc' => + array ( + 0 => 'Portable FloatMap', + ), + 'e' => + array ( + 0 => 'pfm', + ), + ), 'image/x-photo-cd' => array ( 'desc' => @@ -12011,6 +12059,17 @@ class DrupalMap extends AbstractMap { 0 => 'ppm', ), ), + 'image/x-pxr' => + array ( + 'desc' => + array ( + 0 => 'Pixar raster', + ), + 'e' => + array ( + 0 => 'pxr', + ), + ), 'image/x-quicktime' => array ( 'desc' => @@ -12034,6 +12093,18 @@ class DrupalMap extends AbstractMap { 0 => 'rgb', ), ), + 'image/x-sct' => + array ( + 'desc' => + array ( + 0 => 'Scitex CT', + 1 => 'CT: Continuous Tone', + ), + 'e' => + array ( + 0 => 'sct', + ), + ), 'image/x-sgi' => array ( 'desc' => @@ -12453,7 +12524,8 @@ class DrupalMap extends AbstractMap { 0 => 'ics', 1 => 'ifb', 2 => 'vcs', - 3 => 'icz', + 3 => 'icalendar', + 4 => 'icz', ), ), 'text/css' => @@ -12986,6 +13058,10 @@ class DrupalMap extends AbstractMap { ), 'text/x-asm' => array ( + 'desc' => + array ( + 0 => 'Assembly code', + ), 'e' => array ( 0 => 's', @@ -13739,6 +13815,17 @@ class DrupalMap extends AbstractMap { 1 => 'nimble', ), ), + 'text/x-nix' => + array ( + 'desc' => + array ( + 0 => 'Nix source code', + ), + 'e' => + array ( + 0 => 'nix', + ), + ), 'text/x-objc++src' => array ( 'desc' => @@ -16387,6 +16474,13 @@ class DrupalMap extends AbstractMap { 0 => 'chemical/x-cxf', ), ), + 'cel' => + array ( + 't' => + array ( + 0 => 'image/x-kiss-cel', + ), + ), 'cer' => array ( 't' => @@ -19250,6 +19344,13 @@ class DrupalMap extends AbstractMap { 0 => 'application/x-ica', ), ), + 'icalendar' => + array ( + 't' => + array ( + 0 => 'text/calendar', + ), + ), 'icb' => array ( 't' => @@ -19936,6 +20037,13 @@ class DrupalMap extends AbstractMap { 1 => 'application/x-karbon', ), ), + 'kcf' => + array ( + 't' => + array ( + 0 => 'image/x-kiss-cel', + ), + ), 'kdc' => array ( 't' => @@ -20265,7 +20373,7 @@ class DrupalMap extends AbstractMap { array ( 't' => array ( - 0 => 'application/vnd.microsoft.portable-executable', + 0 => 'application/x-archive', ), ), 'link66' => @@ -21793,6 +21901,13 @@ class DrupalMap extends AbstractMap { 0 => 'application/vnd.nitf', ), ), + 'nix' => + array ( + 't' => + array ( + 0 => 'text/x-nix', + ), + ), 'nlu' => array ( 't' => @@ -21871,6 +21986,13 @@ class DrupalMap extends AbstractMap { 0 => 'video/x-nsv', ), ), + 'ntar' => + array ( + 't' => + array ( + 0 => 'application/x-pcapng', + ), + ), 'ntf' => array ( 't' => @@ -22510,6 +22632,13 @@ class DrupalMap extends AbstractMap { 1 => 'application/vnd.tcpdump.pcap', ), ), + 'pcapng' => + array ( + 't' => + array ( + 0 => 'application/x-pcapng', + ), + ), 'pcd' => array ( 't' => @@ -22682,6 +22811,7 @@ class DrupalMap extends AbstractMap { 't' => array ( 0 => 'application/x-font-type1', + 1 => 'image/x-pfm', ), ), 'pfr' => @@ -23252,6 +23382,13 @@ class DrupalMap extends AbstractMap { 0 => 'text/x-cython', ), ), + 'pxr' => + array ( + 't' => + array ( + 0 => 'image/x-pxr', + ), + ), 'py' => array ( 't' => @@ -24127,6 +24264,7 @@ class DrupalMap extends AbstractMap { 't' => array ( 0 => 'text/scriptlet', + 1 => 'image/x-sct', ), ), 'scurl' => @@ -24309,6 +24447,7 @@ class DrupalMap extends AbstractMap { 't' => array ( 0 => 'application/vnd.spotfire.sfs', + 1 => 'application/vnd.squashfs', ), ), 'sfv' => @@ -24795,6 +24934,13 @@ class DrupalMap extends AbstractMap { 3 => 'audio/x-speex', ), ), + 'sqfs' => + array ( + 't' => + array ( + 0 => 'application/vnd.squashfs', + ), + ), 'sql' => array ( 't' => @@ -24824,6 +24970,13 @@ class DrupalMap extends AbstractMap { 0 => 'application/vnd.squashfs', ), ), + 'squashfs' => + array ( + 't' => + array ( + 0 => 'application/vnd.squashfs', + ), + ), 'sr2' => array ( 't' => @@ -29691,6 +29844,13 @@ class DrupalMap extends AbstractMap { 0 => 'application/fits', ), ), + 'image/x-fpx' => + array ( + 't' => + array ( + 0 => 'image/vnd.fpx', + ), + ), 'image/x-icb' => array ( 't' => diff --git a/src/MimeMapManager.php b/src/MimeMapManager.php index 006a94db4eae0784b1644dcf3115c45141af12cc..e6fb49de4e247c197e428f8749a73dbf800b95c9 100644 --- a/src/MimeMapManager.php +++ b/src/MimeMapManager.php @@ -15,6 +15,7 @@ use FileEye\MimeMap\Extension; use FileEye\MimeMap\Map\AbstractMap; use FileEye\MimeMap\Map\DefaultMap; use FileEye\MimeMap\MapHandler; +use FileEye\MimeMap\MappingException; use FileEye\MimeMap\Type; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -55,8 +56,8 @@ class MimeMapManager implements MimeMapManagerInterface { /** * {@inheritdoc} */ - public function isMapClassValid(string $map_class): bool { - if (class_exists($map_class) && in_array(AbstractMap::class, class_parents($map_class))) { + public function isMapClassValid(string $mapClass): bool { + if (class_exists($mapClass) && in_array(AbstractMap::class, class_parents($mapClass))) { return TRUE; } return FALSE; @@ -77,8 +78,8 @@ class MimeMapManager implements MimeMapManagerInterface { break; case static::CUSTOM_MAP: - $map_class = $this->sophronSettings->get('map_class'); - $this->setMapClass($this->isMapClassValid($map_class) ? $map_class : DrupalMap::class); + $mapClass = $this->sophronSettings->get('map_class'); + $this->setMapClass($this->isMapClassValid($mapClass) ? $mapClass : DrupalMap::class); break; } @@ -89,12 +90,12 @@ class MimeMapManager implements MimeMapManagerInterface { /** * {@inheritdoc} */ - public function setMapClass(string $map_class): MimeMapManagerInterface { - $this->currentMapClass = $map_class; - if (!isset($this->initializedMapClasses[$map_class])) { - $event = new MapEvent($map_class); + public function setMapClass(string $mapClass): MimeMapManagerInterface { + $this->currentMapClass = $mapClass; + if (!isset($this->initializedMapClasses[$mapClass])) { + $event = new MapEvent($mapClass); $this->eventDispatcher->dispatch($event, MapEvent::INIT); - $this->initializedMapClasses[$map_class] = $event->getErrors(); + $this->initializedMapClasses[$mapClass] = $event->getErrors(); } return $this; } @@ -102,9 +103,9 @@ class MimeMapManager implements MimeMapManagerInterface { /** * {@inheritdoc} */ - public function getMappingErrors(string $map_class): array { - $this->setMapClass($map_class); - return $this->initializedMapClasses[$map_class] ?? []; + public function getMappingErrors(string $mapClass): array { + $this->setMapClass($mapClass); + return $this->initializedMapClasses[$mapClass] ?? []; } /** @@ -149,4 +150,54 @@ class MimeMapManager implements MimeMapManagerInterface { ]; } + /** + * Returns an array of gaps of a map vs Drupal's core mapping. + * + * @param class-string<\FileEye\MimeMap\Map\MimeMapInterface> $mapClass + * A FQCN. + * + * @return array + * An array of simple arrays, each having a file extension, its Drupal MIME + * type guess, and a gap information. + * + * @todo add to interface in sophron:3.0.0 + */ + public function determineMapGaps(string $mapClass): array { + $currentMapClass = $this->getMapClass(); + $this->setMapClass($mapClass); + + $core_extended_guesser = new CoreExtensionMimeTypeGuesserExtended(); + + $extensions = $core_extended_guesser->listExtensions(); + sort($extensions); + + $rows = []; + foreach ($extensions as $ext) { + $drupal_mime_type = $core_extended_guesser->guessMimeType('a.' . (string) $ext); + + $extension = $this->getExtension((string) $ext); + try { + $mimemap_mime_type = $extension->getDefaultType(); + } + catch (MappingException $e) { + $mimemap_mime_type = ''; + } + + $gap = ''; + if ($mimemap_mime_type === '') { + $gap = $this->t('No MIME type mapped to this file extension.'); + } + elseif (mb_strtolower($drupal_mime_type) != mb_strtolower($mimemap_mime_type)) { + $gap = $this->t("File extension mapped to '@type' instead.", ['@type' => $mimemap_mime_type]); + } + + if ($gap !== '') { + $rows[] = [(string) $ext, $drupal_mime_type, $gap]; + } + } + + $this->setMapClass($currentMapClass); + return $rows; + } + } diff --git a/src/MimeMapManagerInterface.php b/src/MimeMapManagerInterface.php index 087b37e641f8db2341aa5d7bd60aade787c885c6..2c7acb7f51980cc0d74c80d59252c67216e738c1 100644 --- a/src/MimeMapManagerInterface.php +++ b/src/MimeMapManagerInterface.php @@ -130,4 +130,20 @@ interface MimeMapManagerInterface { */ public function requirements(string $phase): array; + // phpcs:disable + /** + * Returns an array of gaps of a map vs Drupal's core mapping. + * + * @param class-string<\FileEye\MimeMap\Map\MimeMapInterface> $mapClass + * A FQCN. + * + * @return array + * An array of simple arrays, each having a file extension, its Drupal MIME + * type guess, and a gap information. + * + * @todo add to interface in sophron:3.0.0 + */ + // public function determineMapGaps(string $mapClass): array; + // phpcs:enable + } diff --git a/tests/src/Kernel/SophronApiTest.php b/tests/src/Kernel/SophronApiTest.php index 82225e7d7777875c5d45ae63913ce07f70970f43..18b9fc495896ef57c551b53e05e5d193dda83de1 100644 --- a/tests/src/Kernel/SophronApiTest.php +++ b/tests/src/Kernel/SophronApiTest.php @@ -127,4 +127,11 @@ class SophronApiTest extends KernelTestBase { $this->assertCount(4, $manager->getMappingErrors(DefaultMap::class)); } + /** + * Tests no mapping errors for DrupalMap vs core. + */ + public function testZeroMappingErrorsForDrupalMap(): void { + $this->assertSame([], \Drupal::service(MimeMapManagerInterface::class)->determineMapGaps(DrupalMap::class)); + } + }