Skip to content

Commit

Permalink
feature #29896 [Mime] Add the component (fabpot)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 4.3-dev branch (closes #29896).

Discussion
----------

[Mime] Add the component

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #28832 #21985 makes #15460 trivial
| License       | MIT
| Doc PR        | symfony/symfony-docs#10886

This has been on my todo-list for X years :)

Commits
-------

bdca5d9 tweaked code
5268389 [Mime] added freedesktop as a source for mime types
74ca91d [Mime] added the component
d7ee0ec [HttpFoundation] updated File code
  • Loading branch information
fabpot committed Jan 17, 2019
2 parents 5aa0967 + bdca5d9 commit db6784b
Show file tree
Hide file tree
Showing 42 changed files with 3,945 additions and 68 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -60,6 +60,7 @@
"symfony/ldap": "self.version",
"symfony/lock": "self.version",
"symfony/messenger": "self.version",
"symfony/mime": "self.version",
"symfony/monolog-bridge": "self.version",
"symfony/options-resolver": "self.version",
"symfony/process": "self.version",
Expand Down
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Registers custom mime types guessers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AddMimeTypeGuesserPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if ($container->has('mime_types')) {
$definition = $container->findDefinition('mime_types');
foreach ($container->findTaggedServiceIds('mime.mime_type_guesser', true) as $id => $attributes) {
$definition->addMethodCall('registerGuesser', [new Reference($id)]);
}
}
}
}
Expand Up @@ -42,6 +42,7 @@ class UnusedTagsPass implements CompilerPassInterface
'messenger.bus',
'messenger.receiver',
'messenger.message_handler',
'mime.mime_type_guesser',
'monolog.logger',
'proxy',
'routing.expression_language_provider',
Expand Down
Expand Up @@ -73,6 +73,8 @@
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
use Symfony\Component\Messenger\Transport\TransportInterface;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
Expand Down Expand Up @@ -310,6 +312,10 @@ public function load(array $configs, ContainerBuilder $container)
'Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController',
]);

if (class_exists(MimeTypes::class)) {
$loader->load('mime_type.xml');
}

$container->registerForAutoconfiguration(Command::class)
->addTag('console.command');
$container->registerForAutoconfiguration(ResourceCheckerInterface::class)
Expand Down Expand Up @@ -374,6 +380,8 @@ public function load(array $configs, ContainerBuilder $container)
->addTag('messenger.message_handler');
$container->registerForAutoconfiguration(TransportFactoryInterface::class)
->addTag('messenger.transport_factory');
$container->registerForAutoconfiguration(MimeTypeGuesserInterface::class)
->addTag('mime.mime_type_guesser');
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
->addMethodCall('setLogger', [new Reference('logger')]);

Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Expand Up @@ -14,6 +14,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddExpressionLanguageProvidersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddMimeTypeGuesserPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
Expand Down Expand Up @@ -72,6 +73,11 @@ public function boot()
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}

if ($this->container->has('mime_types')) {
$mt = $this->container->get('mime_types');
$mt->setDefault($mt);
}
}

public function build(ContainerBuilder $container)
Expand Down Expand Up @@ -118,6 +124,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new ResettableServicePass());
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new AddMimeTypeGuesserPass());
$this->addCompilerPassIfExists($container, MessengerPass::class);

