1. 程式人生 > >repository 上手 « 關於網路那些事...

repository 上手 « 關於網路那些事...

安裝

composer require prettus/l5-repository

設定 ServiceProvider

如果是 >= laravel5.5 ,ServiceProvider 會自動設定好

其他版本要在 config/app.php 增加

'providers' => [
    ...
    Prettus\Repository\Providers\RepositoryServiceProvider::class,
],

發布設定 設定完成多出一個設定檔: /config/repository.php

php artisan vendor:publish --provider "Prettus\Repository\Providers\RepositoryServiceProvider"

手動註冊 RepositoryServiceProvider

在一開始,要先手動在 app/Providers/[email protected] 新增 RepositoryServiceProvider

$this->app->register(RepositoryServiceProvider::class);

檢查

可以透過查詢 artisan 瞭解目前已經新增了哪些功能,用法會陸續說明

php artisan

簡介

  • entity

即 Model, 為了避免與原有Laravel架構混淆,特別用 Entitys 來做區隔,在 Entity 只負責接資料表

  • repository

只針對單一 Entity,處理一個資料表的行為

Model --->  Repository --...-> Controller
  • Criteria

如果有些 Repository 查詢條件經常使用到,可以將查詢的方法放在 Criteria,重複使用

他使用的邏輯,偏向於,在原有Repository 再疊加 Criteria 規則

在 l5-repository 架構並沒有分出 Service 這層來處理商業邏輯,

因此,關於多個 Repository 組成的商業邏輯,也可放在 Criteria 裡面處理即可

MOdel ---> Repository |
MOdel ---> Repository | ---> Criteria --..-> Controller
MOdel ---> Repository |
  • Presenter 我們常常需要將資料庫紀錄的內容進行轉換,例如,性別會用 1, 0 的方式紀錄,在輸出給使用者之前,會轉換成 男, 女 針對 Controller 從 Repository或 Service 取得結果,返回給 View 之前,有些資料需要經過格式轉換,就會在 Presenter 處理
Model --->  Repository --...-> Controller -> (Presenter) -> View

MOdel ---> Repository |
MOdel ---> Repository | ---> Service --..-> Controller -> (Presenter) -> View
MOdel ---> Repository |
  • transform

有時,在同一個 Repository or Service ,我們只希望丟出少數的資料 例如,使用者只需要返回name 與 email ,這時就能透過 transform 處理

Model --->  Repository --...-> Controller -> (transform) -> Response

MOdel ---> Repository |
MOdel ---> Repository | ---> Service --..-> Controller -> (transform) -> Response
MOdel ---> Repository |
  • Validator 驗證皆放置在這裡面處理,預設會自動生成新增及更新的驗證

建立好基本 migration

接下來會以 members 來進行範例說明, 這裡,我們建立一個 members migration 並且包含 name 及 email 欄位

artisan make:migration create_members_table
<?php ...
        Schema::create('members', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->softDeletes();
            $table->timestamps();
        });

執行 migrate

php artisan migrate

建立 Model

在 l5-repository 為了避免混淆,會將 Model 以 Entitys 方式管理

php artisan make:entity 名稱

//例如

php artisan make:entity members

在建立過程中,會自動詢問是否要同步建立 Presenter, Transformer, Validator, Controller

php artisan make:entity Members

 Would you like to create a Presenter? [y|N] (yes/no) [no]:
 > yes

App\Transformers\MembersTransformerPresenter created successfully.

 Would you like to create a Transformer? [y|N] (yes/no) [no]:
 > yes

Transformer created successfully.

 Would you like to create a Validator? [y|N] (yes/no) [no]:
 > yes

Validator created successfully.

 Would you like to create a Controller? [y|N] (yes/no) [no]:
 > yes

透過自動新增的好處是,會自動在 app/Providers/[email protected] 新增 binding

這裡 binging 的用意是,在某些地方會引用 repository,出問題時會容易混淆,因此這裡會透過一個 Interface 隔開

$this->app->bind(\App\Repositories\MembersRepository::class, \App\Repositories\MembersRepositoryEloquent::class);

Controller

透過 make:entity 可以自行決定要產生哪些功能,其中包括了 Controller

在預設生成的 Controller 裡麵包含了 index, store, show, edit , update, destroy

  • index 返回所有資料
  • store 儲存一筆資料
  • show 顯示指定id資料
  • update 更新資料
  • destroy 刪除指定id資料
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use Prettus\Validator\Contracts\ValidatorInterface;
use Prettus\Validator\Exceptions\ValidatorException;
use App\Http\Requests\MembersCreateRequest;
use App\Http\Requests\MembersUpdateRequest;
use App\Repositories\MembersRepository;
use App\Validators\MembersValidator;

/**
 * Class MembersController.
 *
 * @package namespace App\Http\Controllers;
 */
