- <?php
- declare(strict_types=1);
- /*
-  * This file is part of Contao.
-  *
-  * (c) Leo Feyer
-  *
-  * @license LGPL-3.0-or-later
-  */
- namespace Contao\ManagerBundle\ContaoManager;
- use Contao\CoreBundle\ContaoCoreBundle;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\GenerateJwtCookieCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\GetConfigCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\GetDotEnvCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\ParseJwtCookieCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\RemoveDotEnvCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\SetConfigCommand;
- use Contao\ManagerBundle\ContaoManager\ApiCommand\SetDotEnvCommand;
- use Contao\ManagerBundle\ContaoManagerBundle;
- use Contao\ManagerPlugin\Api\ApiPluginInterface;
- use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
- use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
- use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
- use Contao\ManagerPlugin\Config\ConfigPluginInterface;
- use Contao\ManagerPlugin\Config\ContainerBuilder as PluginContainerBuilder;
- use Contao\ManagerPlugin\Config\ExtensionPluginInterface;
- use Contao\ManagerPlugin\Dependency\DependentPluginInterface;
- use Contao\ManagerPlugin\Routing\RoutingPluginInterface;
- use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
- use FOS\HttpCacheBundle\FOSHttpCacheBundle;
- use League\FlysystemBundle\FlysystemBundle;
- use Nelmio\CorsBundle\NelmioCorsBundle;
- use Nelmio\SecurityBundle\NelmioSecurityBundle;
- use Symfony\Bundle\DebugBundle\DebugBundle;
- use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
- use Symfony\Bundle\MonologBundle\MonologBundle;
- use Symfony\Bundle\SecurityBundle\SecurityBundle;
- use Symfony\Bundle\TwigBundle\TwigBundle;
- use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
- use Symfony\Component\Config\Loader\LoaderInterface;
- use Symfony\Component\Config\Loader\LoaderResolverInterface;
- use Symfony\Component\DependencyInjection\ContainerBuilder;
- use Symfony\Component\Filesystem\Path;
- use Symfony\Component\Finder\Finder;
- use Symfony\Component\Finder\SplFileInfo;
- use Symfony\Component\HttpKernel\KernelInterface;
- use Symfony\Component\Mailer\Transport\NativeTransportFactory;
- use Symfony\Component\Routing\Route;
- use Symfony\Component\Routing\RouteCollection;
- use Twig\Extra\TwigExtraBundle\TwigExtraBundle;
- /**
-  * @internal
-  */
- class Plugin implements BundlePluginInterface, ConfigPluginInterface, RoutingPluginInterface, ExtensionPluginInterface, DependentPluginInterface, ApiPluginInterface
- {
-     private static ?string $autoloadModules = null;
-     /**
-      * Sets the path to enable autoloading of legacy Contao modules.
-      */
-     public static function autoloadModules(string $modulePath): void
-     {
-         static::$autoloadModules = $modulePath;
-     }
-     public function getPackageDependencies(): array
-     {
-         return ['contao/core-bundle'];
-     }
-     public function getBundles(ParserInterface $parser): array
-     {
-         $configs = [
-             BundleConfig::create(FrameworkBundle::class),
-             BundleConfig::create(SecurityBundle::class)->setLoadAfter([FrameworkBundle::class]),
-             BundleConfig::create(TwigBundle::class),
-             BundleConfig::create(TwigExtraBundle::class),
-             BundleConfig::create(MonologBundle::class),
-             BundleConfig::create(DoctrineBundle::class),
-             BundleConfig::create(NelmioCorsBundle::class),
-             BundleConfig::create(NelmioSecurityBundle::class),
-             BundleConfig::create(FOSHttpCacheBundle::class),
-             BundleConfig::create(ContaoManagerBundle::class)->setLoadAfter([ContaoCoreBundle::class]),
-             BundleConfig::create(DebugBundle::class)->setLoadInProduction(false),
-             BundleConfig::create(WebProfilerBundle::class)->setLoadInProduction(false),
-             BundleConfig::create(FlysystemBundle::class)->setLoadAfter([ContaoCoreBundle::class]),
-         ];
-         // Autoload the legacy modules
-         if (null !== static::$autoloadModules && file_exists(static::$autoloadModules)) {
-             /** @var array<SplFileInfo> $modules */
-             $modules = Finder::create()
-                 ->directories()
-                 ->depth(0)
-                 ->in(static::$autoloadModules)
-             ;
-             $iniConfigs = [];
-             foreach ($modules as $module) {
-                 if (!file_exists(Path::join($module->getPathname(), '.skip'))) {
-                     $iniConfigs[] = $parser->parse($module->getFilename(), 'ini');
-                 }
-             }
-             if (!empty($iniConfigs)) {
-                 $configs = array_merge($configs, ...$iniConfigs);
-             }
-         }
-         return $configs;
-     }
-     public function registerContainerConfiguration(LoaderInterface $loader, array $managerConfig): void
-     {
-         $loader->load(
-             static function (ContainerBuilder $container) use ($loader): void {
-                 if ('dev' === $container->getParameter('kernel.environment')) {
-                     $loader->load('@ContaoManagerBundle/Resources/skeleton/config/config_dev.yml');
-                 } else {
-                     $loader->load('@ContaoManagerBundle/Resources/skeleton/config/config_prod.yml');
-                 }
-                 $container->setParameter('container.dumper.inline_class_loader', true);
-             }
-         );
-     }
-     public function getRouteCollection(LoaderResolverInterface $resolver, KernelInterface $kernel): ?RouteCollection
-     {
-         if ('dev' !== $kernel->getEnvironment()) {
-             return null;
-         }
-         $collections = [];
-         $files = [
-             '_wdt' => '@WebProfilerBundle/Resources/config/routing/wdt.xml',
-             '_profiler' => '@WebProfilerBundle/Resources/config/routing/profiler.xml',
-         ];
-         foreach ($files as $prefix => $file) {
-             /** @var RouteCollection $collection */
-             $collection = $resolver->resolve($file)->load($file);
-             $collection->addPrefix($prefix);
-             $collections[] = $collection;
-         }
-         $collection = array_reduce(
-             $collections,
-             static function (RouteCollection $carry, RouteCollection $item): RouteCollection {
-                 $carry->addCollection($item);
-                 return $carry;
-             },
-             new RouteCollection()
-         );
-         // Redirect the deprecated install.php file
-         $collection->add(
-             'contao_install_redirect',
-             new Route(
-                 '/install.php',
-                 [
-                     '_scope' => 'backend',
-                     '_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction',
-                     'route' => 'contao_install',
-                     'permanent' => true,
-                 ]
-             )
-         );
-         return $collection;
-     }
-     public function getApiFeatures(): array
-     {
-         return [
-             'dot-env' => [
-                 'APP_SECRET',
-                 'APP_ENV',
-                 'COOKIE_WHITELIST',
-                 'DATABASE_URL',
-                 'DISABLE_HTTP_CACHE',
-                 'MAILER_URL',
-                 'MAILER_DSN',
-                 'TRACE_LEVEL',
-                 'TRUSTED_PROXIES',
-                 'TRUSTED_HOSTS',
-             ],
-             'config' => [
-                 'disable-packages',
-             ],
-             'jwt-cookie' => [
-                 'debug',
-             ],
-         ];
-     }
-     public function getApiCommands(): array
-     {
-         return [
-             GetConfigCommand::class,
-             SetConfigCommand::class,
-             GetDotEnvCommand::class,
-             SetDotEnvCommand::class,
-             RemoveDotEnvCommand::class,
-             GenerateJwtCookieCommand::class,
-             ParseJwtCookieCommand::class,
-         ];
-     }
-     public function getExtensionConfig($extensionName, array $extensionConfigs, PluginContainerBuilder $container): array
-     {
-         switch ($extensionName) {
-             case 'contao':
-                 return $this->handlePrependLocale($extensionConfigs, $container);
-             case 'framework':
-                 $extensionConfigs = $this->checkMailerTransport($extensionConfigs, $container);
-                 $extensionConfigs = $this->addDefaultMailer($extensionConfigs, $container);
-                 if (!isset($_SERVER['APP_SECRET'])) {
-                     $container->setParameter('env(APP_SECRET)', $container->getParameter('secret'));
-                 }
-                 if (!isset($_SERVER['MAILER_DSN'])) {
-                     if (isset($_SERVER['MAILER_URL'])) {
-                         trigger_deprecation('contao/manager-bundle', '4.13', 'Using the "MAILER_URL" environment variable has been deprecated and will no longer work in Contao 5.0. Use the "MAILER_DSN" environment variable instead.');
-                         $container->setParameter('env(MAILER_DSN)', $this->getMailerDsnFromMailerUrl($_SERVER['MAILER_URL']));
-                     } else {
-                         $container->setParameter('env(MAILER_DSN)', $this->getMailerDsn($container));
-                     }
-                 }
-                 return $extensionConfigs;
-             case 'doctrine':
-                 if (!isset($_SERVER['DATABASE_URL'])) {
-                     $container->setParameter('env(DATABASE_URL)', $this->getDatabaseUrl($container, $extensionConfigs));
-                 }
-                 $extensionConfigs = $this->addDefaultPdoDriverOptions($extensionConfigs, $container);
-                 $extensionConfigs = $this->addDefaultDoctrineMapping($extensionConfigs, $container);
-                 $extensionConfigs = $this->enableStrictMode($extensionConfigs, $container);
-                 $extensionConfigs = $this->setDefaultCollation($extensionConfigs);
-                 return $extensionConfigs;
-             case 'nelmio_security':
-                 return $this->checkClickjackingPaths($extensionConfigs);
-         }
-         return $extensionConfigs;
-     }
-     /**
-      * Adds backwards compatibility for the %prepend_locale% parameter.
-      *
-      * @return array<string,array<string,mixed>>
-      */
-     private function handlePrependLocale(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         if (!$container->hasParameter('prepend_locale')) {
-             return $extensionConfigs;
-         }
-         foreach ($extensionConfigs as $extensionConfig) {
-             if (isset($extensionConfig['prepend_locale'])) {
-                 return $extensionConfigs;
-             }
-         }
-         trigger_deprecation('contao/manager-bundle', '4.6', 'Defining the "prepend_locale" parameter in the parameters.yml file has been deprecated and will no longer work in Contao 5.0. Define the "contao.prepend_locale" parameter in the config.yml file instead.');
-         $extensionConfigs[] = [
-             'prepend_locale' => '%prepend_locale%',
-         ];
-         return $extensionConfigs;
-     }
-     /**
-      * Sets the PDO driver options if applicable (#2459).
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function addDefaultPdoDriverOptions(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         // Do not add PDO options if the constant does not exist
-         if (!\defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
-             return $extensionConfigs;
-         }
-         [$driver, $options] = $this->parseDbalDriverAndOptions($extensionConfigs, $container);
-         // Do not add PDO options if custom options have been defined
-         if (isset($options[\PDO::MYSQL_ATTR_MULTI_STATEMENTS])) {
-             return $extensionConfigs;
-         }
-         // Do not add PDO options if the selected driver is not mysql
-         if (null !== $driver && 'mysql' !== $driver) {
-             return $extensionConfigs;
-         }
-         $extensionConfigs[] = [
-             'dbal' => [
-                 'connections' => [
-                     'default' => [
-                         'options' => [
-                             \PDO::MYSQL_ATTR_MULTI_STATEMENTS => false,
-                         ],
-                     ],
-                 ],
-             ],
-         ];
-         return $extensionConfigs;
-     }
-     /**
-      * Adds a default ORM mapping for the App namespace if none is configured.
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function addDefaultDoctrineMapping(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         $defaultEntityManager = 'default';
-         foreach ($extensionConfigs as $config) {
-             if (null !== $em = $config['orm']['default_entity_manager'] ?? null) {
-                 $defaultEntityManager = $em;
-             }
-         }
-         $mappings = [];
-         $autoMappingEnabled = false;
-         foreach ($extensionConfigs as $config) {
-             $mappings[] = $config['orm']['mappings'] ?? [];
-             foreach ($config['orm']['entity_managers'] ?? [] as $em) {
-                 $mappings[] = $em['mappings'] ?? [];
-             }
-             $autoMappingEnabled |= ($config['orm']['auto_mapping'] ?? false)
-                 || ($config['orm']['entity_managers'][$defaultEntityManager]['auto_mapping'] ?? false);
-         }
-         // Skip if auto mapping is not enabled for the default entity manager.
-         if (!$autoMappingEnabled) {
-             return $extensionConfigs;
-         }
-         // Skip if a mapping with the name or alias "App" already exists or any
-         // mapping already targets "%kernel.project_dir%/src/Entity".
-         foreach (array_replace(...$mappings) as $name => $values) {
-             if (
-                 'App' === $name
-                 || 'App' === ($values['alias'] ?? '')
-                 || '%kernel.project_dir%/src/Entity' === ($values['dir'] ?? '')
-             ) {
-                 return $extensionConfigs;
-             }
-         }
-         // Skip if the "%kernel.project_dir%/src/Entity" directory does not exist.
-         if (!$container->fileExists(Path::join($container->getParameter('kernel.project_dir'), 'src/Entity'))) {
-             return $extensionConfigs;
-         }
-         $extensionConfigs[] = [
-             'orm' => [
-                 'entity_managers' => [
-                     $defaultEntityManager => [
-                         'mappings' => [
-                             'App' => [
-                                 'dir' => '%kernel.project_dir%/src/Entity',
-                                 'is_bundle' => false,
-                                 'prefix' => 'App\Entity',
-                                 'alias' => 'App',
-                             ],
-                         ],
-                     ],
-                 ],
-             ],
-         ];
-         return $extensionConfigs;
-     }
-     /**
-      * Enables the SQL strict mode for PDO and MySQL drivers.
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function enableStrictMode(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         [$driver, $options] = $this->parseDbalDriverAndOptions($extensionConfigs, $container);
-         // Skip if driver is not supported
-         if (null === ($key = ['mysql' => 1002, 'mysqli' => 3][$driver] ?? null)) {
-             return $extensionConfigs;
-         }
-         // Skip if init command is already configured
-         if (isset($options[$key])) {
-             return $extensionConfigs;
-         }
-         // Enable strict mode
-         $extensionConfigs[] = [
-             'dbal' => [
-                 'connections' => [
-                     'default' => [
-                         'options' => [
-                             $key => "SET SESSION sql_mode=CONCAT(@@sql_mode, IF(INSTR(@@sql_mode, 'STRICT_'), '', ',TRADITIONAL'))",
-                         ],
-                     ],
-                 ],
-             ],
-         ];
-         return $extensionConfigs;
-     }
-     /**
-      * Sets the "collate" and "collation" options to the same value (see #4798).
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function setDefaultCollation(array $extensionConfigs): array
-     {
-         $defaultCollation = null;
-         foreach ($extensionConfigs as $config) {
-             $collation = $config['dbal']['connections']['default']['default_table_options']['collation'] ?? $config['dbal']['connections']['default']['default_table_options']['collate'] ?? null;
-             if (null !== $collation) {
-                 $defaultCollation = $collation;
-             }
-         }
-         if (null !== $defaultCollation) {
-             $extensionConfigs[] = [
-                 'dbal' => [
-                     'connections' => [
-                         'default' => [
-                             'default_table_options' => [
-                                 'collate' => $defaultCollation,
-                                 'collation' => $defaultCollation,
-                             ],
-                         ],
-                     ],
-                 ],
-             ];
-         }
-         return $extensionConfigs;
-     }
-     /**
-      * Changes the mail transport from "mail" to "sendmail".
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function checkMailerTransport(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         if ('mail' === $container->getParameter('mailer_transport')) {
-             $container->setParameter('mailer_transport', 'sendmail');
-         }
-         return $extensionConfigs;
-     }
-     /**
-      * Dynamically adds a default mailer to the config, if no mailer is defined.
-      *
-      * We cannot add a default mailer configuration to the skeleton config.yml,
-      * since different types of configurations are not allowed.
-      *
-      * For example, if the Manager Bundle defined
-      *
-      *     framework:
-      *         mailer:
-      *             dsn: '%env(MAILER_DSN)%'
-      *
-      * in the skeleton config.yml and the user adds
-      *
-      *     framework:
-      *         mailer:
-      *             transports:
-      *                 foobar: 'smtps://smtp.example.com'
-      *
-      * to their config.yml, the merged configuration will lead to an error, since
-      * you cannot use "framework.mailer.dsn" together with "framework.mailer.transports".
-      * Thus, the default mailer configuration needs to be added dynamically if
-      * not already present.
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function addDefaultMailer(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         foreach ($extensionConfigs as $config) {
-             if (isset($config['mailer']) && (isset($config['mailer']['transports']) || isset($config['mailer']['dsn']))) {
-                 return $extensionConfigs;
-             }
-         }
-         $extensionConfigs[] = [
-             'mailer' => [
-                 'dsn' => '%env(MAILER_DSN)%',
-             ],
-         ];
-         return $extensionConfigs;
-     }
-     /**
-      * @return array{0: string|null, 1: array<string, mixed>}
-      */
-     private function parseDbalDriverAndOptions(array $extensionConfigs, ContainerBuilder $container): array
-     {
-         $driver = null;
-         $url = null;
-         $options = [];
-         foreach ($extensionConfigs as $config) {
-             if (null !== ($driverConfig = $config['dbal']['connections']['default']['driver'] ?? null)) {
-                 $driver = $driverConfig;
-             }
-             if (null !== ($urlConfig = $config['dbal']['connections']['default']['url'] ?? null)) {
-                 $url = $container->resolveEnvPlaceholders($urlConfig, true);
-             }
-             if (null !== ($optionsConfig = $config['dbal']['connections']['default']['options'] ?? null)) {
-                 $options[] = $optionsConfig;
-             }
-         }
-         // If URL is set, it overrides the driver option
-         if (!empty($url)) {
-             $driver = str_replace('-', '_', parse_url($url, PHP_URL_SCHEME));
-         }
-         // Normalize the driver name
-         if (\in_array($driver, ['pdo_mysql', 'mysql2'], true)) {
-             $driver = 'mysql';
-         }
-         return [$driver, array_replace([], ...$options)];
-     }
-     /**
-      * Adds a clickjacking configuration for "^/.*" if not already defined.
-      *
-      * @return array<string,array<string,array<string,array<string,mixed>>>>
-      */
-     private function checkClickjackingPaths(array $extensionConfigs): array
-     {
-         foreach ($extensionConfigs as $extensionConfig) {
-             if (isset($extensionConfig['clickjacking']['paths']['^/.*'])) {
-                 return $extensionConfigs;
-             }
-         }
-         $extensionConfigs[] = [
-             'clickjacking' => [
-                 'paths' => [
-                     '^/.*' => 'SAMEORIGIN',
-                 ],
-             ],
-         ];
-         return $extensionConfigs;
-     }
-     private function getDatabaseUrl(ContainerBuilder $container, array $extensionConfigs): string
-     {
-         $driver = 'mysql';
-         foreach ($extensionConfigs as $extensionConfig) {
-             // Loop over all configs so the last one wins
-             $driver = $extensionConfig['dbal']['connections']['default']['driver'] ?? $driver;
-         }
-         $userPassword = '';
-         if ($user = $container->getParameter('database_user')) {
-             $userPassword = $this->encodeUrlParameter((string) $user);
-             if ($password = $container->getParameter('database_password')) {
-                 $userPassword .= ':'.$this->encodeUrlParameter((string) $password);
-             }
-             $userPassword .= '@';
-         }
-         $dbName = '';
-         if ($name = $container->getParameter('database_name')) {
-             $dbName .= '/'.$this->encodeUrlParameter((string) $name);
-         }
-         if ($container->hasParameter('database_version') && $version = $container->getParameter('database_version')) {
-             $dbName .= '?serverVersion='.$this->encodeUrlParameter((string) $version);
-         }
-         return sprintf(
-             '%s://%s%s:%s%s',
-             str_replace('_', '-', $driver),
-             $userPassword,
-             $container->getParameter('database_host'),
-             (int) $container->getParameter('database_port'),
-             $dbName
-         );
-     }
-     private function getMailerDsnFromMailerUrl(string $mailerUrl): string
-     {
-         if (false === $parts = parse_url($mailerUrl)) {
-             throw new \InvalidArgumentException(sprintf('The MAILER_URL "%s" is not valid.', $mailerUrl));
-         }
-         $options = [
-             'transport' => null,
-             'username' => null,
-             'password' => null,
-             'host' => null,
-             'port' => null,
-             'encryption' => null,
-         ];
-         $queryOptions = [];
-         if (isset($parts['scheme'])) {
-             $options['transport'] = $parts['scheme'];
-         }
-         if (isset($parts['user'])) {
-             $options['username'] = rawurldecode($parts['user']);
-         }
-         if (isset($parts['pass'])) {
-             $options['password'] = rawurldecode($parts['pass']);
-         }
-         if (isset($parts['host'])) {
-             $options['host'] = rawurldecode($parts['host']);
-         }
-         if (isset($parts['port'])) {
-             $options['port'] = $parts['port'];
-         }
-         if (isset($parts['query'])) {
-             parse_str($parts['query'], $query);
-             foreach ($query as $key => $value) {
-                 if (empty($key)) {
-                     continue;
-                 }
-                 if (\array_key_exists($key, $options)) {
-                     $options[$key] = $value;
-                 } else {
-                     $queryOptions[$key] = $value;
-                 }
-             }
-         }
-         if (empty($options['transport'])) {
-             throw new \InvalidArgumentException(sprintf('The MAILER_URL "%s" is not valid.', $mailerUrl));
-         }
-         if (\in_array($options['transport'], ['mail', 'sendmail'], true)) {
-             return 'sendmail://default';
-         }
-         /*
-          * Check for gmail transport.
-          *
-          * With Swiftmailer a DSN like "gmail://username:password@localhost" was
-          * supported out-of-the-box. See https://symfony.com/doc/4.4/email.html#using-gmail-to-send-emails
-          * Symfony Mailer supports something similar, but only with an additional
-          * dependency. See https://symfony.com/doc/4.4/components/mailer.html#transport
-          *
-          * Thus we add backwards compatibility for the "gmail" transport here.
-          */
-         if ('gmail' === $options['transport']) {
-             $options['host'] = 'smtp.gmail.com';
-             $options['transport'] = 'smtps';
-         }
-         if (empty($options['host']) || !\in_array($options['transport'], ['smtp', 'smtps'], true)) {
-             throw new \InvalidArgumentException(sprintf('The MAILER_URL "%s" is not valid.', $mailerUrl));
-         }
-         $transport = $options['transport'];
-         $credentials = '';
-         $port = '';
-         if (!empty($options['encryption']) && 'ssl' === $options['encryption']) {
-             $transport = 'smtps';
-         }
-         if (!empty($options['username'])) {
-             $credentials .= $this->encodeUrlParameter((string) $options['username']);
-             if (!empty($options['password'])) {
-                 $credentials .= ':'.$this->encodeUrlParameter((string) $options['password']);
-             }
-             $credentials .= '@';
-         }
-         if (!empty($options['port'])) {
-             $port = ':'.$options['port'];
-         }
-         return sprintf(
-             '%s://%s%s%s%s',
-             $transport,
-             $credentials,
-             $options['host'],
-             $port,
-             !empty($queryOptions) ? '?'.http_build_query($queryOptions) : ''
-         );
-     }
-     private function getMailerDsn(ContainerBuilder $container): string
-     {
-         if (!$container->hasParameter('mailer_transport') || 'sendmail' === $container->getParameter('mailer_transport')) {
-             return class_exists(NativeTransportFactory::class) ? 'native://default' : 'sendmail://default';
-         }
-         $transport = 'smtp';
-         $credentials = '';
-         $portSuffix = '';
-         if (($encryption = $container->getParameter('mailer_encryption')) && 'ssl' === $encryption) {
-             $transport = 'smtps';
-         }
-         if ($user = $container->getParameter('mailer_user')) {
-             $credentials .= $this->encodeUrlParameter((string) $user);
-             if ($password = $container->getParameter('mailer_password')) {
-                 $credentials .= ':'.$this->encodeUrlParameter((string) $password);
-             }
-             $credentials .= '@';
-         }
-         if ($port = $container->getParameter('mailer_port')) {
-             $portSuffix = ':'.$port;
-         }
-         return sprintf(
-             '%s://%s%s%s',
-             $transport,
-             $credentials,
-             $container->getParameter('mailer_host'),
-             $portSuffix
-         );
-     }
-     private function encodeUrlParameter(string $parameter): string
-     {
-         return str_replace('%', '%%', rawurlencode($parameter));
-     }
- }
-