為了提高程式碼的 重用率
,我只在基礎類上寫了,每個模型所必須要的操作,CURD 在到具體的 Repository 上去做實現:
<?php
namespace App\Repositories;
use App\Exceptions\GeneralException;
/**
* 抽象的 Repository 類
*
* @package App\Repositories
*/
abstract class BaseRepository
{
/**
* 根據主鍵查詢
*
* @param $id
* @param $trashed
* @return mixed
*/
public function find($id, $trashed = false)
{
if ($trashed) {
return $this->query()->withTrashed()->findOrFail($id);
}
return $this->query()->findOrFail($id);
}
/**
* 查詢資源集合
*
* @param bool $query_string
* @param bool $keys
* @param int $paginate
* @param bool $trashed
* @return mixed
* @throws GeneralException
*/
public function getAll($query_string = false, $keys = false, $paginate = 15, $trashed = false)
{
try {
$query = $this->query();
if ($query_string && is_array($keys)) {
foreach ($keys as $key => $value) {
$query->orWhere($value, 'like', "%$query_string%");
}
}
if ($trashed) {
$query->withTrashed();
}
return $query->paginate($paginate);
} catch (Exception $exception) {
throw new GeneralException('未知錯誤,導致查詢失敗', 500);
}
}
/**
* 建立查詢構造器
*
* @return mixed
*/
public function query()
{
return call_user_func(static::MODEL.'::query');
}
/**
* 序列化模型例項
*
* @param array $attributes
* @return mixed
*/
abstract protected function serialization(array $attributes);
}
<?php
namespace App\Repositories;
use App\Models\Company;
use App\Exceptions\GeneralException;
/**
* Class CompanyRepository
*
* @author George <jinrenjie@me.com>
* @package App\Repositories
*/
class CompanyRepository extends BaseRepository
{
/**
* 定義資料模型
*/
const MODEL = Company::class;
/**
* 建立企業資訊
*
* @param array $attributes
* @return Company
* @throws GeneralException
*/
public function store(array $attributes)
{
$compnay = $this->serialization($attributes);
try {
$compnay->save();
return $compnay;
} catch (Exception $exception) {
throw new GeneralException('建立企業資訊失敗');
}
}
/**
* 更新企業資訊
*
* @param Company $company
* @param array $attributes
* @return Company
* @throws GeneralException
*/
public function update(Company $company, array $attributes)
{
if (is_array($attributes)) {
foreach ($attributes as $key => $value) {
$company->$key = $value;
}
$company->saveOrFail();
return $company;
}
throw new GeneralException('要更新的屬性必須是陣列');
}
/**
* 刪除企業資訊
*
* @param Company $company
* @param bool $force
* @return bool|null
* @throws GeneralException
*/
public function delete(Company $company, $force = false)
{
try {
return $force ? $company->forceDelete() : $company->delete();
} catch (Exception $exception) {
throw new GeneralException('刪除企業資訊失敗');
}
}
/**
* 序列化使用者輸入
*
* @param array $attributes
* @return Company
*/
protected function serialization(array $attributes)
{
$company = self::MODEL;
$company = new $company();
$company->title = $attributes['title'];
$company->introduction = array_get($attributes, 'introduction', null);
$company->url = array_get($attributes, 'url', null);
$company->logo = array_get($attributes, 'logo', null);
$company->address = array_get($attributes, 'address', null);
$company->contact = array_get($attributes, 'contact', null);
return $company;
}
}
這一層只處理資料的 CURD,並返回對應的操作結果,除了丟擲異常勁量不涉及響應和請求……這樣Controller 裡只要呼叫方法而無需考慮異常處理。
<?php
namespace App\Http\Controllers\Interfaces;
use App\Models\Company;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\CompanyRepository;
use App\Extensions\Library\MaterialHandling;
use App\Http\Requests\Interfaces\Company\DeleteRequest;
use App\Http\Requests\Interfaces\Company\UpdateRequest;
use App\Http\Requests\Interfaces\Company\CreateRequest;
use App\Http\Requests\Interfaces\Company\ChangeLogoRequest;
use App\Http\Requests\Interfaces\Company\QueryResourceRequest;
use App\Http\Requests\Interfaces\Company\QueryCollectionRequest;
/**
* Class CompanyController
*
* @package App\Http\Controllers\Interfaces\User
*/
class CompanyController extends Controller
{
use MaterialHandling;
/**
* 定義儲存 CompanyRepository 的例項
* @var CompanyRepository
*/
protected $companyRepository;
/**
* CompanyController constructor.
* @param $companyRepository
*/
public function __construct(CompanyRepository $companyRepository)
{
$this->companyRepository = $companyRepository;
}
/**
* 獲取企業資訊集合
*
* @param QueryCollectionRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(QueryCollectionRequest $request)
{
//獲取分頁大小
$paginate = $request->get('paginate', 15);
//獲取模糊查詢字串
$query_string = $request->get('query_string', false);
//獲取是否顯示軟刪除的資料
$trashed = $request->get('trashed', false);
//定義需要模糊查詢的欄位
$keys = [
'title',
'introduction',
'address'
];
$collections = $this->companyRepository
->getAll($query_string, $keys, $paginate, $trashed);
return $this->success($collections);
}
/**
* 根據企業 ID 獲取企業資訊
*
* @param Company $company
* @param QueryResourceRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function show(Company $company, QueryResourceRequest $request)
{
return $this->success($company);
}
/**
* 建立企業資訊
*
* @param CreateRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function create(CreateRequest $request)
{
$attributes = $request->all();
$company = $this->companyRepository->store($attributes);
return $this->created($company);
}
/**
* 更新企業資訊
*
* @param Company $company
* @param UpdateRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function update(Company $company, UpdateRequest $request)
{
$attributes = $request->all();
$company = $this->companyRepository->update($company, $attributes);
return $this->updated($company);
}
/**
* 刪除企業資訊
*
* @param Company $company
* @param DeleteRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function delete(Company $company, DeleteRequest $request)
{
$this->companyRepository->delete($company);
return $this->deleted();
}
/**
* 更改企業 Logo
*
* @param Company $company
* @param ChangeLogoRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function changeLogo(Company $company, ChangeLogoRequest $request)
{
$file = $request->file('logo');
$path = $this->store($file, $request->user());
$result = $this->companyRepository->update($company, ['logo' => $path]);
return $this->updated($result);
}
}
控制器裡的自定義響應,我參照了@王舉 的文章:Laravel5.5+passport 放棄 dingo 開發 API 實戰,讓 API 開發更省心。
我還把 鑑權
和表單驗證及錯誤資訊
放到了 專門的 Request 裡面去處理這樣整體結構也更加清晰了,比如我的註冊請求:
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Http\FormRequest;
/**
* 使用者註冊請求
*
* @author George <jinrenjie@me.com>
* @package App\Http\Requests\Auth
*/
class RegisterRequest extends FormRequest
{
/**
* 定義授權規則
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* 定義驗證規則
*
* @return array
*/
public function rules()
{
return [
'username' => 'required|alpha_dash|min:6|max:16|unique:users',
'password' => 'required|confirmed|min:8|max:32',
'mobile' => 'required|min:11|max:11|unique:users',
];
}
/**
* 定義錯誤訊息
*
* @return array
*/
public function messages()
{
return [
'username.required' => '請填寫使用者名稱',
'username.alpha_dash' => '使用者名稱只能是字母、數字、及下劃線',
'username.min' => '使用者名稱不得少於6個字元',
'username.max' => '使用者名稱不得超過16個字元',
'username.unique' => '該使用者名稱稱已存在,請使用其他名稱註冊',
'password.required' => '請填寫密碼',
'password.confirmed' => '兩次填寫的密碼不一致',
'password.min' => '密碼最少8個字元',
'password.max' => '密碼最多32個字元',
'mobile.required' => '請填寫您的手機號碼',
'mobile.min' => '您輸入的號碼不滿11位',
'mobile.max' => '號碼不得超過11位',
'mobile.unique' => '該手機號碼已被註冊',
];
}
/**
* 驗證使用者輸入的驗證碼是否正確
*
* @param $validator
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (Cache::get($this->get('mobile'), false) !== $this->get('verification')) {
$validator->errors()->add('verification', '你輸入的驗證碼有誤');
} else {
Cache::forget($this->get('mobile'));
}
});
}
}
當然缺點就是要增加很多程式碼量,但是對於團隊開發來說這樣也許比較規範吧……
如果你有更好的分離方法,歡迎一起討論,謝謝!
本作品採用《CC 協議》,轉載必須註明作者和本文連結