雖然 Controller 昨天切成兩個了,但是裡面還是亂七八糟,今天的目標是要把裡面盡可能的整理。
Shop
與 Mysql
在這個應用程式裡,是屬於單例的角色。我們可以把這兩個物件,放在 Laravel Container 裡,透過 DI 注入讓 Controller 取得,這樣程式會更加簡潔。
首先我們先處理 Mysql
:
// app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Mysql::class, function ($app) {
// 定義 Mysql 物件如何建構
require base_path('config.php');
return new Mysql(env('APP_DEBUG', false));
});
}
}
如此在使用 app(Mysql::class)
就能取得到 Mysql
單例物件了。接著在調整 Shop
的建構子:
public function __construct(Mysql $mysql)
{
$this->_db = $mysql;
}
這樣在使用 app(Shop::class)
時, Laravel 會發現要注入 Mysql
物件,所以會接著用 app(Mysql::class)
拿到 Mysql
物件後,再繼續把 Shop 物件建構出來。
Controller 的 Action 也有一樣的功能:當定義 Shop
物件時, Laravel 會使用 app(Shop::class)
取得 Shop
物件再傳入 action :
public function index(Request $request, Shop $shop)
{
}
如此一來,就不需要在 controller 裡面建構 Shop
物件,而能專注在如何操作 Shop
物件。
同理 Smarty 也能做一樣的處理:
$this->app->singleton(Smarty::class, function () {
$instance = new Smarty;
$instance->template_dir = base_path('/templates/');
$instance->compile_dir = base_path('/templates/compile/');
$instance->config_dir = base_path('/templates/configs/');
$instance->cache_dir = base_path('/templates/cache/');
$instance->caching = false;
$instance->auto_literal = false;
$instance->left_delimiter = '<%';
$instance->right_delimiter = '%>';
$instance->assign('config', [
'debug' => DEBUG_MODE,
'per_page' => PER_PAGE,
'per_top_list' => PER_TOP_LIST
]);
return $instance;
});
完成後, coverage 累積上升 1.98% 。
上面做完之後,會發現 config.php
的內容都是定義常數,因此可以移到 Service Provider 裡的 boot()
方法,接著就能移除它了。
帳號密碼目前的設計也是常數,所以先暫時也用常數處理。
完成後, coverage 累積上升 2.76% 。
如 contact 的功能相對獨立,可以另外拆出一個 Controller 來處理:
class ContactController extends Controller
{
public function index()
{
return view('shop.contact');
}
}
調整 Route :
Route::get('/contact', 'ContactController@index');
調整 View :
<a href="/contact">聯絡我們</a>
測試也得調整:
$browser->visit('/contact')
這樣就能把一個頁面移出另一個 controller 了。
同樣的方法也可以用在 admin 登入頁。
Laravel 的套件 Request
提供了許多取得 HTTP request 的方法,如:
if (!isset($_GET['act'])) {
$_GET['act'] = 'main';
}
switch ($_GET['act']) {}
可以用下面的程式碼取代:
$act = $request->query('act', 'main');
switch ($act) {}
記得要先確認其他程式碼沒有使用到
$_GET['act']
才能直接這樣改。
許多常用的判斷,框架都有提供更精簡的方法提供開發者使用。因此改使用這些方法,也是個提高易讀性的好辦法。
今天的程式可以參考 GitHub PR 。
上面的技巧不斷使用後,會發現 coverage 越來越高,程式也會越來越精簡好懂,這正是重構的目的與價值。