2017-04-04 23 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