是否可以将接口绑定到 Laravel 控制器中的实现?类似于以下非常粗略的示例:
if($property->param == 1){
$mailSourceData = bind('MailInterface', 'gmailProviderRepo')
{
else if($property->param == 2){
$mailSourceData = bind('MailInterface', 'yahooProviderRepo')
}
$mailSourceData->sendMail($emailBody);
Run Code Online (Sandbox Code Playgroud)
这不适用于服务提供者中的上下文绑定,因为当时我不知道我将需要哪个接口实现,并且“$property”对服务提供者不可用。
你可以使用 Laravel 的服务容器:
https://laravel.com/docs/5.0/container
我认为单身人士可能是您的选择:
$this->app->singleton('FooBar', function($app)
{
return new FooBar($app['SomethingElse']);
});
Run Code Online (Sandbox Code Playgroud)
你可以使用任何你想要的键,不需要是接口或类名,即使它是值得推荐的。
然后你可以称之为:
$fooBar = $this->app->make('FooBar');
Run Code Online (Sandbox Code Playgroud)
要自动加载它以使其始终可访问,您可以使用服务提供商:
https://laravel.com/docs/5.6/providers
您可以检查原始邮件服务提供商如何设置复制一些想法:
https://github.com/laravel/framework/blob/5.6/src/Illuminate/Mail/MailServiceProvider.php
默认邮件服务提供商是:
/**
* Register the Illuminate mailer instance.
*
* @return void
*/
protected function registerIlluminateMailer()
{
$this->app->singleton('mailer', function ($app) {
$config = $app->make('config')->get('mail');
// Once we have create the mailer instance, we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new Mailer(
$app['view'], $app['swift.mailer'], $app['events']
);
if ($app->bound('queue')) {
$mailer->setQueue($app['queue']);
}
// Next we will set all of the global addresses on this mailer, which allows
// for easy unification of all "from" addresses as well as easy debugging
// of sent messages since they get be sent into a single email address.
foreach (['from', 'reply_to', 'to'] as $type) {
$this->setGlobalAddress($mailer, $config, $type);
}
return $mailer;
});
}
Run Code Online (Sandbox Code Playgroud)
它使用单例$app['swift.mailer'],它被创建为:
/**
* Register the Swift Mailer instance.
*
* @return void
*/
public function registerSwiftMailer()
{
$this->registerSwiftTransport();
// Once we have the transporter registered, we will register the actual Swift
// mailer instance, passing in the transport instances, which allows us to
// override this transporter instances during app start-up if necessary.
$this->app->singleton('swift.mailer', function ($app) {
return new Swift_Mailer($app['swift.transport']->driver());
});
}
Run Code Online (Sandbox Code Playgroud)
这个使用$app['swift.transport']创建的:
/**
* Register the Swift Transport instance.
*
* @return void
*/
protected function registerSwiftTransport()
{
$this->app->singleton('swift.transport', function ($app) {
return new TransportManager($app);
});
}
Run Code Online (Sandbox Code Playgroud)
您可以在此处查看 TransportManager 的代码:
https://github.com/laravel/framework/blob/5.6/src/Illuminate/Mail/TransportManager.php
它使用默认驱动程序,因为没有其他驱动程序传递给方法driver()。
重用此代码可能很有趣,但它从配置中获取值,除非我们覆盖配置(在这种情况下根本不推荐!),否则无法传递其他值。
所以剩下的唯一选择是脏复制粘贴。
您可以创建一个新的 TransportManager 来支持不同的驱动程序,但这会使它过于复杂,我想现在仅支持 smtp 驱动程序就足够了。
您的自定义邮件服务提供商可能类似于:
<?php
namespace App\Providers;
use Swift_Mailer;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\ServiceProvider;
use Swift_SmtpTransport as SmtpTransport;
class MultipleMailServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->registerMultipleMailer();
}
/**
* Register the Illuminate mailer instance.
*
* @return void
*/
protected function registerMultipleMailer()
{
foreach ($this->app->make('config')->get('mail.multiple') as $key => $config) {
$this->app->singleton($key, function ($app) use ($config) {
// Once we have create the mailer instance, we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new Mailer(
$app['view'], new Swift_Mailer($this->createSmtpDriver($config)), $app['events']
);
// Next we will set all of the global addresses on this mailer, which allows
// for easy unification of all "from" addresses as well as easy debugging
// of sent messages since they get be sent into a single email address.
foreach (['from', 'reply_to', 'to'] as $type) {
$this->setGlobalAddress($mailer, $config, $type);
}
return $mailer;
});
}
}
/**
* Set a global address on the mailer by type.
*
* @param \Illuminate\Mail\Mailer $mailer
* @param array $config
* @param string $type
* @return void
*/
protected function setGlobalAddress($mailer, array $config, $type)
{
$address = Arr::get($config, $type);
if (is_array($address) && isset($address['address'])) {
$mailer->{'always'.Str::studly($type)}($address['address'], $address['name']);
}
}
/**
* Create an instance of the SMTP Swift Transport driver.
*
* @param array $config
*
* @return \Swift_SmtpTransport
*/
protected function createSmtpDriver($config)
{
// The Swift SMTP transport instance will allow us to use any SMTP backend
// for delivering mail such as Sendgrid, Amazon SES, or a custom server
// a developer has available. We will just pass this configured host.
$transport = new SmtpTransport($config['host'], $config['port']);
if (isset($config['encryption'])) {
$transport->setEncryption($config['encryption']);
}
// Once we have the transport we will check for the presence of a username
// and password. If we have it we will set the credentials on the Swift
// transporter instance so that we'll properly authenticate delivery.
if (isset($config['username'])) {
$transport->setUsername($config['username']);
$transport->setPassword($config['password']);
}
// Next we will set any stream context options specified for the transport
// and then return it. The option is not required any may not be inside
// the configuration array at all so we'll verify that before adding.
if (isset($config['stream'])) {
$transport->setStreamOptions($config['stream']);
}
return $transport;
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array_keys($this->app->make('config')->get('mail.multiple'));
}
}
Run Code Online (Sandbox Code Playgroud)
然后您可能需要将数据添加到您的 mail.php 配置文件(或另一个),如:
'multiple' => [
'mailer.gmail' => [
'host' => env('MAIL_GAMIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_GAMIL_PORT', 587),
'from' => [
'address' => env('MAIL_GAMIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_GAMIL_FROM_NAME', 'Example'),
],
'encryption' => env('MAIL_GAMIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_GAMIL_USERNAME'),
'password' => env('MAIL_GAMIL_PASSWORD'),
],
'mailer.yahoo' => [
'host' => env('MAIL_YAHOO_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_YAHOO_PORT', 587),
'from' => [
'address' => env('MAIL_YAHOO_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_YAHOO_FROM_NAME', 'Example'),
],
'encryption' => env('MAIL_YAHOO_ENCRYPTION', 'tls'),
'username' => env('MAIL_YAHOO_USERNAME'),
'password' => env('MAIL_YAHOO_PASSWORD'),
],
],
Run Code Online (Sandbox Code Playgroud)
不要忘记注册您的服务提供商:
https://laravel.com/docs/5.6/providers#registering-providers
'providers' => [
// Other Service Providers
App\Providers\MultipleMailServiceProvider::class,
],
Run Code Online (Sandbox Code Playgroud)
然后,一旦服务提供者在服务容器中定义了单例,您就可以通过多种方式构建和加载创建的单例。一种方法是:
switch ($property->param) {
case 1:
$mailSourceData = app('mailer.gmail');
break;
case 2:
$mailSourceData = app('mailer.yahoo');
break;
default:
throw new \InvalidArgumentException('Invalid property param');
}
$mailSourceData->sendMail($emailBody);
Run Code Online (Sandbox Code Playgroud)
您甚至可以创建 Facedes 和别名...
https://laravel.com/docs/5.6/facades
当然,有一些可能的改进可以在这里和那里完成,但这只是一个概念证明。
| 归档时间: |
|
| 查看次数: |
4435 次 |
| 最近记录: |