2017-04-04 60 views
0

对于某些上下文 - 今天早些时候,我一直在努力弄清楚如何实现一个类似于Cache的外观 - 在那里我可以设置一个提供者(如disk()),但也有当不提供通用回退提供程序时。Facade在工厂类Laravel前的实现5.4

现在,我得到了基本的基础架构工作,但我认为我的实现是令人讨厌的。调用default()或provider()只是很臭。然而,这里有一个概念或者我错过了填补空白的地方。

Implementing similar functionality to Cache::disk('x') in Laravel

这里是我做了什么。

// Factories\SMSFactory.php 

namespace App\Factories; 

use App\IError; 


class SMSFactory 
{ 
    public static function default() 
    { 
     $defaultProvider = config('sms.default_provider'); 
     return self::provider($defaultProvider); 
    } 

    public static function provider($providerId) 
    { 
     $providerClass = config('sms.' . $providerId); 

     if (class_exists($providerClass)) 
     { 
      return (new $providerClass); 
     } 

     return new class implements IError { 

     }; 
    } 

} 

// sms.php (config) 

return [ 
    /** 
    * Set the default SMS provider for the application 
    */ 
    'default_provider' => 'smsglobal', 

    /** 
    * Map the SMS provider to a class implementation 
    */ 
    'smsglobal' => 'App\SMSGlobal\SMSGlobal', 
]; 

// Providers\SMSServiceProvider.php 

namespace App\Providers; 

use Illuminate\Support\ServiceProvider; 


class SMSServiceProvider extends ServiceProvider 
{ 
    /** 
    * Bootstrap the application services. 
    * 
    * @return void 
    */ 
    public function boot() 
    { 
     // 
    } 

    /** 
    * Register the application services. 
    * 
    * 
    * @return void 
    */ 
    public function register() 
    { 
     $this->app->bind('sms', 'App\Factories\SMSFactory'); 
    } 
} 

// Facades\SMS.php 

namespace App\Facades; 

use Illuminate\Support\Facades\Facade; 

class SMS extends Facade 
{ 
    protected static function getFacadeAccessor() 
    { 
     return 'sms'; 
    } 
} 


// app.php 

App\Providers\SMSServiceProvider::class, 

# and in aliases 

'SMS' => App\Facades\SMS::class, 


// Controllers/TestController.php 


namespace App\Http\Controllers\TestController; 

use App\Http\Controllers\Controller; 
use Illuminate\Http\Request; 

use App\Facades\SMS; 


class TestController extends Controller 
{ 
    public function sendSMS($destination, $message) 
    { 
     $data = $request->all(); 

     return SMS::default()->send([ 
      'destination' => $destination, 
      'message' => $message, 
     ]); 
    } 
} 

什么是真正困扰我的是不必总是使用默认值()...

据我所知,门面作为一个静态类,但有可能将其设置以这样的方式我可以打电话吗?

SMS::send($args); 

// When I want to use another gateway 
SMS::provider('nexmo')->send($args); 
+0

在您的提供者类中,您是否有办法更改为不同的提供者? –

+0

服务提供商绑定工厂。因此,只要在sms.php配置文件中定义了“新网关”,我就可以通过SMS :: provider('new-gateway')切换网关。该部分全部正常工作 – Trent

回答

1

您可以在短信工厂类使用__call方法,而且必须相应改变:

class SMSFactory 
{ 
    public function default() 
    { 
     $defaultProvider = config('sms.default_provider'); 

     return $this->provider($defaultProvider); 
    } 

    public function provider($providerId) 
    { 
     $providerClass = config('sms.' . $providerId); 

     if (class_exists($providerClass)) 
     { 
      return (new $providerClass); 
     } 

     return new class implements IError { 

     }; 
    } 

    public function __call($name, $arguments) 
    { 
     if (!method_exists($this, $name)) { 
      $object = [$this->default(), $name]; 
     } else { 
      $object = [$this, $name]; 
     } 

     return call_user_func_array($object, $arguments); 
    } 
} 

的SMSFactory类不应该静态方法为静态方法可以通过立面进行访问。

+0

因此,神奇的方法意味着我可以将任何方法调用到外观作为静态,这将尝试并生成一个新的实例,然后在该实例上运行该命令。当我把它放入我的代码时,它告诉我调用未定义的方法SMSFactory :: send()。从控制器运行SMS :: send('Testing'); – Trent

+0

当方法不存在时,我也注意到call_user_func_array没有将函数名称传递给实例,因此我将其更改为[$ default,$ name],$ arguments - 但仍然没有解决问题 – Trent

+0

OK - 结果这个函数甚至没有被称为(PHP7)... – Trent