laravel框架開發專案架構擴充套件包
前言
開發專案過程中由於分層比較多,便於後期維護,所以導致每次都需要手動建立檔案和方法。 為了省略這些麻煩的操作,所以和小夥伴開發了一個架構擴充套件包,後面這些重複的機械操作可以用命令進行替代, 快速的進入到開發階段。 如果覺得不錯希望大家給個star,請大家幫忙多提意見,想參與開源的維護請聯絡我們。
功能
專案架構分層,程式碼生成器,拆分職責降低耦合。借鑑開源專案
擴充套件包地址:phpno1-architecture
目錄
安裝
使用要求
- laravel >= 5.5
- php >= 7.1
composer
執行以下命令獲取包的最新版本:
composer require phpno1/architecture
laravel
生成配置檔案
php artisan vendor:publish --provider "Phpno1\Architecture\Providers\ArchitectureServiceProvider"
註冊到服務容器
說明:用命令生成倉儲檔案時(phpno1:entity || phpno1:repository),會自動生成ArchitectureServiceProvider檔案。
# 在config/app.php中
'providers' => [
// ......
App\Providers\ArchitectureServiceProvider::class,
];
配置
//architecture.php
'pagination' => [//預設分頁數量
'limit' => 20
],
'cache' => [//快取時間
'enabled' => true,
'minutes' => 10,
],
'order' => [//排序欄位
'o',
],
'generator' => [//程式碼生成器名稱空間
'root_namespace' => 'App\\',
'namespace' => [
'controller' => 'Backend',
'repository_eloquent' => 'Repository\\Eloquent',
'repository' => 'Repository\\Contracts',
'criteria' => 'Architecture\\Criterias',
'provider' => 'Providers\\ArchitectureServiceProvider',
'service' => 'Services',
'model' => 'Models',
'response' => 'Http\\Responses',
'filter' => 'Repository\\Filters'
]
]
命令
說明:使用命令建立倉儲檔案時(phpno1:entity和phpno1:repository),會自動繫結介面與實現類關係。
生成組合配置
//@params {name} 生成檔名稱
//@params {--resource} 生成資源方法(參照laravel控制器 資源控制器)
php artisan phpno1:entity {name} {--resource}
生成控制器
//@params {name} 控制器名稱
//@params {--resource} 生成資源方法(參照laravel控制器 資源控制器)
php artisan phpno1:controller {name} {--resource}
生成業務處理類
@params {name} 檔名稱
@params {--resource} 生成資源方法
php artisan phpno1:service {name} {--resource}
生成擴充套件全侷限制類
@params {name} 限制類名稱
php artisan phpno1:criteria {name}
生成過濾類
@params {name} 過濾類名稱
@params {--prefix=} 名稱空間
@params {--sort} 排序方法
php artisan phpno1:filter {name} {--prefix=} {--sort}
生成模型類
@params {name} 模型名稱
php artisan phpno1:model {name}
生成伺服器提供者,用於介面繫結實體類
php artisan phpno1:provider
生成倉庫類
@params {name} 倉庫名稱
php artisan phpno1:repository {name}
生成校驗類
@params {name} 檔名稱
@params {--dir=} 生成目錄
php artisan phpno1:request {name} {--dir=}
生成響應類
@params {name} 檔名稱
@params {--dir=} 生成目錄
php artisan phpno1:response {name} {--dir=}
生成種子檔案
@params {name} 檔名稱
php artisan phpno1:seeder {name}
快速使用
1.執行以下命令:
php artisan phpno1:entity User --resource
生成檔案 (注:以下命令生成檔案路徑可以透過配置修改architecture.php)
- app\Http\Controllers\Backend\UserController
- app\Services\UserService
- app\Repository\Eloquent\UserRepositoryEloquent
- app\Repository\Contracts\UserRepository
- app\Http\Requests\User\StoreRequest
\UpdateRequest - app\Http\Responses\User\IndexResponse
\ShowResponse - app\Models\UserModel
- database\factories\UserFactory
- database\migrations\UserTable
- database\seeds\UserSeeder
2.修改程式碼
1).控制器
<?php
namespace App\Http\Controllers\Backend;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Services\UserService;
use App\Http\Responses\User\IndexResponse;
class UserController extends Controller
{
private $user;
public function __construct(UserService $userService)
{
$this->user=$userService;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
$result=$this->user->getUsers();//這裡呼叫是業務層資源方法
return new IndexResponse($result);
}
2).響應(資料對映)
<?php
namespace App\Http\Responses\User;
use Illuminate\Contracts\Support\Responsable;
use App\Traits\ResponseTrait;
class UserIndexResponse implements Responsable
{
use ResponseTrait;
protected $result;
public function __construct($result)
{
$this->result = $result;
}
public function toResponse($request)
{
$data = $this->transform();
return $data;
}
protected function transform()
{
//分頁資料例子
$this->result->getCollection()->transform(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
];
});
//集合資料例子
$this->result->transform(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
];
});
return $this->result;
}
}
方法介紹
- Contracts : 倉儲業務抽象介面。
- Criterias : 全域性通用業務抽取以及準對某一類業務的Scope。
- Eloquent : 倉儲業務具體實現。
- Exceptions : 倉儲異常處理。
- Filters : 根據引數自動過濾和排序。
- Traits : Trait封裝
Phpno1\Repository\Contracts\IRepository;
- function entity();
- function all();
- function find(int $id);
- function first();
- function count();
- function findWhere(...$condition);
- function findWhereFirst(...$condition);
- function findWhereCount(...$condition);
- function paginate(int $perPage = 10);
- function create(array $properties);
- function update(int $id, array $properties);
- function delete(int $id);
- function withCriteria(...$criteria);
- function toEntity();
- function toRepository(Builder $entity);
Phpno1\Repository\Eloquent;
// 獲取所有記錄
$this->repository->all();
// 根據id查詢單條記錄
$this->repository->find(int $id);
// 獲取第一條記錄
$this->repository->first();
// 獲取總記錄數
$this->repository->count();
// 根據一個或多個 AND WHERE 條件查詢。得到一個結果集
// 單個條件寫法:->findWhere('name', 'tome');
// 多個條件寫法:->findWhere(['name', 'tome'], ['age', '>', 20]);
$this->repository->findWhere(...$condition);
// 根據一個或多個 AND WHERE 條件查詢。得到一條記錄。
$this->repository->findWhereFirst(...$condition);
// 根據一個或多個 AND WHERE 條件獲取記錄數
$this->repository->findWhereCount(...$condition);
// 獲取分頁資料
$this->repository->paginate(int $perPage = 10);
// 插入記錄
$this->repository->create(array $properties);
// 修改記錄
$this->repository->update(int $id, array $properties);
// 根據id刪除
$this->repository->delete(int $id);
// 用於載入預設的自定義標準操作 (Criterias目錄中的類),後面會詳細介紹
$this->repository->withCriteria(...$criteria);
// 把Repository轉換成Model或者Build物件,後續可以使用框架提供的ORM操作
$this->repository->toEntity();
// 把Build物件轉回Repository物件
$this->repository->toRepository(Builder $entity);
初始化載入
//請重寫boot方法 不要重寫構造方法
function boot()
{
}
限制條件
編寫Criteria類
namespace App\Repositories\Criterias;
class ByCreateTime implements ICriteria
{
public function apply($entity)
{
return $entity->latest();
}
}
使用Criteria類
public function getUserListByCreateTime()
{
return $this->repository
->withCriteria(
new ByCreateTime()
// more...
)->paginate();
}
過濾條件
在Repository中配置要過濾和排序的對映欄位
class UserRepositoryEloquent extends AbstractRepository implements UserRepository
{
// 設定過濾對映
protected $filters = [
'email' => EmailFilter::class,
'name' => NameFilter::class,
];
public function entity()
{
return User::class;
}
// 過濾和排序在withCriteria中新增過濾和排序操作類FilterRequest
public function findUserListByPage()
{
return $this->withCriteria(
new FilterRequest($this->filters)
)->paginate();
}
// something...
}
編寫要過濾的業務
namespace App\Repositories\Filters\User;
use App\Repositories\Filters\AbstractFilter;
class NameFilter extends AbstractFilter
{
// 過濾操作
public function filter($entity, $value)
{
return $entity->where('name', $value);
}
}
編寫要排序的業務
注意:如果你需要欄位排序,首先需要在生成的配置檔案architecture.php中定義你需要的排序接收引數
在過濾類中必須實現介面 "IOrder"!!!
namespace App\Repositories\Filters\Admin;
use App\Repositories\Filters\{
AbstractFilter,
IOrder
};
// 需要排序,必須實現排序介面
class NameFilter extends AbstractFilter implements IOrder
{
// 過濾操作
public function filter($entity, $value)
{
return $entity->where('name', $value);
}
// 排序操作
public function order($entity, $direction)
{
return $entity->orderBy('name', $this->resolveOrderDirection($direction));
}
}
傳遞引數進行過濾操作
// 過濾name和email
http://www.phpno1.com/user?name=Anthony&email=king19800105@163.com
// 過濾和排序組合。引數"o"表示排序方式。引數"orderable"表示要排序的欄位
http://www.phpno1.com/user?name=Anthony&email=king19800105@163.com&o=desc&orderable=name
scope
這裡倉庫層中的scope方法是相容laravel模型的scope方法呼叫
注意如果呼叫scope方法請注意,必須先呼叫再執行withCriteria進行過濾
//模型中定義
class User extends Model
{
public function scopeUserFields()
{
return $this->select(['id','name','email']);
}
}
//倉庫中呼叫
class UserRepositoryEloquent extends AbstractRepository implements UserRepository
{
public function getUsers(int $perPage=0)
{
return $this->userFields()->withCriteria(
new FilterRequest($this->filters)
)->paginate($perPage);
}
}
自定義
//當Repository提供的method無法滿足業務
public function do()
{
// 使用toEntity() 轉換回Model或Build物件
return $this->repository
->toEntity()
->where(...)
->orWhere(...)
->when(...)
->get(...);
}
快取
使用CacheGenerate的trait特性
用途:當使用redis或memcahce做快取時,方便做資料快取操作。當然,您也可以使用Laravel框架提供的Cache。
public function getUserList()
{
// 引數1:快取的key值
// 快取中有資料則從快取中取,沒有資料則從資料庫取一次放入快取。
$this->getOrCache('getUserList', function () {
return $this->paginate();
});
}
注意事項
- 建議檔案生成都使用命令來操作。
- 過濾必須要繼承AbstractFilter (有特殊需求的可以實現IFilter介面) ,過濾必須實現IOrder介面。
- 過濾和排序都是可選的。
- 透過重寫過濾中的mappings()方法來改變資料庫欄位和過濾使用的引數對映關係。
- 透過重寫AbstractFilter中的resolveOrderDirection()方法來改變排序方式的對映關係。
本作品採用《CC 協議》,轉載必須註明作者和本文連結