<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 如何使用 Repository 模式 若將數據庫邏輯都寫在 Model 里,會造成 model 代碼的臃腫難以維護,基于 SOLID 原則,我們應該使用 **Repository** 模式輔助 Model,將相關的數據庫邏輯封裝在不同的 Repository,方便后期項目的維護。 ### Laravel 框架版本 Laravel 5.4.17 ### 數據庫邏輯 在 CURD 中,CUR 比較穩定,但 Read 的部分則變化萬千,大部分的數據庫邏輯都在描述 Read 部分,若將數據庫邏輯寫在 Controller 或 Model 都不合適,會造成 Controller 或 Model 代碼臃腫,如后難以維護。 ### Model 使用 Repository 模式之后,Model 僅僅當成 Eloquent Class 即可,不需要包含數據庫邏輯,僅保留如下部分: * Property: 如 `$table` `$fillable` .. * Mutator: 包括 mutator 與 accessor * Method: relation 類的方法,比如使用 `hasMany()` 與 `belongsTo()` 單一對應關系: * hasOne * belongsTo * morphTo * morphOne 多個對應關系指的是使用以下關鍵詞定義的關聯模型: * hasMany * belongsToMany * morphMany * morphToMany * morphedByMany > 因為 Eloquent 會根據數據庫字段動態的產生 property 與 method等,若使用 [Laravel IDE Helper](https://github.com/barryvdh/laravel-ide-helper) ,會直接在Model加上 `@property` 與 `@method` 描述model的動態 proerty 與 method。 如下`app\User.php`中安裝完`Laravel IDE Helper`后執行`php artisan ide-helper:models`后自動生成的內容: ``` <?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; /** * App\User * * @property int $id * @property string $name * @property string $email * @property string $password * @property string $remember_token * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at * @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications * @method static \Illuminate\Database\Query\Builder|\App\User whereCreatedAt($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereEmail($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereId($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereName($value) * @method static \Illuminate\Database\Query\Builder|\App\User wherePassword($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereRememberToken($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereUpdatedAt($value) * @mixin \Eloquent */ class User extends Authenticatable { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; } ``` ### Repository 在開發時常常會在 Controller 直接調用 Model 寫數據庫邏輯,如下:獲取數據庫中用戶 `age>20`的數據。 ``` public function index() { return User::where('age','>',20)->orderBy('age')->get(); } ``` 這樣寫邏輯會有幾個問題: * 將數據庫邏輯寫在 Controller,造成 Controller 代碼臃腫難以維護。 * 違反了 SOLID 的單一職責原則,數據庫邏輯不應該寫在 Controller 中。 * Controller 直接操作 Model,使得對 Controller 做單元測試困難。 比較好的方式是使用 Repository: * 將 Model 依賴注入到 Repository。 * 將數據庫邏輯寫在 Repository。 * 將 Repository 依賴注入到 Service。 `app/Repositories/UserRepostitory.php` 中的內容: ``` <?php namespace App\Repositories; use App\User; /** * Class UserRepository * @package App\Repositories */ class UserRepository { /** * @var User */ private $user; /** * UserRepository constructor. * @param $user */ public function __construct(User $user) { $this->user = $user; } /** * @param $age * @return \Illuminate\Database\Eloquent\Collection|static[] */ public function getAgeLargerThan($age) { return $this->user ->where('age', '>', $age) ->orderBy('age') ->get(); } } ``` 在控制器`app\Controllers\UserController.php`中使用依賴注入: ``` <?php namespace App\Http\Controllers; use App\Repositories\UserRepository; use Illuminate\Http\Request; /** * Class UserController * * @package App\Http\Controllers */ class UserController extends Controller { /** * @var \App\Repositories\UserRepository */ protected $userRepository; /** * UserController constructor. * @param $userRepository */ public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } /** * @return \Illuminate\Database\Eloquent\Collection|static[] */ public function index() { return $this->userRepository->getAgeLargerThan(20); } } ``` 將相依的 `UserRepository` 依賴注入到 `UserController`,并從原本直接依賴 `User` Model改成依賴注入的 `UserRepository` #### 優點 * 將數據庫邏輯寫在 Repository 里,解決了 Controller 代碼臃腫的問題。 * 符合 SOLID 的單一職責原則:數據庫邏輯寫在 Repository 里,沒寫在 Controller 里。 * 符合 SOLID 的依賴反轉原則:Controller 并非直接相依與 Repositroy,而是將 Repository 依賴注入進 Controller。 > 實際上建議 Repository 僅依賴注入進 Service,而不是直接注入在 Controller。 #### 是否該建立 Repository Interface? 理論上使用依賴注入時,應該使用 Interface ,不過 Interface 目的在于更換數據庫,讓代碼達到開放封閉的要求,但是實際上要更改 Reposiroty 的機會也不多,除非是從 MySQL 更換到 MongoDB,此時就應該建立 Repository Interface。 不過由于我們使用了依賴注入,將來要從 Class 改成 Interface 也很方便,只要在 Constructor 的 type hint 改成 Interface 即可,維護成本很低,所以在此大可使用 Repository Class 即可,不一定得用Interface而造成 Over Design,等真正需要修改時,再重構 Interface 即可。 #### 是否該使用 Query Scope? Laravel 4.2 就有 QueryScope,到 Laravel5.1 都還保留著,它讓我們可以將邏輯代碼寫在 Model ,解決了維護與重復使用的問題。 如 `app/User.php` 里的代碼: ``` <?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; /** * App\User * * @property int $id * @property string $name * @property string $email * @property string $password * @property string $remember_token * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at * @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications * @method static \Illuminate\Database\Query\Builder|\App\User whereCreatedAt($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereEmail($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereId($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereName($value) * @method static \Illuminate\Database\Query\Builder|\App\User wherePassword($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereRememberToken($value) * @method static \Illuminate\Database\Query\Builder|\App\User whereUpdatedAt($value) * @mixin \Eloquent */ class User extends Authenticatable { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * * @param Builder $query * @param integer $age * * @return Builder */ public function scopeGetAgerLargerThan($query, $age) { return $query->where('age', '>', $age) ->orderBy('age'); } } ``` QueryScope 必須以 `scope`開頭,第一個參數為 queryBuilder,一定要加上;第二個參數以后為自己要傳入的參數。 由于回傳必須是一個 queryBuilder ,因此不需要加上 `get()` `app/Controllers/UserController.php` 中使用代碼: ``` <?php namespace App\Http\Controllers; use App\Repositories\UserRepository; use App\User; use Illuminate\Http\Request; /** * Class UserController * * @package App\Http\Controllers */ class UserController extends Controller { /** * @var \App\Repositories\UserRepository */ protected $userRepository; /** * UserController constructor. * @param $userRepository */ public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } /** * @return \Illuminate\Database\Eloquent\Collection|static[] */ public function index() { return User::getAgerLargerThan(20)->get(); } } ``` 在 Controller 中使用 QueryScope 時,不需要加上 Prefix,由于其本質是 queryBuilder,所以還要加上 `get()` 才能獲得 Conllection 數據。 由于 QueryScope 是寫在 Model,不是寫在 Controller,所以基本上解決了 Controller 臃腫違反 SOLID 的單一職責原則的問題, Controller 也可以重復使用 QueryScope ,已經比直接將資料庫邏輯寫在 Controlelr 中好很多。 不過若在中大型項目中,仍然有以下問題: * Model 已經有原來的責任,若再加上 queryScope,造成 Model 過于臃腫難以維護。 * 若數據庫邏輯很多,可能拆成多個 Repository,可是確很難拆成多個 Model。 * 單元測試困難,必須面臨 mock Eloquent 的問題。 ### 最后 實際開發時,可以一開始 1 個 Repository 對應 1 個 Model,但是也不必太過執著于 1 個 Repository,一定要對應 1 個 Model,可將 Repository 視為邏輯上的數據庫邏輯類別即可,可以橫跨多個Model處理,也可以 1 個 Model 拆成多個 Repository,視情況而定。 Repository 使得數據庫邏輯從 Controller 或 Model 中解放,不僅更容易維護、更容易拓展、更容易重復使用,也更容易測試。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看