- 服務模式
- 在 app 目錄下建立一個 Repositories 目錄,在 Repositories目錄下,建立三個子目錄:Contracts、Eloquent 和Exceptions。
Contracts: 介面目錄
Eloquent: 用於存放實現Repository介面的抽象類和具體類。
Exceptions:目錄用於存放異常處理類。
這種模式是參考Laravel的服務容器和服務提供者,Laravel 服務容器是一個用於管理類依賴和執行依賴注入的強大工具。依賴注入聽上去很花哨,其實質是透過建構函式或者某些情況下透過 set 方法將類依賴注入到類中。服務提供者是所有Laravel應用啟動的中心,你自己的應用以及所有Laravel的核心服務都是透過服務提供者啟動。透過服務容器建立服務(service),然後在服務提供者中(provider)註冊。 - 實現步驟:
- 定義介面
在app\Repositories\Contracts 資料夾下建立 UserInterface.php<?php namespace App\Repositories\Contracts; interface UserInterface{ public function findBy($id); }
- 實現介面類
在app\Repositories\Eloquent 資料夾下建立UserServiceRepository.php<?php namespace App\Repositories\Eloquent; use App\Repositories\Contracts\UserInterface; use App\User; //服務模式 class UserServiceRepository implements UserInterface{ public function findBy($id) { return User::find($id); } }
- 註冊服務
建立provider或在系統的provider中註冊(介面與實現類的繫結):php artisan make:provider RepositoryServiceProvider
開啟app\Providers\RepositoryServiceProvider.php
public function register() { //介面與實現類的兩種繫結模式 //單例模式(個人推薦) $this->app->singleton('App\Repositories\Contracts\UserInterface',function ($app){ return new \App\Repositories\Eloquent\UserServiceRepository(); }); //繫結 // $this->app->bind('App\Repositories\Contracts\UserInterface','App\Repositories\Eloquent\UserServiceRepository'); }
- 新增到配置檔案中:
注:如果不是自己建立provider,而是直接在AppServiceProvider.php中繫結的話,則不需要操作本步驟,因為系統已經引入了那4個Provider 。
具體步驟:
開啟 config/app.php, providers 陣列中新增下面一行:app\Providers\RepositoryServiceProvider::class,
- 在控制器中呼叫
首先要在控制器中引入:use App\Repositories\Contracts\UserInterface;
然後再進行依賴注入:private $user; //定義一個私有的變數 public function __construct(UserInterface $user){ $this->user = $user; } public function index(){ dd($this->user->findBy(1)->toArray()); }
- 定義介面
- 在 app 目錄下建立一個 Repositories 目錄,在 Repositories目錄下,建立三個子目錄:Contracts、Eloquent 和Exceptions。
-
門面模式
- 門面為應用的服務容器中的繫結類提供了一個“靜態”介面。Laravel 內建了很多門面,你可能在不知道的情況下正在使用它們。Laravel 的門面作為服務容器中的底層類的“靜態代理”,相比於傳統靜態方法,在維護時能夠提供更加易於測試、更加靈活的、簡明且富有表現力的語法。門面就是一個提供訪問容器中物件的類。該機制原理由 Facade 類實現,Laravel 自帶的門面,以及建立的自定義門面,都會繼承自 Illuminate\Support\Facades\Facade 基類。門面類只需要實現一個方法:getFacadeAccessor。正是 getFacadeAccessor 方法定義了從容器中解析什麼,然後 Facade 基類使用魔術方法 __callStatic() 從你的門面中呼叫解析物件。
-
實現步驟:
- 定義介面(建議):
雖然門面模式中可以不用定義介面,個人建議還是定義介面。在以後的專案功能升級併相容老功能的時候非常有用,增加了開發時間,卻減少了後期維護或升級功能的難度。
具體步驟:
在 app\Repositories\Contracts 資料夾下新建UserInterface.php<?php namespace App\Repositories\Contracts; interface UserInterface{ public function findBy($id); }
- 介面實現類
具體步驟:
在 app\Repositories\Eloquent 資料夾下新建 UserFacadeRepository.php<?php namespace App\Repositories\Eloquent; use App\Repositories\Contracts\UserInterface; use App\User; class UserFacadeRepository implements UserInterface{ //根據id查詢使用者資訊 public function findBy($id){ return User::find($id); } }
- 註冊服務
執行如下命令,新建一個RepositoryServiceProvider:php artisan make:provider RepositoryServiceProvider
在register 方法中新增如下程式碼來註冊服務:$this->app->singleton('UserFacadeRepository',function ($app){ return new \App\Repositories\Eloquent\UserFacadeRepository(); });
-
定義Facade(門面)
在 app目錄下建立一個 Facades 目錄, Facades目錄下新建一個 UserFacade.php<?php namespace App\Facades; use Illuminate\Support\Facades\Facade; class UserFacade extends Facade{ protected static function getFacadeAccessor(){ return 'UserFacadeRepository'; } }
- 在app\config\app.php中的aliases 陣列中新增下面程式碼:
//自己新建的門面 'UserRepository' => App\Facades\UserFacade::class,
- 使用門面
首先在方法中引入門面:use UserRepository;
使用門面:public function index(){ dd(UserRepository::findBy(1)->toArray()); }
- 定義介面(建議):
-
倉庫(Repository)模式
- Repository 是銜接資料對映層和領域層之間的一個紐帶,作用相當於一個在記憶體中的域物件集合。客戶端物件把查詢的一些實體進行組合,並把它們提交給 Repository。物件能夠從 Repository 中移除或者新增。Repository 是MVC中銜接Controller和Model之間的一個紐帶。從概念上講,Repository 是把將資料給封裝後的集合並提供給Controller的操作。
-
實現步驟:
- 定義介面
在app\Repositories\Contracts 目錄下新建一個UserInterface.php<?php namespace App\Repositories\Contracts; interface UserInterface{ public function findBy($id); }
-
定義一個基本的抽象類:
在 app\Repositories\Eloquent目錄下新建一個Repository.php<?php namespace App\Repositories\Eloquent; use App\Repositories\Contracts\UserInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Container\Container as App; abstract class Repository implements UserInterface{ protected $app; //App容器 protected $model; //操作model public function __construct(App $app){ $this->app = $app; $this->makeModel(); } abstract function model(); public function findBy($id){ return $this->model->find($id); } public function makeModel(){ $model = $this->app->make($this->model()); /*是否是Model例項*/ if (!$model instanceof Model){ throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); } $this->model = $model; } }
- 建立UserRepository.php 並繼承抽象類
在 app\Repositories\Eloquent 目錄下新建一個UserRepository.php<?php namespace App\Repositories\Eloquent; use App\Repositories\Eloquent\Repository; use App\User; class UserRepository extends Repository{ public function model(){ return User::class; } public function findBy($id){ return $this->model->where('id',$id)->first()->toArray(); } }
- 控制器依賴注入
首先需要引入檔案,然後在HomeController類裡書寫程式碼:<?php namespace App\Http\Controllers; use App\Http\Requests; use Illuminate\Http\Request; use App\Repositories\Contracts\UserInterface; use UserRepository; use App\Repositories\Eloquent\UserRepository as UserRepo; class HomeController extends Controller{ private $user; //定義一個私有的變數 private $userRepo; public function __construct(UserInterface $user,UserRepo $userRepo){ $this->user = $user; $this->userRepo = $userRepo; } public function index(){ dd($this->userRepo->findBy(2)); return view('home'); } }
- 定義介面
- 總結:
- 這種將資料訪問從業務邏輯中分離出來的模式有很多好處:
- 集中資料訪問邏輯使程式碼易於維護
- 業務和資料訪問邏輯完全分離
- 減少重複程式碼
- 使程式出錯的機率降低
- 一個控制器呼叫多個Repository資料的時候,要麼都在相應的Repository中進行注入或引用,要麼在控制其中新增。避免交叉引用亂象!
本作品採用《CC 協議》,轉載必須註明作者和本文連結
老郭部落格:laughing:
個人部落格地址:www.phpsix.com