Merge branch '4.4'
* 4.4: [WebProfilerBundle] Remove unneeded information in the routing panel Add transport factories (closes #31385, closes #32523) [Lock] remove uusage of the StoreInterface [HttpClient] make toStream() throw by default [Mailer] added XML configuration for the mailer envelope added missing test [Mailer] Allow register mailer configuration in xml format [VarDumper] Allow to configure VarDumperTestTrait casters & flags Improve errors when trying to find a writable property [Lock] add aliases for LockFactory fixed CS fix some deprecations and add upgrade instructions fix typo Added Nl translations fixed CS [FrameworkBundle] Fix descriptor of routes described as callable array [Debug][DebugClassLoader] Include found files instead of requiring them [HttpKernel] fix tests Adding missing event_dispatcher wiring for messenger.middleware.send_message
This commit is contained in:
commit
330a093b83
@ -71,6 +71,7 @@ Form
|
|||||||
FrameworkBundle
|
FrameworkBundle
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
* Deprecated booting the kernel before running `WebTestCase::createClient()`.
|
||||||
* Deprecated support for `templating` engine in `TemplateController`, use Twig instead
|
* Deprecated support for `templating` engine in `TemplateController`, use Twig instead
|
||||||
* The `$parser` argument of `ControllerResolver::__construct()` and `DelegatingLoader::__construct()`
|
* The `$parser` argument of `ControllerResolver::__construct()` and `DelegatingLoader::__construct()`
|
||||||
has been deprecated.
|
has been deprecated.
|
||||||
@ -90,8 +91,17 @@ HttpFoundation
|
|||||||
HttpKernel
|
HttpKernel
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* Implementing the `BundleInterface` without implementing the `getPublicDir()` method is deprecated.
|
||||||
|
This method will be added to the interface in 5.0.
|
||||||
* The `DebugHandlersListener` class has been marked as `final`
|
* The `DebugHandlersListener` class has been marked as `final`
|
||||||
|
|
||||||
|
Lock
|
||||||
|
----
|
||||||
|
|
||||||
|
* Deprecated `Symfony\Component\Lock\StoreInterface` in favor of `Symfony\Component\Lock\BlockingStoreInterface` and
|
||||||
|
`Symfony\Component\Lock\PersistStoreInterface`.
|
||||||
|
* `Factory` is deprecated, use `LockFactory` instead
|
||||||
|
|
||||||
Messenger
|
Messenger
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@ -143,3 +153,8 @@ WebProfilerBundle
|
|||||||
|
|
||||||
* Deprecated the `ExceptionController::templateExists()` method
|
* Deprecated the `ExceptionController::templateExists()` method
|
||||||
* Deprecated the `TemplateManager::templateExists()` method
|
* Deprecated the `TemplateManager::templateExists()` method
|
||||||
|
|
||||||
|
WebServerBundle
|
||||||
|
---------------
|
||||||
|
|
||||||
|
* The bundle is deprecated and will be removed in 5.0.
|
||||||
|
@ -208,6 +208,8 @@ Form
|
|||||||
FrameworkBundle
|
FrameworkBundle
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
* Dropped support for booting the kernel before running `WebTestCase::createClient()`. `createClient()` will throw an
|
||||||
|
exception if the kernel was already booted before.
|
||||||
* Removed the `framework.templating` option, use Twig instead.
|
* Removed the `framework.templating` option, use Twig instead.
|
||||||
* The project dir argument of the constructor of `AssetsInstallCommand` is required.
|
* The project dir argument of the constructor of `AssetsInstallCommand` is required.
|
||||||
* Removed support for `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method`
|
* Removed support for `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method`
|
||||||
@ -275,6 +277,7 @@ HttpFoundation
|
|||||||
HttpKernel
|
HttpKernel
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* The `getPublicDir()` method has been added to the `BundleInterface`.
|
||||||
* Removed `Client`, use `HttpKernelBrowser` instead
|
* Removed `Client`, use `HttpKernelBrowser` instead
|
||||||
* The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been removed
|
* The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been removed
|
||||||
* The `KernelInterface::getName()` and the `kernel.name` parameter have been removed
|
* The `KernelInterface::getName()` and the `kernel.name` parameter have been removed
|
||||||
@ -301,6 +304,13 @@ Intl
|
|||||||
* Removed `Intl::getLocaleBundle()`, use `Locales` instead
|
* Removed `Intl::getLocaleBundle()`, use `Locales` instead
|
||||||
* Removed `Intl::getRegionBundle()`, use `Countries` instead
|
* Removed `Intl::getRegionBundle()`, use `Countries` instead
|
||||||
|
|
||||||
|
Lock
|
||||||
|
----
|
||||||
|
|
||||||
|
* Removed `Symfony\Component\Lock\StoreInterface` in favor of `Symfony\Component\Lock\BlockingStoreInterface` and
|
||||||
|
`Symfony\Component\Lock\PersistStoreInterface`.
|
||||||
|
* Removed `Factory`, use `LockFactory` instead
|
||||||
|
|
||||||
Messenger
|
Messenger
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@ -583,3 +593,8 @@ Yaml
|
|||||||
|
|
||||||
* The parser is now stricter and will throw a `ParseException` when a
|
* The parser is now stricter and will throw a `ParseException` when a
|
||||||
mapping is found inside a multi-line string.
|
mapping is found inside a multi-line string.
|
||||||
|
|
||||||
|
WebServerBundle
|
||||||
|
---------------
|
||||||
|
|
||||||
|
* The bundle has been removed.
|
||||||
|
@ -540,7 +540,7 @@ class TextDescriptor extends Descriptor
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (\is_array($controller)) {
|
if (\is_array($controller)) {
|
||||||
$r = new \ReflectionMethod($controller);
|
$r = new \ReflectionMethod($controller[0], $controller[1]);
|
||||||
} elseif ($controller instanceof \Closure) {
|
} elseif ($controller instanceof \Closure) {
|
||||||
$r = new \ReflectionFunction($controller);
|
$r = new \ReflectionFunction($controller);
|
||||||
} elseif (method_exists($controller, '__invoke')) {
|
} elseif (method_exists($controller, '__invoke')) {
|
||||||
|
@ -70,11 +70,18 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
|
|||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
use Symfony\Component\Lock\Factory;
|
use Symfony\Component\Lock\Factory;
|
||||||
use Symfony\Component\Lock\Lock;
|
use Symfony\Component\Lock\Lock;
|
||||||
|
use Symfony\Component\Lock\LockFactory;
|
||||||
use Symfony\Component\Lock\LockInterface;
|
use Symfony\Component\Lock\LockInterface;
|
||||||
use Symfony\Component\Lock\PersistStoreInterface;
|
use Symfony\Component\Lock\PersistStoreInterface;
|
||||||
use Symfony\Component\Lock\Store\FlockStore;
|
use Symfony\Component\Lock\Store\FlockStore;
|
||||||
use Symfony\Component\Lock\Store\StoreFactory;
|
use Symfony\Component\Lock\Store\StoreFactory;
|
||||||
use Symfony\Component\Lock\StoreInterface;
|
use Symfony\Component\Lock\StoreInterface;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
|
||||||
use Symfony\Component\Mailer\Mailer;
|
use Symfony\Component\Mailer\Mailer;
|
||||||
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||||
use Symfony\Component\Messenger\MessageBus;
|
use Symfony\Component\Messenger\MessageBus;
|
||||||
@ -1441,7 +1448,7 @@ class FrameworkExtension extends Extension
|
|||||||
$container->setDefinition($connectionDefinitionId, $connectionDefinition);
|
$container->setDefinition($connectionDefinitionId, $connectionDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
$storeDefinition = new Definition(StoreInterface::class);
|
$storeDefinition = new Definition(PersistStoreInterface::class);
|
||||||
$storeDefinition->setPublic(false);
|
$storeDefinition->setPublic(false);
|
||||||
$storeDefinition->setFactory([StoreFactory::class, 'createStore']);
|
$storeDefinition->setFactory([StoreFactory::class, 'createStore']);
|
||||||
$storeDefinition->setArguments([new Reference($connectionDefinitionId)]);
|
$storeDefinition->setArguments([new Reference($connectionDefinitionId)]);
|
||||||
@ -1486,11 +1493,13 @@ class FrameworkExtension extends Extension
|
|||||||
$container->setAlias(StoreInterface::class, new Alias('lock.store', false));
|
$container->setAlias(StoreInterface::class, new Alias('lock.store', false));
|
||||||
$container->setAlias(PersistStoreInterface::class, new Alias('lock.store', false));
|
$container->setAlias(PersistStoreInterface::class, new Alias('lock.store', false));
|
||||||
$container->setAlias(Factory::class, new Alias('lock.factory', false));
|
$container->setAlias(Factory::class, new Alias('lock.factory', false));
|
||||||
|
$container->setAlias(LockFactory::class, new Alias('lock.factory', false));
|
||||||
$container->setAlias(LockInterface::class, new Alias('lock', false));
|
$container->setAlias(LockInterface::class, new Alias('lock', false));
|
||||||
} else {
|
} else {
|
||||||
$container->registerAliasForArgument('lock.'.$resourceName.'.store', StoreInterface::class, $resourceName.'.lock.store');
|
$container->registerAliasForArgument('lock.'.$resourceName.'.store', StoreInterface::class, $resourceName.'.lock.store');
|
||||||
$container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistStoreInterface::class, $resourceName.'.lock.store');
|
$container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistStoreInterface::class, $resourceName.'.lock.store');
|
||||||
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', Factory::class, $resourceName.'.lock.factory');
|
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', Factory::class, $resourceName.'.lock.factory');
|
||||||
|
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory');
|
||||||
$container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock');
|
$container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1793,8 +1802,24 @@ class FrameworkExtension extends Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
$loader->load('mailer.xml');
|
$loader->load('mailer.xml');
|
||||||
|
$loader->load('mailer_transports.xml');
|
||||||
$container->getDefinition('mailer.default_transport')->setArgument(0, $config['dsn']);
|
$container->getDefinition('mailer.default_transport')->setArgument(0, $config['dsn']);
|
||||||
|
|
||||||
|
$classToServices = [
|
||||||
|
SesTransportFactory::class => 'mailer.transport_factory.amazon',
|
||||||
|
GmailTransportFactory::class => 'mailer.transport_factory.gmail',
|
||||||
|
MandrillTransportFactory::class => 'mailer.transport_factory.mailchimp',
|
||||||
|
MailgunTransportFactory::class => 'mailer.transport_factory.mailgun',
|
||||||
|
PostmarkTransportFactory::class => 'mailer.transport_factory.postmark',
|
||||||
|
SendgridTransportFactory::class => 'mailer.transport_factory.sendgrid',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($classToServices as $class => $service) {
|
||||||
|
if (!class_exists($class)) {
|
||||||
|
$container->removeDefinition($service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$recipients = $config['envelope']['recipients'] ?? null;
|
$recipients = $config['envelope']['recipients'] ?? null;
|
||||||
$sender = $config['envelope']['sender'] ?? null;
|
$sender = $config['envelope']['sender'] ?? null;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<service id="lock.strategy.majority" class="Symfony\Component\Lock\Strategy\ConsensusStrategy" />
|
<service id="lock.strategy.majority" class="Symfony\Component\Lock\Strategy\ConsensusStrategy" />
|
||||||
|
|
||||||
<service id="lock.factory.abstract" class="Symfony\Component\Lock\Factory" abstract="true">
|
<service id="lock.factory.abstract" class="Symfony\Component\Lock\LockFactory" abstract="true">
|
||||||
<tag name="monolog.logger" channel="lock" />
|
<tag name="monolog.logger" channel="lock" />
|
||||||
<argument /> <!-- Store -->
|
<argument /> <!-- Store -->
|
||||||
<call method="setLogger">
|
<call method="setLogger">
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
<service id="mailer" alias="mailer.mailer" />
|
<service id="mailer" alias="mailer.mailer" />
|
||||||
<service id="Symfony\Component\Mailer\MailerInterface" alias="mailer.mailer" />
|
<service id="Symfony\Component\Mailer\MailerInterface" alias="mailer.mailer" />
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory" class="Symfony\Component\Mailer\Transport">
|
||||||
|
<argument type="tagged_iterator" tag="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<service id="mailer.default_transport" class="Symfony\Component\Mailer\Transport\TransportInterface">
|
<service id="mailer.default_transport" class="Symfony\Component\Mailer\Transport\TransportInterface">
|
||||||
<factory class="Symfony\Component\Mailer\Transport" method="fromDsn" />
|
<factory service="mailer.transport_factory" method="fromString" />
|
||||||
<argument /> <!-- env(MAILER_DSN) -->
|
<argument /> <!-- env(MAILER_DSN) -->
|
||||||
<argument type="service" id="event_dispatcher" />
|
|
||||||
<argument type="service" id="http_client" on-invalid="ignore" />
|
|
||||||
<argument type="service" id="logger" on-invalid="ignore" />
|
|
||||||
</service>
|
</service>
|
||||||
<service id="Symfony\Component\Mailer\Transport\TransportInterface" alias="mailer.default_transport" />
|
<service id="Symfony\Component\Mailer\Transport\TransportInterface" alias="mailer.default_transport" />
|
||||||
|
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<service id="mailer.transport_factory.abstract" class="Symfony\Component\Mailer\Transport\AbstractTransportFactory" abstract="true">
|
||||||
|
<argument type="service" id="event_dispatcher" />
|
||||||
|
<argument type="service" id="http_client" on-invalid="ignore" />
|
||||||
|
<argument type="service" id="logger" on-invalid="ignore" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.amazon" class="Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.gmail" class="Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.mailchimp" class="Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.mailgun" class="Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.postmark" class="Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.sendgrid" class="Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.null" class="Symfony\Component\Mailer\Transport\NullTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.sendmail" class="Symfony\Component\Mailer\Transport\SendmailTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="mailer.transport_factory.smtp" class="Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory" parent="mailer.transport_factory.abstract">
|
||||||
|
<tag name="mailer.transport_factory" priority="-100" />
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
|
</container>
|
@ -15,6 +15,7 @@
|
|||||||
<service id="messenger.middleware.send_message" class="Symfony\Component\Messenger\Middleware\SendMessageMiddleware">
|
<service id="messenger.middleware.send_message" class="Symfony\Component\Messenger\Middleware\SendMessageMiddleware">
|
||||||
<tag name="monolog.logger" channel="messenger" />
|
<tag name="monolog.logger" channel="messenger" />
|
||||||
<argument type="service" id="messenger.senders_locator" />
|
<argument type="service" id="messenger.senders_locator" />
|
||||||
|
<argument type="service" id="event_dispatcher" />
|
||||||
<call method="setLogger">
|
<call method="setLogger">
|
||||||
<argument type="service" id="logger" on-invalid="ignore" />
|
<argument type="service" id="logger" on-invalid="ignore" />
|
||||||
</call>
|
</call>
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
<xsd:element name="lock" type="lock" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="lock" type="lock" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="messenger" type="messenger" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="messenger" type="messenger" minOccurs="0" maxOccurs="1" />
|
||||||
<xsd:element name="http-client" type="http_client" minOccurs="0" maxOccurs="1" />
|
<xsd:element name="http-client" type="http_client" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xsd:element name="mailer" type="mailer" minOccurs="0" maxOccurs="1" />
|
||||||
</xsd:choice>
|
</xsd:choice>
|
||||||
|
|
||||||
<xsd:attribute name="http-method-override" type="xsd:boolean" />
|
<xsd:attribute name="http-method-override" type="xsd:boolean" />
|
||||||
@ -539,4 +540,18 @@
|
|||||||
<xsd:complexType name="http_header" mixed="true">
|
<xsd:complexType name="http_header" mixed="true">
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
|
|
||||||
|
<xsd:complexType name="mailer">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="envelope" type="mailer_envelope" minOccurs="0" maxOccurs="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="dsn" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
|
||||||
|
<xsd:complexType name="mailer_envelope">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sender" type="xsd:string" />
|
||||||
|
<xsd:element name="recipients" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
</xsd:schema>
|
</xsd:schema>
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$container->loadFromExtension('framework', [
|
||||||
|
'mailer' => [
|
||||||
|
'dsn' => 'smtp://example.com',
|
||||||
|
'envelope' => [
|
||||||
|
'sender' => 'sender@example.org',
|
||||||
|
'recipients' => ['redirected@example.org', 'redirected1@example.org'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:framework="http://symfony.com/schema/dic/symfony"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
|
||||||
|
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||||
|
|
||||||
|
<framework:config>
|
||||||
|
<framework:mailer dsn="smtp://example.com">
|
||||||
|
<framework:envelope>
|
||||||
|
<framework:sender>sender@example.org</framework:sender>
|
||||||
|
<framework:recipients>redirected@example.org</framework:recipients>
|
||||||
|
<framework:recipients>redirected1@example.org</framework:recipients>
|
||||||
|
</framework:envelope>
|
||||||
|
</framework:mailer>
|
||||||
|
</framework:config>
|
||||||
|
</container>
|
@ -0,0 +1,8 @@
|
|||||||
|
framework:
|
||||||
|
mailer:
|
||||||
|
dsn: 'smtp://example.com'
|
||||||
|
envelope:
|
||||||
|
sender: sender@example.org
|
||||||
|
recipients:
|
||||||
|
- redirected@example.org
|
||||||
|
- redirected1@example.org
|
@ -1378,6 +1378,19 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
], $defaultOptions['peer_fingerprint']);
|
], $defaultOptions['peer_fingerprint']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMailer(): void
|
||||||
|
{
|
||||||
|
$container = $this->createContainerFromFile('mailer');
|
||||||
|
|
||||||
|
$this->assertTrue($container->hasAlias('mailer'));
|
||||||
|
$this->assertTrue($container->hasDefinition('mailer.default_transport'));
|
||||||
|
$this->assertSame('smtp://example.com', $container->getDefinition('mailer.default_transport')->getArgument(0));
|
||||||
|
$this->assertTrue($container->hasDefinition('mailer.envelope_listener'));
|
||||||
|
$l = $container->getDefinition('mailer.envelope_listener');
|
||||||
|
$this->assertSame('sender@example.org', $l->getArgument(0));
|
||||||
|
$this->assertSame(['redirected@example.org', 'redirected1@example.org'], $l->getArgument(1));
|
||||||
|
}
|
||||||
|
|
||||||
protected function createContainer(array $data = [])
|
protected function createContainer(array $data = [])
|
||||||
{
|
{
|
||||||
return new ContainerBuilder(new ParameterBag(array_merge([
|
return new ContainerBuilder(new ParameterBag(array_merge([
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
"symfony/dotenv": "<4.4",
|
"symfony/dotenv": "<4.4",
|
||||||
"symfony/dom-crawler": "<4.4",
|
"symfony/dom-crawler": "<4.4",
|
||||||
"symfony/form": "<4.4",
|
"symfony/form": "<4.4",
|
||||||
|
"symfony/lock": "<4.4",
|
||||||
"symfony/messenger": "<4.4",
|
"symfony/messenger": "<4.4",
|
||||||
"symfony/property-info": "<4.4",
|
"symfony/property-info": "<4.4",
|
||||||
"symfony/serializer": "<4.4",
|
"symfony/serializer": "<4.4",
|
||||||
|
@ -5,13 +5,6 @@
|
|||||||
<span class="value">{{ request.route ?: '(none)' }}</span>
|
<span class="value">{{ request.route ?: '(none)' }}</span>
|
||||||
<span class="label">Matched route</span>
|
<span class="label">Matched route</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if request.route %}
|
|
||||||
<div class="metric">
|
|
||||||
<span class="value">{{ traces|length }}</span>
|
|
||||||
<span class="label">Tested routes before match</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if request.route %}
|
{% if request.route %}
|
||||||
|
@ -153,11 +153,11 @@ class DebugClassLoader
|
|||||||
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
|
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
|
||||||
// no-op
|
// no-op
|
||||||
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
|
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
|
||||||
require $file;
|
include $file;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
require $file;
|
include $file;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
($this->classLoader)($class);
|
($this->classLoader)($class);
|
||||||
|
@ -92,7 +92,7 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$body = isset(class_uses($response)[ResponseTrait::class]) ? $response->toStream() : StreamWrapper::createResource($response, $this->client);
|
$body = isset(class_uses($response)[ResponseTrait::class]) ? $response->toStream(false) : StreamWrapper::createResource($response, $this->client);
|
||||||
|
|
||||||
return $psrResponse->withBody($this->streamFactory->createStreamFromResource($body));
|
return $psrResponse->withBody($this->streamFactory->createStreamFromResource($body));
|
||||||
} catch (TransportExceptionInterface $e) {
|
} catch (TransportExceptionInterface $e) {
|
||||||
|
@ -21,6 +21,10 @@ use Symfony\Component\HttpClient\Exception\RedirectionException;
|
|||||||
use Symfony\Component\HttpClient\Exception\ServerException;
|
use Symfony\Component\HttpClient\Exception\ServerException;
|
||||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||||
use Symfony\Component\HttpClient\Internal\ClientState;
|
use Symfony\Component\HttpClient\Internal\ClientState;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the common logic for response classes.
|
* Implements the common logic for response classes.
|
||||||
@ -182,11 +186,16 @@ trait ResponseTrait
|
|||||||
* Casts the response to a PHP stream resource.
|
* Casts the response to a PHP stream resource.
|
||||||
*
|
*
|
||||||
* @return resource|null
|
* @return resource|null
|
||||||
|
*
|
||||||
|
* @throws TransportExceptionInterface When a network error occurs
|
||||||
|
* @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached
|
||||||
|
* @throws ClientExceptionInterface On a 4xx when $throw is true
|
||||||
|
* @throws ServerExceptionInterface On a 5xx when $throw is true
|
||||||
*/
|
*/
|
||||||
public function toStream()
|
public function toStream(bool $throw = true)
|
||||||
{
|
{
|
||||||
// Ensure headers arrived
|
// Ensure headers arrived
|
||||||
$this->getStatusCode();
|
$this->getHeaders($throw);
|
||||||
|
|
||||||
return StreamWrapper::createResource($this, null, $this->content, $this->handle && 'stream' === get_resource_type($this->handle) ? $this->handle : null);
|
return StreamWrapper::createResource($this, null, $this->content, $this->handle && 'stream' === get_resource_type($this->handle) ? $this->handle : null);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,13 @@ CHANGELOG
|
|||||||
* removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead
|
* removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead
|
||||||
* made `ProfilerStorageInterface` internal
|
* made `ProfilerStorageInterface` internal
|
||||||
|
|
||||||
|
4.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Implementing the `BundleInterface` without implementing the `getPublicDir()` method is deprecated.
|
||||||
|
This method will be added to the interface in 5.0.
|
||||||
|
* The `DebugHandlersListener` class has been marked as `final`
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class CombinedStore implements StoreInterface, LoggerAwareInterface
|
|||||||
*/
|
*/
|
||||||
public function waitAndSave(Key $key)
|
public function waitAndSave(Key $key)
|
||||||
{
|
{
|
||||||
@trigger_error(sprintf('%s::%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', \get_class($this), __METHOD__), E_USER_DEPRECATED);
|
@trigger_error(sprintf('%s() is deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class MemcachedStore implements StoreInterface
|
|||||||
*/
|
*/
|
||||||
public function waitAndSave(Key $key)
|
public function waitAndSave(Key $key)
|
||||||
{
|
{
|
||||||
@trigger_error(sprintf('%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
|
@trigger_error(sprintf('%s() is deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
|
||||||
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ class PdoStore implements StoreInterface
|
|||||||
*/
|
*/
|
||||||
public function waitAndSave(Key $key)
|
public function waitAndSave(Key $key)
|
||||||
{
|
{
|
||||||
@trigger_error(sprintf('%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
|
@trigger_error(sprintf('%s() is deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
|
||||||
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', __METHOD__));
|
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', __METHOD__));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class RedisStore implements StoreInterface
|
|||||||
*/
|
*/
|
||||||
public function waitAndSave(Key $key)
|
public function waitAndSave(Key $key)
|
||||||
{
|
{
|
||||||
@trigger_error(sprintf('%s::%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', \get_class($this), __METHOD__), E_USER_DEPRECATED);
|
@trigger_error(sprintf('%s() is deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class ZookeeperStore implements StoreInterface
|
|||||||
*/
|
*/
|
||||||
public function waitAndSave(Key $key)
|
public function waitAndSave(Key $key)
|
||||||
{
|
{
|
||||||
@trigger_error(sprintf('%s::%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', \get_class($this), __METHOD__), E_USER_DEPRECATED);
|
@trigger_error(sprintf('%s() is deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ use Symfony\Component\Lock\Exception\LockConflictedException;
|
|||||||
use Symfony\Component\Lock\Key;
|
use Symfony\Component\Lock\Key;
|
||||||
use Symfony\Component\Lock\Lock;
|
use Symfony\Component\Lock\Lock;
|
||||||
use Symfony\Component\Lock\PersistStoreInterface;
|
use Symfony\Component\Lock\PersistStoreInterface;
|
||||||
use Symfony\Component\Lock\StoreInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
@ -41,7 +40,7 @@ class LockTest extends TestCase
|
|||||||
public function testAcquireNoBlockingStoreInterface()
|
public function testAcquireNoBlockingStoreInterface()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store);
|
$lock = new Lock($key, $store);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -59,7 +58,7 @@ class LockTest extends TestCase
|
|||||||
public function testPassingOldStoreInterface()
|
public function testPassingOldStoreInterface()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store);
|
$lock = new Lock($key, $store);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -86,7 +85,7 @@ class LockTest extends TestCase
|
|||||||
public function testAcquireReturnsFalseStoreInterface()
|
public function testAcquireReturnsFalseStoreInterface()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store);
|
$lock = new Lock($key, $store);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -121,7 +120,7 @@ class LockTest extends TestCase
|
|||||||
public function testAcquireSetsTtl()
|
public function testAcquireSetsTtl()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store, 10);
|
$lock = new Lock($key, $store, 10);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -138,7 +137,7 @@ class LockTest extends TestCase
|
|||||||
public function testRefresh()
|
public function testRefresh()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store, 10);
|
$lock = new Lock($key, $store, 10);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -152,7 +151,7 @@ class LockTest extends TestCase
|
|||||||
public function testRefreshCustom()
|
public function testRefreshCustom()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store, 10);
|
$lock = new Lock($key, $store, 10);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -201,7 +200,7 @@ class LockTest extends TestCase
|
|||||||
public function testReleaseStoreInterface()
|
public function testReleaseStoreInterface()
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store, 10);
|
$lock = new Lock($key, $store, 10);
|
||||||
|
|
||||||
$store
|
$store
|
||||||
@ -356,7 +355,7 @@ class LockTest extends TestCase
|
|||||||
public function testExpirationStoreInterface($ttls, $expected)
|
public function testExpirationStoreInterface($ttls, $expected)
|
||||||
{
|
{
|
||||||
$key = new Key(uniqid(__METHOD__, true));
|
$key = new Key(uniqid(__METHOD__, true));
|
||||||
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$lock = new Lock($key, $store, 10);
|
$lock = new Lock($key, $store, 10);
|
||||||
|
|
||||||
foreach ($ttls as $ttl) {
|
foreach ($ttls as $ttl) {
|
||||||
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Lock\Tests\Store;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Lock\Exception\LockConflictedException;
|
use Symfony\Component\Lock\Exception\LockConflictedException;
|
||||||
use Symfony\Component\Lock\Key;
|
use Symfony\Component\Lock\Key;
|
||||||
use Symfony\Component\Lock\StoreInterface;
|
use Symfony\Component\Lock\PersistStoreInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
@ -22,7 +22,7 @@ use Symfony\Component\Lock\StoreInterface;
|
|||||||
abstract class AbstractStoreTest extends TestCase
|
abstract class AbstractStoreTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return StoreInterface
|
* @return PersistStoreInterface
|
||||||
*/
|
*/
|
||||||
abstract protected function getStore();
|
abstract protected function getStore();
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Lock\Tests\Store;
|
|||||||
use Symfony\Component\Lock\Exception\LockConflictedException;
|
use Symfony\Component\Lock\Exception\LockConflictedException;
|
||||||
use Symfony\Component\Lock\Exception\NotSupportedException;
|
use Symfony\Component\Lock\Exception\NotSupportedException;
|
||||||
use Symfony\Component\Lock\Key;
|
use Symfony\Component\Lock\Key;
|
||||||
use Symfony\Component\Lock\StoreInterface;
|
use Symfony\Component\Lock\PersistStoreInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
@ -24,7 +24,7 @@ trait BlockingStoreTestTrait
|
|||||||
/**
|
/**
|
||||||
* @see AbstractStoreTest::getStore()
|
* @see AbstractStoreTest::getStore()
|
||||||
*
|
*
|
||||||
* @return StoreInterface
|
* @return PersistStoreInterface
|
||||||
*/
|
*/
|
||||||
abstract protected function getStore();
|
abstract protected function getStore();
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ use Symfony\Component\Lock\Key;
|
|||||||
use Symfony\Component\Lock\PersistStoreInterface;
|
use Symfony\Component\Lock\PersistStoreInterface;
|
||||||
use Symfony\Component\Lock\Store\CombinedStore;
|
use Symfony\Component\Lock\Store\CombinedStore;
|
||||||
use Symfony\Component\Lock\Store\RedisStore;
|
use Symfony\Component\Lock\Store\RedisStore;
|
||||||
use Symfony\Component\Lock\StoreInterface;
|
|
||||||
use Symfony\Component\Lock\Strategy\StrategyInterface;
|
use Symfony\Component\Lock\Strategy\StrategyInterface;
|
||||||
use Symfony\Component\Lock\Strategy\UnanimousStrategy;
|
use Symfony\Component\Lock\Strategy\UnanimousStrategy;
|
||||||
|
|
||||||
@ -268,8 +267,8 @@ class CombinedStoreTest extends AbstractStoreTest
|
|||||||
|
|
||||||
public function testPutOffExpirationIgnoreNonExpiringStorage()
|
public function testPutOffExpirationIgnoreNonExpiringStorage()
|
||||||
{
|
{
|
||||||
$store1 = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store1 = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
$store2 = $this->getMockBuilder(StoreInterface::class)->getMock();
|
$store2 = $this->getMockBuilder(PersistStoreInterface::class)->getMock();
|
||||||
|
|
||||||
$store = new CombinedStore([$store1, $store2], $this->strategy);
|
$store = new CombinedStore([$store1, $store2], $this->strategy);
|
||||||
|
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
<?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\Bridge\Amazon\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Amazon;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class SesTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$scheme = $dsn->getScheme();
|
||||||
|
$user = $this->getUser($dsn);
|
||||||
|
$password = $this->getPassword($dsn);
|
||||||
|
$region = $dsn->getOption('region');
|
||||||
|
|
||||||
|
if ('api' === $scheme) {
|
||||||
|
return new Amazon\Http\Api\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('http' === $scheme) {
|
||||||
|
return new Amazon\Http\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('smtp' === $scheme) {
|
||||||
|
return new Amazon\Smtp\SesTransport($user, $password, $region, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'ses' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
<?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\Bridge\Amazon\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Amazon;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class SesTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new SesTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'ses'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'ses'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'ses'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$client = $this->getClient();
|
||||||
|
$dispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'ses', self::USER, self::PASSWORD),
|
||||||
|
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
|
||||||
|
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'ses', self::USER, self::PASSWORD),
|
||||||
|
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
|
||||||
|
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'ses', self::USER, self::PASSWORD),
|
||||||
|
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
|
||||||
|
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'ses', self::USER, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('smtp', 'ses', self::USER)];
|
||||||
|
|
||||||
|
yield [new Dsn('smtp', 'ses', null, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?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\Bridge\Google\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class GmailTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
if ('smtp' === $dsn->getScheme()) {
|
||||||
|
return new GmailTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'gmail' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Mailer\Bridge\Google\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class GmailTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new GmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'gmail'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'gmail', self::USER, self::PASSWORD),
|
||||||
|
new GmailTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('http', 'gmail', self::USER, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('smtp', 'gmail', self::USER)];
|
||||||
|
|
||||||
|
yield [new Dsn('smtp', 'gmail', null, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?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\Bridge\Mailchimp\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailchimp;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class MandrillTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$scheme = $dsn->getScheme();
|
||||||
|
$user = $this->getUser($dsn);
|
||||||
|
|
||||||
|
if ('api' === $scheme) {
|
||||||
|
return new Mailchimp\Http\Api\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('http' === $scheme) {
|
||||||
|
return new Mailchimp\Http\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('smtp' === $scheme) {
|
||||||
|
$password = $this->getPassword($dsn);
|
||||||
|
|
||||||
|
return new Mailchimp\Smtp\MandrillTransport($user, $password, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'mandrill' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
<?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\Bridge\Mailchimp\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailchimp;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class MandrillTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new MandrillTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'mandrill'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'mandrill'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'mandrill'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$client = $this->getClient();
|
||||||
|
$dispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'mandrill', self::USER),
|
||||||
|
new Mailchimp\Http\Api\MandrillTransport(self::USER, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'mandrill', self::USER),
|
||||||
|
new Mailchimp\Http\MandrillTransport(self::USER, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'mandrill', self::USER, self::PASSWORD),
|
||||||
|
new Mailchimp\Smtp\MandrillTransport(self::USER, self::PASSWORD, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'mandrill', self::USER)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('api', 'mandrill')];
|
||||||
|
|
||||||
|
yield [new Dsn('smtp', 'mandrill', self::USER)];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?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\Bridge\Mailgun\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailgun;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class MailgunTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$scheme = $dsn->getScheme();
|
||||||
|
$user = $this->getUser($dsn);
|
||||||
|
$password = $this->getPassword($dsn);
|
||||||
|
$region = $dsn->getOption('region');
|
||||||
|
|
||||||
|
if ('api' === $scheme) {
|
||||||
|
return new Mailgun\Http\Api\MailgunTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('http' === $scheme) {
|
||||||
|
return new Mailgun\Http\MailgunTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('smtp' === $scheme) {
|
||||||
|
return new Mailgun\Smtp\MailgunTransport($user, $password, $region, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'mailgun' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Mailer\Bridge\Mailgun\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailgun;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class MailgunTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new MailgunTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'mailgun'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'mailgun'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'mailgun'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$client = $this->getClient();
|
||||||
|
$dispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'mailgun', self::USER, self::PASSWORD),
|
||||||
|
new Mailgun\Http\Api\MailgunTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'mailgun', self::USER, self::PASSWORD, null, ['region' => 'eu']),
|
||||||
|
new Mailgun\Http\Api\MailgunTransport(self::USER, self::PASSWORD, 'eu', $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('http', 'mailgun', self::USER, self::PASSWORD),
|
||||||
|
new Mailgun\Http\MailgunTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'mailgun', self::USER, self::PASSWORD),
|
||||||
|
new Mailgun\Smtp\MailgunTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'mailgun', self::USER, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('api', 'mailgun', self::USER)];
|
||||||
|
|
||||||
|
yield [new Dsn('api', 'mailgun', null, self::PASSWORD)];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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\Bridge\Postmark\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Postmark;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class PostmarkTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$scheme = $dsn->getScheme();
|
||||||
|
$user = $this->getUser($dsn);
|
||||||
|
|
||||||
|
if ('api' === $scheme) {
|
||||||
|
return new Postmark\Http\Api\PostmarkTransport($user, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('smtp' === $scheme) {
|
||||||
|
return new Postmark\Smtp\PostmarkTransport($user, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'postmark' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
<?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\Bridge\Postmark\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Postmark;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class PostmarkTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new PostmarkTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'postmark'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'postmark'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$dispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'postmark', self::USER),
|
||||||
|
new Postmark\Http\Api\PostmarkTransport(self::USER, $this->getClient(), $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'postmark', self::USER),
|
||||||
|
new Postmark\Smtp\PostmarkTransport(self::USER, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'postmark', self::USER)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('api', 'postmark')];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
<?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\Bridge\Sendgrid\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Sendgrid;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class SendgridTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$key = $this->getUser($dsn);
|
||||||
|
|
||||||
|
if ('api' === $dsn->getScheme()) {
|
||||||
|
return new Sendgrid\Http\Api\SendgridTransport($key, $this->client, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('smtp' === $dsn->getScheme()) {
|
||||||
|
return new Sendgrid\Smtp\SendgridTransport($key, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'sendgrid' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
<?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\Bridge\Sendgrid\Tests\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge\Sendgrid;
|
||||||
|
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class SendgridTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new SendgridTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'sendgrid'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'sendgrid'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$dispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'sendgrid', self::USER),
|
||||||
|
new Sendgrid\Http\Api\SendgridTransport(self::USER, $this->getClient(), $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'sendgrid', self::USER),
|
||||||
|
new Sendgrid\Smtp\SendgridTransport(self::USER, $dispatcher, $logger),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'sendgrid', self::USER)];
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,8 @@ CHANGELOG
|
|||||||
|
|
||||||
* [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface`
|
* [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface`
|
||||||
instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`.
|
instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`.
|
||||||
|
* Added possibility to register custom transport for dsn by implementing
|
||||||
|
`Symfony\Component\Mailer\Transport\TransportFactoryInterface` and tagging with `mailer.transport_factory` tag in DI.
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<?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\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
class IncompleteDsnException extends InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
<?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\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Bridge;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
class UnsupportedHostException extends LogicException
|
||||||
|
{
|
||||||
|
private const HOST_TO_PACKAGE_MAP = [
|
||||||
|
'gmail' => [
|
||||||
|
'class' => Bridge\Google\Factory\GmailTransportFactory::class,
|
||||||
|
'package' => 'symfony/google-mailer',
|
||||||
|
],
|
||||||
|
'mailgun' => [
|
||||||
|
'class' => Bridge\Mailgun\Factory\MailgunTransportFactory::class,
|
||||||
|
'package' => 'symfony/mailgun-mailer',
|
||||||
|
],
|
||||||
|
'postmark' => [
|
||||||
|
'class' => Bridge\Postmark\Factory\PostmarkTransportFactory::class,
|
||||||
|
'package' => 'symfony/postmark-mailer',
|
||||||
|
],
|
||||||
|
'sendgrid' => [
|
||||||
|
'class' => Bridge\Sendgrid\Factory\SendgridTransportFactory::class,
|
||||||
|
'package' => 'symfony/sendgrid-mailer',
|
||||||
|
],
|
||||||
|
'ses' => [
|
||||||
|
'class' => Bridge\Amazon\Factory\SesTransportFactory::class,
|
||||||
|
'package' => 'symfony/amazon-mailer',
|
||||||
|
],
|
||||||
|
'mandrill' => [
|
||||||
|
'class' => Bridge\Mailchimp\Factory\MandrillTransportFactory::class,
|
||||||
|
'package' => 'symfony/mailchimp-mailer',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(Dsn $dsn)
|
||||||
|
{
|
||||||
|
$host = $dsn->getHost();
|
||||||
|
$package = self::HOST_TO_PACKAGE_MAP[$host] ?? null;
|
||||||
|
if ($package && !class_exists($package['class'])) {
|
||||||
|
parent::__construct(sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $host, $package['package']));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct(sprintf('The "%s" mailer is not supported.', $host));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
<?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\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
class UnsupportedSchemeException extends LogicException
|
||||||
|
{
|
||||||
|
public function __construct(Dsn $dsn)
|
||||||
|
{
|
||||||
|
parent::__construct(sprintf('The "%s" scheme is not supported for mailer "%s".', $dsn->getScheme(), $dsn->getHost()));
|
||||||
|
}
|
||||||
|
}
|
88
src/Symfony/Component/Mailer/Tests/Transport/DsnTest.php
Normal file
88
src/Symfony/Component/Mailer/Tests/Transport/DsnTest.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?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\Tests\Transport;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
|
||||||
|
class DsnTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider fromStringProvider
|
||||||
|
*/
|
||||||
|
public function testFromString(string $string, Dsn $dsn): void
|
||||||
|
{
|
||||||
|
$this->assertEquals($dsn, Dsn::fromString($string));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetOption(): void
|
||||||
|
{
|
||||||
|
$options = ['with_value' => 'some value', 'nullable' => null];
|
||||||
|
$dsn = new Dsn('smtp', 'example.com', null, null, null, $options);
|
||||||
|
|
||||||
|
$this->assertSame('some value', $dsn->getOption('with_value'));
|
||||||
|
$this->assertSame('default', $dsn->getOption('nullable', 'default'));
|
||||||
|
$this->assertSame('default', $dsn->getOption('not_existent_property', 'default'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider invalidDsnProvider
|
||||||
|
*/
|
||||||
|
public function testInvalidDsn(string $dsn, string $exceptionMessage): void
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage($exceptionMessage);
|
||||||
|
Dsn::fromString($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromStringProvider(): iterable
|
||||||
|
{
|
||||||
|
yield 'simple smtp without user and pass' => [
|
||||||
|
'smtp://example.com',
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield 'simple smtp with custom port' => [
|
||||||
|
'smtp://user1:pass2@example.com:99',
|
||||||
|
new Dsn('smtp', 'example.com', 'user1', 'pass2', 99),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield 'gmail smtp with urlencoded user and pass' => [
|
||||||
|
'smtp://u%24er:pa%24s@gmail',
|
||||||
|
new Dsn('smtp', 'gmail', 'u$er', 'pa$s'),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield 'mailgun api with custom options' => [
|
||||||
|
'api://u%24er:pa%24s@mailgun?region=eu',
|
||||||
|
new Dsn('api', 'mailgun', 'u$er', 'pa$s', null, ['region' => 'eu']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invalidDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
'some://',
|
||||||
|
'The "some://" mailer DSN is invalid.',
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'//sendmail',
|
||||||
|
'The "//sendmail" mailer DSN must contain a transport scheme.',
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'file:///some/path',
|
||||||
|
'The "file:///some/path" mailer DSN must contain a mailer name.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
<?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\Tests\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\NullTransport;
|
||||||
|
use Symfony\Component\Mailer\Transport\NullTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class NullTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new NullTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'null'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'null'),
|
||||||
|
new NullTransport($this->getDispatcher(), $this->getLogger()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('foo', 'null')];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
<?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\Tests\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\SendmailTransport;
|
||||||
|
use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class SendmailTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new SendmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'sendmail'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'sendmail'),
|
||||||
|
new SendmailTransport(null, $this->getDispatcher(), $this->getLogger()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [new Dsn('http', 'sendmail')];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Mailer\Tests\Transport\Smtp;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
|
||||||
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
|
||||||
|
class EsmtpTransportFactoryTest extends TransportFactoryTestCase
|
||||||
|
{
|
||||||
|
public function getFactory(): TransportFactoryInterface
|
||||||
|
{
|
||||||
|
return new EsmtpTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsProvider(): iterable
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
true,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('api', 'example.com'),
|
||||||
|
false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createProvider(): iterable
|
||||||
|
{
|
||||||
|
$eventDispatcher = $this->getDispatcher();
|
||||||
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
|
$transport = new EsmtpTransport('example.com', 25, null, null, $eventDispatcher, $logger);
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com'),
|
||||||
|
$transport,
|
||||||
|
];
|
||||||
|
|
||||||
|
$transport = new EsmtpTransport('example.com', 99, 'ssl', 'login', $eventDispatcher, $logger);
|
||||||
|
$transport->setUsername(self::USER);
|
||||||
|
$transport->setPassword(self::PASSWORD);
|
||||||
|
|
||||||
|
yield [
|
||||||
|
new Dsn('smtp', 'example.com', self::USER, self::PASSWORD, 99, ['encryption' => 'ssl', 'auth_mode' => 'login']),
|
||||||
|
$transport,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
105
src/Symfony/Component/Mailer/Tests/TransportFactoryTestCase.php
Normal file
105
src/Symfony/Component/Mailer/Tests/TransportFactoryTestCase.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?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\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
|
abstract class TransportFactoryTestCase extends TestCase
|
||||||
|
{
|
||||||
|
protected const USER = 'u$er';
|
||||||
|
protected const PASSWORD = 'pa$s';
|
||||||
|
|
||||||
|
protected $dispatcher;
|
||||||
|
protected $client;
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
abstract public function getFactory(): TransportFactoryInterface;
|
||||||
|
|
||||||
|
abstract public function supportsProvider(): iterable;
|
||||||
|
|
||||||
|
abstract public function createProvider(): iterable;
|
||||||
|
|
||||||
|
public function unsupportedSchemeProvider(): iterable
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function incompleteDsnProvider(): iterable
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider supportsProvider
|
||||||
|
*/
|
||||||
|
public function testSupports(Dsn $dsn, bool $supports): void
|
||||||
|
{
|
||||||
|
$factory = $this->getFactory();
|
||||||
|
|
||||||
|
$this->assertSame($supports, $factory->supports($dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider createProvider
|
||||||
|
*/
|
||||||
|
public function testCreate(Dsn $dsn, TransportInterface $transport): void
|
||||||
|
{
|
||||||
|
$factory = $this->getFactory();
|
||||||
|
|
||||||
|
$this->assertEquals($transport, $factory->create($dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider unsupportedSchemeProvider
|
||||||
|
*/
|
||||||
|
public function testUnsupportedSchemeException(Dsn $dsn): void
|
||||||
|
{
|
||||||
|
$factory = $this->getFactory();
|
||||||
|
|
||||||
|
$this->expectException(UnsupportedSchemeException::class);
|
||||||
|
$factory->create($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider incompleteDsnProvider
|
||||||
|
*/
|
||||||
|
public function testIncompleteDsnException(Dsn $dsn): void
|
||||||
|
{
|
||||||
|
$factory = $this->getFactory();
|
||||||
|
|
||||||
|
$this->expectException(IncompleteDsnException::class);
|
||||||
|
$factory->create($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDispatcher(): EventDispatcherInterface
|
||||||
|
{
|
||||||
|
return $this->dispatcher ?? $this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClient(): HttpClientInterface
|
||||||
|
{
|
||||||
|
return $this->client ?? $this->client = $this->createMock(HttpClientInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLogger(): LoggerInterface
|
||||||
|
{
|
||||||
|
return $this->logger ?? $this->logger = $this->createMock(LoggerInterface::class);
|
||||||
|
}
|
||||||
|
}
|
@ -12,345 +12,71 @@
|
|||||||
namespace Symfony\Component\Mailer\Tests;
|
namespace Symfony\Component\Mailer\Tests;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Log\LoggerInterface;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\Bridge\Amazon;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Bridge\Google;
|
|
||||||
use Symfony\Component\Mailer\Bridge\Mailchimp;
|
|
||||||
use Symfony\Component\Mailer\Bridge\Mailgun;
|
|
||||||
use Symfony\Component\Mailer\Bridge\Postmark;
|
|
||||||
use Symfony\Component\Mailer\Bridge\Sendgrid;
|
|
||||||
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
|
||||||
use Symfony\Component\Mailer\Exception\LogicException;
|
|
||||||
use Symfony\Component\Mailer\Transport;
|
use Symfony\Component\Mailer\Transport;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Component\Mime\RawMessage;
|
||||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
|
||||||
|
|
||||||
class TransportTest extends TestCase
|
class TransportTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testFromDsnNull()
|
/**
|
||||||
|
* @dataProvider fromStringProvider
|
||||||
|
*/
|
||||||
|
public function testFromString(string $dsn, TransportInterface $transport): void
|
||||||
{
|
{
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
$transportFactory = new Transport([new DummyTransportFactory()]);
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://null', $dispatcher, null, $logger);
|
$this->assertEquals($transport, $transportFactory->fromString($dsn));
|
||||||
$this->assertInstanceOf(Transport\NullTransport::class, $transport);
|
|
||||||
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$this->assertSame($dispatcher, $p->getValue($transport));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFromDsnSendmail()
|
public function fromStringProvider(): iterable
|
||||||
{
|
{
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
$transportA = new DummyTransport('a');
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
$transportB = new DummyTransport('b');
|
||||||
$transport = Transport::fromDsn('smtp://sendmail', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Transport\SendmailTransport::class, $transport);
|
yield 'simple transport' => [
|
||||||
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
|
'dummy://a',
|
||||||
$p->setAccessible(true);
|
$transportA,
|
||||||
$this->assertSame($dispatcher, $p->getValue($transport));
|
];
|
||||||
|
|
||||||
|
yield 'failover transport' => [
|
||||||
|
'dummy://a || dummy://b',
|
||||||
|
new Transport\FailoverTransport([$transportA, $transportB]),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield 'round robin transport' => [
|
||||||
|
'dummy://a && dummy://b',
|
||||||
|
new Transport\RoundRobinTransport([$transportA, $transportB]),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFromDsnSmtp()
|
class DummyTransport implements Transport\TransportInterface
|
||||||
{
|
{
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
private $host;
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://localhost:44?auth_mode=plain&encryption=tls', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Transport\Smtp\SmtpTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
$this->assertEquals('localhost', $transport->getStream()->getHost());
|
|
||||||
$this->assertEquals('plain', $transport->getAuthMode());
|
|
||||||
$this->assertTrue($transport->getStream()->isTLS());
|
|
||||||
$this->assertEquals(44, $transport->getStream()->getPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromInvalidDsn()
|
public function __construct(string $host)
|
||||||
{
|
{
|
||||||
$this->expectException(InvalidArgumentException::class);
|
$this->host = $host;
|
||||||
$this->expectExceptionMessage('The "some://" mailer DSN is invalid.');
|
|
||||||
Transport::fromDsn('some://');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNoScheme()
|
public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage
|
||||||
{
|
{
|
||||||
$this->expectException(InvalidArgumentException::class);
|
throw new \BadMethodCallException('This method newer should be called.');
|
||||||
$this->expectExceptionMessage('The "//sendmail" mailer DSN must contain a transport scheme.');
|
}
|
||||||
Transport::fromDsn('//sendmail');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFromInvalidDsnNoHost()
|
class DummyTransportFactory implements Transport\TransportFactoryInterface
|
||||||
{
|
{
|
||||||
$this->expectException(InvalidArgumentException::class);
|
public function create(Dsn $dsn): TransportInterface
|
||||||
$this->expectExceptionMessage('The "file:///some/path" mailer DSN must contain a mailer name.');
|
|
||||||
Transport::fromDsn('file:///some/path');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromInvalidTransportName()
|
|
||||||
{
|
{
|
||||||
$this->expectException(LogicException::class);
|
return new DummyTransport($dsn->getHost());
|
||||||
Transport::fromDsn('api://foobar');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFromDsnGmail()
|
public function supports(Dsn $dsn): bool
|
||||||
{
|
{
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
return 'dummy' === $dsn->getScheme();
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@gmail', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Google\Smtp\GmailTransport::class, $transport);
|
|
||||||
$this->assertEquals('u$er', $transport->getUsername());
|
|
||||||
$this->assertEquals('pa$s', $transport->getPassword());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('http://gmail');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnMailgun()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Mailgun\Smtp\MailgunTransport::class, $transport);
|
|
||||||
$this->assertEquals('u$er', $transport->getUsername());
|
|
||||||
$this->assertEquals('pa$s', $transport->getPassword());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, null, $logger);
|
|
||||||
$this->assertEquals('smtp.mailgun.org', $transport->getStream()->getHost());
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, null, $logger);
|
|
||||||
$this->assertEquals('smtp.eu.mailgun.org', $transport->getStream()->getHost());
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, null, $logger);
|
|
||||||
$this->assertEquals('smtp.mailgun.org', $transport->getStream()->getHost());
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Mailgun\Http\MailgunTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'domain' => 'pa$s',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response = $this->createMock(ResponseInterface::class);
|
|
||||||
$response->expects($this->any())->method('getStatusCode')->willReturn(200);
|
|
||||||
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->text('Hello you');
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.eu.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Mailgun\Http\Api\MailgunTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'domain' => 'pa$s',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.eu.mailgun.net/v3/pa%24s/messages')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html('test');
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$stream = fopen('data://text/plain,'.$message->getTextBody(), 'r');
|
|
||||||
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html($stream);
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
|
|
||||||
$transport->send($message);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('foo://mailgun');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnPostmark()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@postmark', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Postmark\Smtp\PostmarkTransport::class, $transport);
|
|
||||||
$this->assertEquals('u$er', $transport->getUsername());
|
|
||||||
$this->assertEquals('u$er', $transport->getPassword());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@postmark', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Postmark\Http\Api\PostmarkTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('http://postmark');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnSendgrid()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@sendgrid', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Sendgrid\Smtp\SendgridTransport::class, $transport);
|
|
||||||
$this->assertEquals('apikey', $transport->getUsername());
|
|
||||||
$this->assertEquals('u$er', $transport->getPassword());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@sendgrid', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Sendgrid\Http\Api\SendgridTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('http://sendgrid');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnAmazonSes()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Amazon\Smtp\SesTransport::class, $transport);
|
|
||||||
$this->assertEquals('u$er', $transport->getUsername());
|
|
||||||
$this->assertEquals('pa$s', $transport->getPassword());
|
|
||||||
$this->assertContains('.sun.', $transport->getStream()->getHost());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Amazon\Http\SesTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'accessKey' => 'u$er',
|
|
||||||
'secretKey' => 'pa$s',
|
|
||||||
'region' => 'sun',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Amazon\Http\Api\SesTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'accessKey' => 'u$er',
|
|
||||||
'secretKey' => 'pa$s',
|
|
||||||
'region' => 'sun',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('foo://ses');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnMailchimp()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mandrill', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Mailchimp\Smtp\MandrillTransport::class, $transport);
|
|
||||||
$this->assertEquals('u$er', $transport->getUsername());
|
|
||||||
$this->assertEquals('pa$s', $transport->getPassword());
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
|
|
||||||
$client = $this->createMock(HttpClientInterface::class);
|
|
||||||
$transport = Transport::fromDsn('http://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Mailchimp\Http\MandrillTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger);
|
|
||||||
$this->assertInstanceOf(Mailchimp\Http\Api\MandrillTransport::class, $transport);
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger, [
|
|
||||||
'key' => 'u$er',
|
|
||||||
'client' => $client,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->expectException(LogicException::class);
|
|
||||||
Transport::fromDsn('foo://mandrill');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnFailover()
|
|
||||||
{
|
|
||||||
$user = 'user';
|
|
||||||
$pass = 'pass';
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://example.com || smtp://'.urlencode($user).'@example.com || smtp://'.urlencode($user).':'.urlencode($pass).'@example.com', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Transport\FailoverTransport::class, $transport);
|
|
||||||
$p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports');
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$transports = $p->getValue($transport);
|
|
||||||
$this->assertCount(3, $transports);
|
|
||||||
foreach ($transports as $transport) {
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
$this->assertSame('', $transports[0]->getUsername());
|
|
||||||
$this->assertSame('', $transports[0]->getPassword());
|
|
||||||
$this->assertSame($user, $transports[1]->getUsername());
|
|
||||||
$this->assertSame('', $transports[1]->getPassword());
|
|
||||||
$this->assertSame($user, $transports[2]->getUsername());
|
|
||||||
$this->assertSame($pass, $transports[2]->getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFromDsnRoundRobin()
|
|
||||||
{
|
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
|
||||||
$logger = $this->createMock(LoggerInterface::class);
|
|
||||||
$transport = Transport::fromDsn('smtp://null && smtp://null && smtp://null', $dispatcher, null, $logger);
|
|
||||||
$this->assertInstanceOf(Transport\RoundRobinTransport::class, $transport);
|
|
||||||
$p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports');
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$transports = $p->getValue($transport);
|
|
||||||
$this->assertCount(3, $transports);
|
|
||||||
foreach ($transports as $transport) {
|
|
||||||
$this->assertProperties($transport, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function assertProperties(Transport\TransportInterface $transport, EventDispatcherInterface $dispatcher, LoggerInterface $logger, array $props = [])
|
|
||||||
{
|
|
||||||
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$this->assertSame($dispatcher, $p->getValue($transport));
|
|
||||||
|
|
||||||
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'logger');
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$this->assertSame($logger, $p->getValue($transport));
|
|
||||||
|
|
||||||
foreach ($props as $prop => $value) {
|
|
||||||
$p = new \ReflectionProperty($transport, $prop);
|
|
||||||
$p->setAccessible(true);
|
|
||||||
$this->assertEquals($value, $p->getValue($transport));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,181 +12,107 @@
|
|||||||
namespace Symfony\Component\Mailer;
|
namespace Symfony\Component\Mailer;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Bridge\Amazon;
|
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
|
||||||
use Symfony\Component\Mailer\Bridge\Google;
|
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
|
||||||
use Symfony\Component\Mailer\Bridge\Mailchimp;
|
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
|
||||||
use Symfony\Component\Mailer\Bridge\Mailgun;
|
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
|
||||||
use Symfony\Component\Mailer\Bridge\Postmark;
|
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
|
||||||
use Symfony\Component\Mailer\Bridge\Sendgrid;
|
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
|
||||||
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
use Symfony\Component\Mailer\Exception\UnsupportedHostException;
|
||||||
use Symfony\Component\Mailer\Exception\LogicException;
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\NullTransportFactory;
|
||||||
|
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\TransportInterface;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
*/
|
*/
|
||||||
class Transport
|
class Transport
|
||||||
{
|
{
|
||||||
|
private const FACTORY_CLASSES = [
|
||||||
|
SesTransportFactory::class,
|
||||||
|
GmailTransportFactory::class,
|
||||||
|
MandrillTransportFactory::class,
|
||||||
|
MailgunTransportFactory::class,
|
||||||
|
PostmarkTransportFactory::class,
|
||||||
|
SendgridTransportFactory::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
private $factories;
|
||||||
|
|
||||||
public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
|
public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
|
||||||
{
|
{
|
||||||
// failover?
|
$factory = new self(self::getDefaultFactories($dispatcher, $client, $logger));
|
||||||
|
|
||||||
|
return $factory->fromString($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransportFactoryInterface[] $factories
|
||||||
|
*/
|
||||||
|
public function __construct(iterable $factories)
|
||||||
|
{
|
||||||
|
$this->factories = $factories;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromString(string $dsn): TransportInterface
|
||||||
|
{
|
||||||
$dsns = preg_split('/\s++\|\|\s++/', $dsn);
|
$dsns = preg_split('/\s++\|\|\s++/', $dsn);
|
||||||
if (\count($dsns) > 1) {
|
if (\count($dsns) > 1) {
|
||||||
$transports = [];
|
return new Transport\FailoverTransport($this->createFromDsns($dsns));
|
||||||
foreach ($dsns as $dsn) {
|
|
||||||
$transports[] = self::createTransport($dsn, $dispatcher, $client, $logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Transport\FailoverTransport($transports);
|
|
||||||
}
|
|
||||||
|
|
||||||
// round robin?
|
|
||||||
$dsns = preg_split('/\s++&&\s++/', $dsn);
|
$dsns = preg_split('/\s++&&\s++/', $dsn);
|
||||||
if (\count($dsns) > 1) {
|
if (\count($dsns) > 1) {
|
||||||
|
return new Transport\RoundRobinTransport($this->createFromDsns($dsns));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->fromDsnObject(Dsn::fromString($dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromDsnObject(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
foreach ($this->factories as $factory) {
|
||||||
|
if ($factory->supports($dsn)) {
|
||||||
|
return $factory->create($dsn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedHostException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $dsns
|
||||||
|
*
|
||||||
|
* @return TransportInterface[]
|
||||||
|
*/
|
||||||
|
private function createFromDsns(array $dsns): array
|
||||||
|
{
|
||||||
$transports = [];
|
$transports = [];
|
||||||
foreach ($dsns as $dsn) {
|
foreach ($dsns as $dsn) {
|
||||||
$transports[] = self::createTransport($dsn, $dispatcher, $client, $logger);
|
$transports[] = $this->fromDsnObject(Dsn::fromString($dsn));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Transport\RoundRobinTransport($transports);
|
return $transports;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::createTransport($dsn, $dispatcher, $client, $logger);
|
private static function getDefaultFactories(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): iterable
|
||||||
}
|
|
||||||
|
|
||||||
private static function createTransport(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
|
|
||||||
{
|
{
|
||||||
if (false === $parsedDsn = parse_url($dsn)) {
|
foreach (self::FACTORY_CLASSES as $factoryClass) {
|
||||||
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn));
|
if (class_exists($factoryClass)) {
|
||||||
|
yield new $factoryClass($dispatcher, $client, $logger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($parsedDsn['scheme'])) {
|
yield new NullTransportFactory($dispatcher, $client, $logger);
|
||||||
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a transport scheme.', $dsn));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($parsedDsn['host'])) {
|
yield new SendmailTransportFactory($dispatcher, $client, $logger);
|
||||||
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn));
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = urldecode($parsedDsn['user'] ?? '');
|
yield new EsmtpTransportFactory($dispatcher, $client, $logger);
|
||||||
$pass = urldecode($parsedDsn['pass'] ?? '');
|
|
||||||
parse_str($parsedDsn['query'] ?? '', $query);
|
|
||||||
|
|
||||||
switch ($parsedDsn['host']) {
|
|
||||||
case 'null':
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Transport\NullTransport($dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'sendmail':
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Transport\SendmailTransport(null, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'gmail':
|
|
||||||
if (!class_exists(Google\Smtp\GmailTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Gmail as the Google bridge is not installed. Try running "composer require symfony/google-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Google\Smtp\GmailTransport($user, $pass, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'mailgun':
|
|
||||||
if (!class_exists(Mailgun\Smtp\MailgunTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Mailgun as the bridge is not installed. Try running "composer require symfony/mailgun-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailgun\Smtp\MailgunTransport($user, $pass, $query['region'] ?? null, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('http' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailgun\Http\MailgunTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('api' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailgun\Http\Api\MailgunTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'postmark':
|
|
||||||
if (!class_exists(Postmark\Smtp\PostmarkTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Postmark as the bridge is not installed. Try running "composer require symfony/postmark-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Postmark\Smtp\PostmarkTransport($user, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('api' === $parsedDsn['scheme']) {
|
|
||||||
return new Postmark\Http\Api\PostmarkTransport($user, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'sendgrid':
|
|
||||||
if (!class_exists(Sendgrid\Smtp\SendgridTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Sendgrid as the bridge is not installed. Try running "composer require symfony/sendgrid-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Sendgrid\Smtp\SendgridTransport($user, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('api' === $parsedDsn['scheme']) {
|
|
||||||
return new Sendgrid\Http\Api\SendgridTransport($user, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'ses':
|
|
||||||
if (!class_exists(Amazon\Smtp\SesTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Amazon SES as the bridge is not installed. Try running "composer require symfony/amazon-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Amazon\Smtp\SesTransport($user, $pass, $query['region'] ?? null, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('api' === $parsedDsn['scheme']) {
|
|
||||||
return new Amazon\Http\Api\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('http' === $parsedDsn['scheme']) {
|
|
||||||
return new Amazon\Http\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
case 'mandrill':
|
|
||||||
if (!class_exists(Mailchimp\Smtp\MandrillTransport::class)) {
|
|
||||||
throw new \LogicException('Unable to send emails via Mandrill as the bridge is not installed. Try running "composer require symfony/mailchimp-mailer".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailchimp\Smtp\MandrillTransport($user, $pass, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('api' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailchimp\Http\Api\MandrillTransport($user, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
if ('http' === $parsedDsn['scheme']) {
|
|
||||||
return new Mailchimp\Http\MandrillTransport($user, $client, $dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
|
|
||||||
default:
|
|
||||||
if ('smtp' === $parsedDsn['scheme']) {
|
|
||||||
$transport = new Transport\Smtp\EsmtpTransport($parsedDsn['host'], $parsedDsn['port'] ?? 25, $query['encryption'] ?? null, $query['auth_mode'] ?? null, $dispatcher, $logger);
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
$transport->setUsername($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($pass) {
|
|
||||||
$transport->setPassword($pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transport;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new LogicException(sprintf('The "%s" mailer is not supported.', $parsedDsn['host']));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
<?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\Transport;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
|
||||||
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractTransportFactory implements TransportFactoryInterface
|
||||||
|
{
|
||||||
|
protected $dispatcher;
|
||||||
|
protected $client;
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null)
|
||||||
|
{
|
||||||
|
$this->dispatcher = $dispatcher;
|
||||||
|
$this->client = $client;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUser(Dsn $dsn): string
|
||||||
|
{
|
||||||
|
$user = $dsn->getUser();
|
||||||
|
if (null === $user) {
|
||||||
|
throw new IncompleteDsnException('User is not set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPassword(Dsn $dsn): string
|
||||||
|
{
|
||||||
|
$password = $dsn->getPassword();
|
||||||
|
if (null === $password) {
|
||||||
|
throw new IncompleteDsnException('Password is not set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $password;
|
||||||
|
}
|
||||||
|
}
|
89
src/Symfony/Component/Mailer/Transport/Dsn.php
Normal file
89
src/Symfony/Component/Mailer/Transport/Dsn.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?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\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class Dsn
|
||||||
|
{
|
||||||
|
private $scheme;
|
||||||
|
private $host;
|
||||||
|
private $user;
|
||||||
|
private $password;
|
||||||
|
private $port;
|
||||||
|
private $options;
|
||||||
|
|
||||||
|
public function __construct(string $scheme, string $host, ?string $user = null, ?string $password = null, ?int $port = null, array $options = [])
|
||||||
|
{
|
||||||
|
$this->scheme = $scheme;
|
||||||
|
$this->host = $host;
|
||||||
|
$this->user = $user;
|
||||||
|
$this->password = $password;
|
||||||
|
$this->port = $port;
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromString(string $dsn): self
|
||||||
|
{
|
||||||
|
if (false === $parsedDsn = parse_url($dsn)) {
|
||||||
|
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($parsedDsn['scheme'])) {
|
||||||
|
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a transport scheme.', $dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($parsedDsn['host'])) {
|
||||||
|
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = urldecode($parsedDsn['user'] ?? null);
|
||||||
|
$password = urldecode($parsedDsn['pass'] ?? null);
|
||||||
|
$port = $parsedDsn['port'] ?? null;
|
||||||
|
parse_str($parsedDsn['query'] ?? '', $query);
|
||||||
|
|
||||||
|
return new self($parsedDsn['scheme'], $parsedDsn['host'], $user, $password, $port, $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScheme(): string
|
||||||
|
{
|
||||||
|
return $this->scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHost(): string
|
||||||
|
{
|
||||||
|
return $this->host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): ?string
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPassword(): ?string
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPort(int $default = null): ?int
|
||||||
|
{
|
||||||
|
return $this->port ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOption(string $key, $default = null)
|
||||||
|
{
|
||||||
|
return $this->options[$key] ?? $default;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
<?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\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class NullTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
if ('smtp' === $dsn->getScheme()) {
|
||||||
|
return new NullTransport($this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'null' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
<?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\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class SendmailTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
if ('smtp' === $dsn->getScheme()) {
|
||||||
|
return new SendmailTransport(null, $this->dispatcher, $this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedSchemeException($dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'sendmail' === $dsn->getHost();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?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\Transport\Smtp;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||||
|
use Symfony\Component\Mailer\Transport\Dsn;
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
final class EsmtpTransportFactory extends AbstractTransportFactory
|
||||||
|
{
|
||||||
|
public function create(Dsn $dsn): TransportInterface
|
||||||
|
{
|
||||||
|
$encryption = $dsn->getOption('encryption');
|
||||||
|
$authMode = $dsn->getOption('auth_mode');
|
||||||
|
$port = $dsn->getPort(25);
|
||||||
|
$host = $dsn->getHost();
|
||||||
|
|
||||||
|
$transport = new EsmtpTransport($host, $port, $encryption, $authMode, $this->dispatcher, $this->logger);
|
||||||
|
|
||||||
|
if ($user = $dsn->getUser()) {
|
||||||
|
$transport->setUsername($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($password = $dsn->getPassword()) {
|
||||||
|
$transport->setPassword($password);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool
|
||||||
|
{
|
||||||
|
return 'smtp' === $dsn->getScheme();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
<?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\Transport;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
|
||||||
|
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||||
|
*/
|
||||||
|
interface TransportFactoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws UnsupportedSchemeException
|
||||||
|
* @throws IncompleteDsnException
|
||||||
|
*/
|
||||||
|
public function create(Dsn $dsn): TransportInterface;
|
||||||
|
|
||||||
|
public function supports(Dsn $dsn): bool;
|
||||||
|
}
|
@ -633,14 +633,24 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
$access[self::ACCESS_HAS_PROPERTY] = $reflClass->hasProperty($property);
|
$access[self::ACCESS_HAS_PROPERTY] = $reflClass->hasProperty($property);
|
||||||
$camelized = $this->camelize($property);
|
$camelized = $this->camelize($property);
|
||||||
$singulars = (array) Inflector::singularize($camelized);
|
$singulars = (array) Inflector::singularize($camelized);
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
if ($useAdderAndRemover) {
|
if ($useAdderAndRemover) {
|
||||||
$methods = $this->findAdderAndRemover($reflClass, $singulars);
|
foreach ($this->findAdderAndRemover($reflClass, $singulars) as $methods) {
|
||||||
|
if (3 === \count($methods)) {
|
||||||
if (null !== $methods) {
|
|
||||||
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
|
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
|
||||||
$access[self::ACCESS_ADDER] = $methods[0];
|
$access[self::ACCESS_ADDER] = $methods[self::ACCESS_ADDER];
|
||||||
$access[self::ACCESS_REMOVER] = $methods[1];
|
$access[self::ACCESS_REMOVER] = $methods[self::ACCESS_REMOVER];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($methods[self::ACCESS_ADDER])) {
|
||||||
|
$errors[] = sprintf('The add method "%s" in class "%s" was found, but the corresponding remove method "%s" was not found', $methods['methods'][self::ACCESS_ADDER], $reflClass->name, $methods['methods'][self::ACCESS_REMOVER]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($methods[self::ACCESS_REMOVER])) {
|
||||||
|
$errors[] = sprintf('The remove method "%s" in class "%s" was found, but the corresponding add method "%s" was not found', $methods['methods'][self::ACCESS_REMOVER], $reflClass->name, $methods['methods'][self::ACCESS_ADDER]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,19 +674,56 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
// we call the getter and hope the __call do the job
|
// we call the getter and hope the __call do the job
|
||||||
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC;
|
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC;
|
||||||
$access[self::ACCESS_NAME] = $setter;
|
$access[self::ACCESS_NAME] = $setter;
|
||||||
} elseif (null !== $methods = $this->findAdderAndRemover($reflClass, $singulars)) {
|
} else {
|
||||||
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
|
foreach ($this->findAdderAndRemover($reflClass, $singulars) as $methods) {
|
||||||
$access[self::ACCESS_NAME] = sprintf(
|
if (3 === \count($methods)) {
|
||||||
|
$errors[] = sprintf(
|
||||||
'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
|
'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
|
||||||
'the new value must be an array or an instance of \Traversable, '.
|
'the new value must be an array or an instance of \Traversable, '.
|
||||||
'"%s" given.',
|
'"%s" given.',
|
||||||
$property,
|
$property,
|
||||||
$reflClass->name,
|
$reflClass->name,
|
||||||
implode('()", "', $methods),
|
implode('()", "', [$methods[self::ACCESS_ADDER], $methods[self::ACCESS_REMOVER]]),
|
||||||
\is_object($value) ? \get_class($value) : \gettype($value)
|
\is_object($value) ? \get_class($value) : \gettype($value)
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($access[self::ACCESS_NAME])) {
|
||||||
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
|
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
|
||||||
|
|
||||||
|
$triedMethods = [
|
||||||
|
$setter => 1,
|
||||||
|
$getsetter => 1,
|
||||||
|
'__set' => 2,
|
||||||
|
'__call' => 2,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($singulars as $singular) {
|
||||||
|
$triedMethods['add'.$singular] = 1;
|
||||||
|
$triedMethods['remove'.$singular] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($triedMethods as $methodName => $parameters) {
|
||||||
|
if (!$reflClass->hasMethod($methodName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = $reflClass->getMethod($methodName);
|
||||||
|
|
||||||
|
if (!$method->isPublic()) {
|
||||||
|
$errors[] = sprintf('The method "%s" in class "%s" was found but does not have public access', $methodName, $reflClass->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($method->getNumberOfRequiredParameters() > $parameters || $method->getNumberOfParameters() < $parameters) {
|
||||||
|
$errors[] = sprintf('The method "%s" in class "%s" requires %d arguments, but should accept only %d', $methodName, $reflClass->name, $method->getNumberOfRequiredParameters(), $parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\count($errors)) {
|
||||||
|
$access[self::ACCESS_NAME] = implode('. ', $errors).'.';
|
||||||
|
} else {
|
||||||
$access[self::ACCESS_NAME] = sprintf(
|
$access[self::ACCESS_NAME] = sprintf(
|
||||||
'Neither the property "%s" nor one of the methods %s"%s()", "%s()", '.
|
'Neither the property "%s" nor one of the methods %s"%s()", "%s()", '.
|
||||||
'"__set()" or "__call()" exist and have public access in class "%s".',
|
'"__set()" or "__call()" exist and have public access in class "%s".',
|
||||||
@ -690,6 +737,8 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($item)) {
|
if (isset($item)) {
|
||||||
$this->cacheItemPool->save($item->set($access));
|
$this->cacheItemPool->save($item->set($access));
|
||||||
@ -751,13 +800,21 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
foreach ($singulars as $singular) {
|
foreach ($singulars as $singular) {
|
||||||
$addMethod = 'add'.$singular;
|
$addMethod = 'add'.$singular;
|
||||||
$removeMethod = 'remove'.$singular;
|
$removeMethod = 'remove'.$singular;
|
||||||
|
$result = ['methods' => [self::ACCESS_ADDER => $addMethod, self::ACCESS_REMOVER => $removeMethod]];
|
||||||
|
|
||||||
$addMethodFound = $this->isMethodAccessible($reflClass, $addMethod, 1);
|
$addMethodFound = $this->isMethodAccessible($reflClass, $addMethod, 1);
|
||||||
|
|
||||||
|
if ($addMethodFound) {
|
||||||
|
$result[self::ACCESS_ADDER] = $addMethod;
|
||||||
|
}
|
||||||
|
|
||||||
$removeMethodFound = $this->isMethodAccessible($reflClass, $removeMethod, 1);
|
$removeMethodFound = $this->isMethodAccessible($reflClass, $removeMethod, 1);
|
||||||
|
|
||||||
if ($addMethodFound && $removeMethodFound) {
|
if ($removeMethodFound) {
|
||||||
return [$addMethod, $removeMethod];
|
$result[self::ACCESS_REMOVER] = $removeMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
<?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\PropertyAccess\Tests\Fixtures;
|
||||||
|
|
||||||
|
class TestAdderRemoverInvalidArgumentLength
|
||||||
|
{
|
||||||
|
public function addFoo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeFoo($var1, $var2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBar($var1, $var2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<?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\PropertyAccess\Tests\Fixtures;
|
||||||
|
|
||||||
|
class TestAdderRemoverInvalidMethods
|
||||||
|
{
|
||||||
|
public function addFoo($foo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeBar($foo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -29,4 +29,8 @@ class TestClassSetValue
|
|||||||
{
|
{
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setFoo()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ abstract class PropertyAccessorCollectionTest extends PropertyAccessorArrayAcces
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
* expectedExceptionMessageRegExp /The property "axes" in class "Mock_PropertyAccessorCollectionTest_Car[^"]*" can be defined with the methods "addAxis()", "removeAxis()" but the new value must be an array or an instance of \Traversable, "string" given./
|
* @expectedExceptionMessageRegExp /Could not determine access type for property "axes" in class "Mock_PropertyAccessorCollectionTest_Car[^"]*": The property "axes" in class "Mock_PropertyAccessorCollectionTest_Car[^"]*" can be defined with the methods "addAxis\(\)", "removeAxis\(\)" but the new value must be an array or an instance of \\Traversable, "string" given./
|
||||||
*/
|
*/
|
||||||
public function testSetValueFailsIfAdderAndRemoverExistButValueIsNotTraversable()
|
public function testSetValueFailsIfAdderAndRemoverExistButValueIsNotTraversable()
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,8 @@ use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
|
|||||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
||||||
use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped;
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped;
|
||||||
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidArgumentLength;
|
||||||
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidMethods;
|
||||||
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass;
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass;
|
||||||
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable;
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable;
|
||||||
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall;
|
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall;
|
||||||
@ -762,4 +764,54 @@ class PropertyAccessorTest extends TestCase
|
|||||||
|
|
||||||
$this->assertEquals(['aeroplane'], $object->getAircraft());
|
$this->assertEquals(['aeroplane'], $object->getAircraft());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
|
* @expectedExceptionMessageRegExp /.*The add method "addFoo" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestAdderRemoverInvalidMethods" was found, but the corresponding remove method "removeFoo" was not found\./
|
||||||
|
*/
|
||||||
|
public function testAdderWithoutRemover()
|
||||||
|
{
|
||||||
|
$object = new TestAdderRemoverInvalidMethods();
|
||||||
|
$this->propertyAccessor->setValue($object, 'foos', [1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
|
* @expectedExceptionMessageRegExp /.*The remove method "removeBar" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestAdderRemoverInvalidMethods" was found, but the corresponding add method "addBar" was not found\./
|
||||||
|
*/
|
||||||
|
public function testRemoverWithoutAdder()
|
||||||
|
{
|
||||||
|
$object = new TestAdderRemoverInvalidMethods();
|
||||||
|
$this->propertyAccessor->setValue($object, 'bars', [1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
|
* @expectedExceptionMessageRegExp /.*The method "addFoo" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestAdderRemoverInvalidArgumentLength" requires 0 arguments, but should accept only 1\. The method "removeFoo" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestAdderRemoverInvalidArgumentLength" requires 2 arguments, but should accept only 1\./
|
||||||
|
*/
|
||||||
|
public function testAdderAndRemoveNeedsTheExactParametersDefined()
|
||||||
|
{
|
||||||
|
$object = new TestAdderRemoverInvalidArgumentLength();
|
||||||
|
$this->propertyAccessor->setValue($object, 'foo', [1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
|
* @expectedExceptionMessageRegExp /.*The method "setBar" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestAdderRemoverInvalidArgumentLength" requires 2 arguments, but should accept only 1\./
|
||||||
|
*/
|
||||||
|
public function testSetterNeedsTheExactParametersDefined()
|
||||||
|
{
|
||||||
|
$object = new TestAdderRemoverInvalidArgumentLength();
|
||||||
|
$this->propertyAccessor->setValue($object, 'bar', [1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException
|
||||||
|
* @expectedExceptionMessageRegExp /.*The method "setFoo" in class "Symfony\\Component\\PropertyAccess\\Tests\\Fixtures\\TestClassSetValue" was found but does not have public access./
|
||||||
|
*/
|
||||||
|
public function testSetterNeedsPublicAccess()
|
||||||
|
{
|
||||||
|
$object = new TestClassSetValue(0);
|
||||||
|
$this->propertyAccessor->setValue($object, 'foo', 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,9 @@ CHANGELOG
|
|||||||
from an array or object
|
from an array or object
|
||||||
* added the `min_limit_path` and `max_limit_path` parameters in violations when using
|
* added the `min_limit_path` and `max_limit_path` parameters in violations when using
|
||||||
`Range` constraint with respectively the `minPropertyPath` and
|
`Range` constraint with respectively the `minPropertyPath` and
|
||||||
`maxPropertyPath` options.
|
`maxPropertyPath` options
|
||||||
* added a new `notInRangeMessage` options to the `Range` constraint that will
|
* added a new `notInRangeMessage` option to the `Range` constraint that will
|
||||||
be used in the violation builder when both `min` and `max` are not null.
|
be used in the violation builder when both `min` and `max` are not null
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -362,6 +362,10 @@
|
|||||||
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
|
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
|
||||||
<target>Dit wachtwoord is gelekt vanwege een data-inbreuk, het moet niet worden gebruikt. Kies een ander wachtwoord.</target>
|
<target>Dit wachtwoord is gelekt vanwege een data-inbreuk, het moet niet worden gebruikt. Kies een ander wachtwoord.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="94">
|
||||||
|
<source>This value should be between {{ min }} and {{ max }}.</source>
|
||||||
|
<target>Deze waarde moet zich tussen {{ min }} en {{ max }} bevinden.</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
@ -19,6 +19,29 @@ use Symfony\Component\VarDumper\Dumper\CliDumper;
|
|||||||
*/
|
*/
|
||||||
trait VarDumperTestTrait
|
trait VarDumperTestTrait
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private $varDumperConfig = [
|
||||||
|
'casters' => [],
|
||||||
|
'flags' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected function setUpVarDumper(array $casters, int $flags = null): void
|
||||||
|
{
|
||||||
|
$this->varDumperConfig['casters'] = $casters;
|
||||||
|
$this->varDumperConfig['flags'] = $flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @after
|
||||||
|
*/
|
||||||
|
protected function tearDownVarDumper(): void
|
||||||
|
{
|
||||||
|
$this->varDumperConfig['casters'] = [];
|
||||||
|
$this->varDumperConfig['flags'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
public function assertDumpEquals($expected, $data, $filter = 0, $message = '')
|
public function assertDumpEquals($expected, $data, $filter = 0, $message = '')
|
||||||
{
|
{
|
||||||
$this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message);
|
$this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message);
|
||||||
@ -31,11 +54,14 @@ trait VarDumperTestTrait
|
|||||||
|
|
||||||
protected function getDump($data, $key = null, $filter = 0)
|
protected function getDump($data, $key = null, $filter = 0)
|
||||||
{
|
{
|
||||||
|
if (null === $flags = $this->varDumperConfig['flags']) {
|
||||||
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
|
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
|
||||||
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
|
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
|
||||||
$flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0;
|
$flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0;
|
||||||
|
}
|
||||||
|
|
||||||
$cloner = new VarCloner();
|
$cloner = new VarCloner();
|
||||||
|
$cloner->addCasters($this->varDumperConfig['casters']);
|
||||||
$cloner->setMaxItems(-1);
|
$cloner->setMaxItems(-1);
|
||||||
$dumper = new CliDumper(null, null, $flags);
|
$dumper = new CliDumper(null, null, $flags);
|
||||||
$dumper->setColors(false);
|
$dumper->setColors(false);
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
namespace Symfony\Component\VarDumper\Tests\Test;
|
namespace Symfony\Component\VarDumper\Tests\Test;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\Stub;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||||
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
|
||||||
|
|
||||||
class VarDumperTestTraitTest extends TestCase
|
class VarDumperTestTraitTest extends TestCase
|
||||||
@ -43,4 +45,34 @@ EODUMP;
|
|||||||
{
|
{
|
||||||
$this->assertDumpEquals(new \ArrayObject(['bim' => 'bam']), new \ArrayObject(['bim' => 'bam']));
|
$this->assertDumpEquals(new \ArrayObject(['bim' => 'bam']), new \ArrayObject(['bim' => 'bam']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItCanBeConfigured()
|
||||||
|
{
|
||||||
|
$this->setUpVarDumper($casters = [
|
||||||
|
\DateTimeInterface::class => static function (\DateTimeInterface $date, array $a, Stub $stub): array {
|
||||||
|
$stub->class = 'DateTime';
|
||||||
|
|
||||||
|
return ['date' => $date->format('d/m/Y')];
|
||||||
|
},
|
||||||
|
], CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
|
||||||
|
|
||||||
|
$this->assertSame(CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR, $this->varDumperConfig['flags']);
|
||||||
|
$this->assertSame($casters, $this->varDumperConfig['casters']);
|
||||||
|
|
||||||
|
$this->assertDumpEquals(<<<DUMP
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
DateTime {
|
||||||
|
+date: "09/07/2019"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
DUMP
|
||||||
|
, [1, 2, new \DateTime('2019-07-09T0:00:00+00:00')]);
|
||||||
|
|
||||||
|
$this->tearDownVarDumper();
|
||||||
|
|
||||||
|
$this->assertNull($this->varDumperConfig['flags']);
|
||||||
|
$this->assertSame([], $this->varDumperConfig['casters']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user