if ($container->getParameter('kernel.debug')) {
Expand Down
12 changes: 12 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml
@@ -0,0 +1,12 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<defaults public="false" />

<service id="mime_types" class="Symfony\Component\Mime\MimeTypes" public="true" />
</services>
</container>
Expand Up @@ -42,6 +42,7 @@
</service>

<service id="serializer.normalizer.data_uri" class="Symfony\Component\Serializer\Normalizer\DataUriNormalizer">
<argument type="service" id="mime_types" on-invalid="null" />
<!-- Run before serializer.normalizer.object -->
<tag name="serializer.normalizer" priority="-920" />
</service>
Expand Down
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;

use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddMimeTypeGuesserPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Mime\FileinfoMimeTypeGuesser;
use Symfony\Component\Mime\MimeTypes;

class AddMimeTypeGuesserPassTest extends TestCase
{
public function testTags()
{
$container = new ContainerBuilder();
$container->addCompilerPass(new AddMimeTypeGuesserPass());

$definition = new Definition(FileinfoMimeTypeGuesser::class);
$definition->addArgument('/path/to/magic/file');
$definition->addTag('mime.mime_type_guesser');
$container->setDefinition('some_mime_type_guesser', $definition->setPublic(true));
$container->register('mime_types', MimeTypes::class)->setPublic(true);
$container->compile();

$router = $container->getDefinition('mime_types');
$calls = $router->getMethodCalls();
$this->assertCount(1, $calls);
$this->assertEquals('registerGuesser', $calls[0][0]);
$this->assertEquals(new Reference('some_mime_type_guesser'), $calls[0][1][0]);
}
}
5 changes: 3 additions & 2 deletions src/Symfony/Bundle/FrameworkBundle/composer.json
Expand Up @@ -23,7 +23,7 @@
"symfony/contracts": "^1.0.2",
"symfony/dependency-injection": "^4.2",
"symfony/event-dispatcher": "^4.1",
"symfony/http-foundation": "^4.1.2",
"symfony/http-foundation": "^4.3",
"symfony/http-kernel": "^4.2",
"symfony/polyfill-mbstring": "~1.0",
"symfony/filesystem": "~3.4|~4.0",
Expand All @@ -43,10 +43,11 @@
"symfony/form": "^4.2",
"symfony/expression-language": "~3.4|~4.0",
"symfony/messenger": "^4.2",
"symfony/mime": "^4.3",
"symfony/process": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/serializer": "^4.2",
"symfony/serializer": "^4.3",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/translation": "~4.2",
"symfony/templating": "~3.4|~4.0",
Expand Down
22 changes: 8 additions & 14 deletions src/Symfony/Component/HttpFoundation/File/File.php
Expand Up @@ -13,8 +13,7 @@

use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\Mime\MimeTypes;

/**
* A file in the file system.
Expand Down Expand Up @@ -50,33 +49,28 @@ public function __construct(string $path, bool $checkPath = true)
*
* @return string|null The guessed extension or null if it cannot be guessed
*
* @see ExtensionGuesser
* @see MimeTypes
* @see getMimeType()
*/
public function guessExtension()
{
$type = $this->getMimeType();
$guesser = ExtensionGuesser::getInstance();

return $guesser->guess($type);
return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null;
}

/**
* Returns the mime type of the file.
*
* The mime type is guessed using a MimeTypeGuesser instance, which uses finfo(),
* mime_content_type() and the system binary "file" (in this order), depending on
* which of those are available.
* The mime type is guessed using a MimeTypeGuesserInterface instance,
* which uses finfo_file() then the "file" system binary,
* depending on which of those are available.
*
* @return string|null The guessed mime type (e.g. "application/pdf")
*
* @see MimeTypeGuesser
* @see MimeTypes
*/
public function getMimeType()
{
$guesser = MimeTypeGuesser::getInstance();

return $guesser->guess($this->getPathname());
return MimeTypes::getDefault()->guessMimeType($this->getPathname());
}

/**
Expand Down
Expand Up @@ -11,6 +11,10 @@

namespace Symfony\Component\HttpFoundation\File\MimeType;

use Symfony\Component\Mime\MimeTypes;

@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', ExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED);

/**
* A singleton mime type to file extension guesser.
*
Expand All @@ -22,6 +26,8 @@
* $guesser->register(new MyCustomExtensionGuesser());
*
* The last registered guesser is preferred over previously registered ones.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
class ExtensionGuesser implements ExtensionGuesserInterface
{
Expand Down
Expand Up @@ -11,8 +11,12 @@

namespace Symfony\Component\HttpFoundation\File\MimeType;

use Symfony\Component\Mime\MimeTypes;

/**
* Guesses the file extension corresponding to a given mime type.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
interface ExtensionGuesserInterface
{
Expand Down
Expand Up @@ -13,11 +13,16 @@

use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\FileBinaryMimeTypeGuesser as NewFileBinaryMimeTypeGuesser;

@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileBinaryMimeTypeGuesser::class, NewFileBinaryMimeTypeGuesser::class), E_USER_DEPRECATED);

/**
* Guesses the mime type with the binary "file" (only available on *nix).
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link NewFileBinaryMimeTypeGuesser} instead
*/
class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
{
Expand Down
Expand Up @@ -13,11 +13,16 @@

use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\FileinfoMimeTypeGuesser as NewFileinfoMimeTypeGuesser;

@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileinfoMimeTypeGuesser::class, NewFileinfoMimeTypeGuesser::class), E_USER_DEPRECATED);

/**
* Guesses the mime type using the PECL extension FileInfo.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link NewFileinfoMimeTypeGuesser} instead
*/
class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
{
Expand Down
Expand Up @@ -11,8 +11,14 @@

namespace Symfony\Component\HttpFoundation\File\MimeType;

use Symfony\Component\Mime\MimeTypes;

@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED);

/**
* Provides a best-guess mapping of mime type to file extension.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
class MimeTypeExtensionGuesser implements ExtensionGuesserInterface
{
Expand Down
Expand Up @@ -13,6 +13,9 @@

use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\MimeTypes;

@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeGuesser::class, MimeTypes::class), E_USER_DEPRECATED);

/**
* A singleton mime type guesser.
Expand Down
Expand Up @@ -13,11 +13,14 @@

use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\MimeTypes;

/**
* Guesses the mime type of a file.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
interface MimeTypeGuesserInterface
{
Expand Down
7 changes: 2 additions & 5 deletions src/Symfony/Component/HttpFoundation/File/UploadedFile.php
Expand Up @@ -20,7 +20,7 @@
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
use Symfony\Component\Mime\MimeTypes;

/**
* A file uploaded through a form.
Expand Down Expand Up @@ -140,10 +140,7 @@ public function getClientMimeType()
*/
public function guessClientExtension()
{
$type = $this->getClientMimeType();
$guesser = ExtensionGuesser::getInstance();

return $guesser->guess($type);
return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null;
}

/**
Expand Down

0 comments on commit db6784b

Please sign in to comment.