class MembersController extends Controller
{
    /**
     * @var MembersRepository
     */
    protected $repository;

    /**
     * @var MembersValidator
     */
    protected $validator;

    /**
     * MembersController constructor.
     *
     * @param MembersRepository $repository
     * @param MembersValidator $validator
     */
    public function __construct(MembersRepository $repository, MembersValidator $validator)
    {
        $this->repository = $repository;
        $this->validator  = $validator;
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
        $members = $this->repository->all();

        $myTest = $this->repository->myCustomRepo();

        if (request()->wantsJson()) {
            return response()->json([
                'data' => $members,
                'test' => $myTest
            ]);
        }

        return view('members.index', compact('members'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  MembersCreateRequest $request
     *
     * @return \Illuminate\Http\Response
     *
     * @throws \Prettus\Validator\Exceptions\ValidatorException
     */
    public function store(MembersCreateRequest $request)
    {
        try {
            $this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_CREATE);

            $member = $this->repository->create($request->all());

            $response = [
                'message' => 'Members created.',
                'data'    => $member->toArray(),
            ];

            return response()->json($response);
        } catch (ValidatorException $e) {
            return response()->json([
                'error'   => true,
                'message' => $e->getMessageBag()
            ]);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $member = $this->repository->find($id);

        if (request()->wantsJson()) {
            return response()->json([
                'data' => $member,
            ]);
        }

        return view('members.show', compact('member'));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $member = $this->repository->find($id);

        return view('members.edit', compact('member'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  MembersUpdateRequest $request
     * @param  string            $id
     *
     * @return Response
     *
     * @throws \Prettus\Validator\Exceptions\ValidatorException
     */
    public function update(MembersUpdateRequest $request, $id)
    {
        try {
            $this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_UPDATE);

            $member = $this->repository->update($request->all(), $id);

            $response = [
                'message' => 'Members updated.',
                'data'    => $member->toArray(),
            ];

            return response()->json($response);
        } catch (ValidatorException $e) {
            return response()->json([
                'error'   => true,
                'message' => $e->getMessageBag()
            ]);
        }
    }


    /**
     * Remove the specified resource from storage.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $deleted = $this->repository->delete($id);
        return response()->json([
            'message' => 'Members deleted.',
            'deleted' => $deleted,
        ]);
    }
}

許可權檢查

比較特別的是,store 與 update 在使用時,預設要經過 auth() 流程 可以在 app/Requests/ 看到這兩個對應的 Request 處理,也可以寫入 Request 的檢查規則 MembersCreateRequest.php MembersUpdateeRequest.php

如果在 store, update 不想使用 auth,只需要在這兩隻檔案中 authorize() return true 即可

Route

可以在 api.php 設定對應的 route

<?php  ...
Route::prefix('members')->group(function () {
    Route::get('get', '[email protected]');
    Route::get('show/{id}', '[email protected]');
    Route::post('store', '[email protected]');
    Route::post('update/{id}', '[email protected]');
    Route::post('destroy/{id}', '[email protected]');
});

Criteria

建立 Criteria

php artisan make:criteria Mytest

會自動在 app/Criteria/ 建立 MytestCriterias.php

可以直接在 apply 裡面新增你想要的查詢規則

<?php ..
    public function apply($model, RepositoryInterface $repository)
    {
        return $model->where('id', 2);
    }

接著就能在 Controller 使用,原則上他是以累加方式來套上這些規則

    $this->repository->pushCriteria(new MytestCriteria());
    $members = $this->repository->all();

RequestCriteria

l5-repository 提供一個預設的 RequestCriteria

裡面提供了一整套查詢規則,相當方便

首先要先在 MembersRepositoryEloquent 新增可以被搜尋的欄位

並且可以在 boot 直接引用 RequestCriteria (這個在自動生成時,就會直接幫你加上)

<?php
class MembersRepositoryEloquent extends BaseRepository implements MembersRepository
{
    protected $fieldSearchable = [
    'name',
    'email'
    ];

        ...
    /**
     * Boot up the repository, pushing criteria
     */
    public function boot()
    {
        $this->pushCriteria(app(RequestCriteria::class));
    }

也可以在 controller 裡面手動匯入

<?php
...
        $this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
        $members = $this->repository->all();

接著就可以參考下方規則,進行搜尋

http://prettus.local/users?search=John%20Doe

or

http://prettus.local/users?search=John&searchFields=name:like

or

http://prettus.local/[email protected]&searchFields=email:=

or

http://prettus.local/users?search=name:John Doe;email:[email protected]

or

http://prettus.local/users?search=name:John;email:[email protected]&searchFields=name:like;email:=

詳細內容可以參考官方檔案

如果你喜歡我們的文章內容,請在這裡按個讚