開源 [輪子] Laravel 專案架構擴充套件包

yourself發表於2018-04-11

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 協議》,轉載必須註明作者和本文連結

相關文章