vendor/symfony/mailer/Transport.php line 59

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Mailer;
  11. use Psr\EventDispatcher\EventDispatcherInterface;
  12. use Psr\Log\LoggerInterface;
  13. use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory;
  14. use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory;
  15. use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory;
  16. use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory;
  17. use Symfony\Component\Mailer\Bridge\Mailjet\Transport\MailjetTransportFactory;
  18. use Symfony\Component\Mailer\Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory;
  19. use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
  20. use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
  21. use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory;
  22. use Symfony\Component\Mailer\Exception\InvalidArgumentException;
  23. use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
  24. use Symfony\Component\Mailer\Transport\Dsn;
  25. use Symfony\Component\Mailer\Transport\FailoverTransport;
  26. use Symfony\Component\Mailer\Transport\NativeTransportFactory;
  27. use Symfony\Component\Mailer\Transport\NullTransportFactory;
  28. use Symfony\Component\Mailer\Transport\RoundRobinTransport;
  29. use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
  30. use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
  31. use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
  32. use Symfony\Component\Mailer\Transport\TransportInterface;
  33. use Symfony\Component\Mailer\Transport\Transports;
  34. use Symfony\Contracts\HttpClient\HttpClientInterface;
  35. /**
  36. * @author Fabien Potencier <fabien@symfony.com>
  37. * @author Konstantin Myakshin <molodchick@gmail.com>
  38. */
  39. final class Transport
  40. {
  41. private const FACTORY_CLASSES = [
  42. GmailTransportFactory::class,
  43. MailgunTransportFactory::class,
  44. MailjetTransportFactory::class,
  45. MandrillTransportFactory::class,
  46. OhMySmtpTransportFactory::class,
  47. PostmarkTransportFactory::class,
  48. SendgridTransportFactory::class,
  49. SendinblueTransportFactory::class,
  50. SesTransportFactory::class,
  51. ];
  52. private iterable $factories;
  53. public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
  54. {
  55. $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
  56. return $factory->fromString($dsn);
  57. }
  58. public static function fromDsns(array $dsns, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
  59. {
  60. $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
  61. return $factory->fromStrings($dsns);
  62. }
  63. /**
  64. * @param TransportFactoryInterface[] $factories
  65. */
  66. public function __construct(iterable $factories)
  67. {
  68. $this->factories = $factories;
  69. }
  70. public function fromStrings(array $dsns): Transports
  71. {
  72. $transports = [];
  73. foreach ($dsns as $name => $dsn) {
  74. $transports[$name] = $this->fromString($dsn);
  75. }
  76. return new Transports($transports);
  77. }
  78. public function fromString(string $dsn): TransportInterface
  79. {
  80. [$transport, $offset] = $this->parseDsn($dsn);
  81. if ($offset !== \strlen($dsn)) {
  82. throw new InvalidArgumentException(sprintf('The DSN has some garbage at the end: "%s".', substr($dsn, $offset)));
  83. }
  84. return $transport;
  85. }
  86. private function parseDsn(string $dsn, int $offset = 0): array
  87. {
  88. static $keywords = [
  89. 'failover' => FailoverTransport::class,
  90. 'roundrobin' => RoundRobinTransport::class,
  91. ];
  92. while (true) {
  93. foreach ($keywords as $name => $class) {
  94. $name .= '(';
  95. if ($name === substr($dsn, $offset, \strlen($name))) {
  96. $offset += \strlen($name) - 1;
  97. preg_match('{\(([^()]|(?R))*\)}A', $dsn, $matches, 0, $offset);
  98. if (!isset($matches[0])) {
  99. continue;
  100. }
  101. ++$offset;
  102. $args = [];
  103. while (true) {
  104. [$arg, $offset] = $this->parseDsn($dsn, $offset);
  105. $args[] = $arg;
  106. if (\strlen($dsn) === $offset) {
  107. break;
  108. }
  109. ++$offset;
  110. if (')' === $dsn[$offset - 1]) {
  111. break;
  112. }
  113. }
  114. return [new $class($args), $offset];
  115. }
  116. }
  117. if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) {
  118. throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords))));
  119. }
  120. if ($pos = strcspn($dsn, ' )', $offset)) {
  121. return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset, $pos))), $offset + $pos];
  122. }
  123. return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset))), \strlen($dsn)];
  124. }
  125. }
  126. public function fromDsnObject(Dsn $dsn): TransportInterface
  127. {
  128. foreach ($this->factories as $factory) {
  129. if ($factory->supports($dsn)) {
  130. return $factory->create($dsn);
  131. }
  132. }
  133. throw new UnsupportedSchemeException($dsn);
  134. }
  135. /**
  136. * @return \Traversable<int, TransportFactoryInterface>
  137. */
  138. public static function getDefaultFactories(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): \Traversable
  139. {
  140. foreach (self::FACTORY_CLASSES as $factoryClass) {
  141. if (class_exists($factoryClass)) {
  142. yield new $factoryClass($dispatcher, $client, $logger);
  143. }
  144. }
  145. yield new NullTransportFactory($dispatcher, $client, $logger);
  146. yield new SendmailTransportFactory($dispatcher, $client, $logger);
  147. yield new EsmtpTransportFactory($dispatcher, $client, $logger);
  148. yield new NativeTransportFactory($dispatcher, $client, $logger);
  149. }
  150. }