189 lines
7.2 KiB
PHP
189 lines
7.2 KiB
PHP
|
<?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\Component\Mailer;
|
||
|
|
||
|
use Psr\EventDispatcher\EventDispatcherInterface;
|
||
|
use Psr\Log\LoggerInterface;
|
||
|
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Infobip\Transport\InfobipTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\MailerSend\Transport\MailerSendTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Mailjet\Transport\MailjetTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\MailPace\Transport\MailPaceTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Scaleway\Transport\ScalewayTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
|
||
|
use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory;
|
||
|
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||
|
use Symfony\Component\Mailer\Transport\FailoverTransport;
|
||
|
use Symfony\Component\Mailer\Transport\NativeTransportFactory;
|
||
|
use Symfony\Component\Mailer\Transport\NullTransportFactory;
|
||
|
use Symfony\Component\Mailer\Transport\RoundRobinTransport;
|
||
|
use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
|
||
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
|
||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||
|
use Symfony\Component\Mailer\Transport\Transports;
|
||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||
|
|
||
|
/**
|
||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||
|
*/
|
||
|
final class Transport
|
||
|
{
|
||
|
private const FACTORY_CLASSES = [
|
||
|
BrevoTransportFactory::class,
|
||
|
GmailTransportFactory::class,
|
||
|
InfobipTransportFactory::class,
|
||
|
MailerSendTransportFactory::class,
|
||
|
MailgunTransportFactory::class,
|
||
|
MailjetTransportFactory::class,
|
||
|
MailPaceTransportFactory::class,
|
||
|
MandrillTransportFactory::class,
|
||
|
OhMySmtpTransportFactory::class,
|
||
|
PostmarkTransportFactory::class,
|
||
|
ScalewayTransportFactory::class,
|
||
|
SendgridTransportFactory::class,
|
||
|
SendinblueTransportFactory::class,
|
||
|
SesTransportFactory::class,
|
||
|
];
|
||
|
|
||
|
private iterable $factories;
|
||
|
|
||
|
public static function fromDsn(#[\SensitiveParameter] string $dsn, ?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): TransportInterface
|
||
|
{
|
||
|
$factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
|
||
|
|
||
|
return $factory->fromString($dsn);
|
||
|
}
|
||
|
|
||
|
public static function fromDsns(#[\SensitiveParameter] array $dsns, ?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): TransportInterface
|
||
|
{
|
||
|
$factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
|
||
|
|
||
|
return $factory->fromStrings($dsns);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param TransportFactoryInterface[] $factories
|
||
|
*/
|
||
|
public function __construct(iterable $factories)
|
||
|
{
|
||
|
$this->factories = $factories;
|
||
|
}
|
||
|
|
||
|
public function fromStrings(#[\SensitiveParameter] array $dsns): Transports
|
||
|
{
|
||
|
$transports = [];
|
||
|
foreach ($dsns as $name => $dsn) {
|
||
|
$transports[$name] = $this->fromString($dsn);
|
||
|
}
|
||
|
|
||
|
return new Transports($transports);
|
||
|
}
|
||
|
|
||
|
public function fromString(#[\SensitiveParameter] string $dsn): TransportInterface
|
||
|
{
|
||
|
[$transport, $offset] = $this->parseDsn($dsn);
|
||
|
if ($offset !== \strlen($dsn)) {
|
||
|
throw new InvalidArgumentException('The mailer DSN has some garbage at the end.');
|
||
|
}
|
||
|
|
||
|
return $transport;
|
||
|
}
|
||
|
|
||
|
private function parseDsn(#[\SensitiveParameter] string $dsn, int $offset = 0): array
|
||
|
{
|
||
|
static $keywords = [
|
||
|
'failover' => FailoverTransport::class,
|
||
|
'roundrobin' => RoundRobinTransport::class,
|
||
|
];
|
||
|
|
||
|
while (true) {
|
||
|
foreach ($keywords as $name => $class) {
|
||
|
$name .= '(';
|
||
|
if ($name === substr($dsn, $offset, \strlen($name))) {
|
||
|
$offset += \strlen($name) - 1;
|
||
|
preg_match('{\(([^()]|(?R))*\)}A', $dsn, $matches, 0, $offset);
|
||
|
if (!isset($matches[0])) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
++$offset;
|
||
|
$args = [];
|
||
|
while (true) {
|
||
|
[$arg, $offset] = $this->parseDsn($dsn, $offset);
|
||
|
$args[] = $arg;
|
||
|
if (\strlen($dsn) === $offset) {
|
||
|
break;
|
||
|
}
|
||
|
++$offset;
|
||
|
if (')' === $dsn[$offset - 1]) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return [new $class($args), $offset];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) {
|
||
|
throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords))));
|
||
|
}
|
||
|
|
||
|
if ($pos = strcspn($dsn, ' )', $offset)) {
|
||
|
return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset, $pos))), $offset + $pos];
|
||
|
}
|
||
|
|
||
|
return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset))), \strlen($dsn)];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function fromDsnObject(Dsn $dsn): TransportInterface
|
||
|
{
|
||
|
foreach ($this->factories as $factory) {
|
||
|
if ($factory->supports($dsn)) {
|
||
|
return $factory->create($dsn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
throw new UnsupportedSchemeException($dsn);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return \Traversable<int, TransportFactoryInterface>
|
||
|
*/
|
||
|
public static function getDefaultFactories(?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): \Traversable
|
||
|
{
|
||
|
foreach (self::FACTORY_CLASSES as $factoryClass) {
|
||
|
if (class_exists($factoryClass)) {
|
||
|
yield new $factoryClass($dispatcher, $client, $logger);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
yield new NullTransportFactory($dispatcher, $client, $logger);
|
||
|
|
||
|
yield new SendmailTransportFactory($dispatcher, $client, $logger);
|
||
|
|
||
|
yield new EsmtpTransportFactory($dispatcher, $client, $logger);
|
||
|
|
||
|
yield new NativeTransportFactory($dispatcher, $client, $logger);
|
||
|
}
|
||
|
}
|