stevema / laravel-restful
laravel 中 每个restful接口都需要写一堆方法。我想写一个公共的类 然后继承它 只需要少少的配置就可以输出相关的API接口
v1.0.0
2023-11-24 08:43 UTC
This package is not auto-updated.
Last update: 2025-01-03 14:05:35 UTC
README
介绍
laravel 中 每个restful接口都需要写一堆方法。我想写一个公共的类 然后继承它 只需要少少的配置就可以输出相关的API接口
安装教程
# 安装
$ composer require stevema/laravel-restful
使用说明
# 比如我现在想加个配置相关的表并输出对应的restful接口
# 1.命令行执行代码
$ php artisan make:restful api/common/make_test -m
# 其中 api/common 是命名空间 make_test 是想要的模型名称
# 可带参数 -i 生成带说明的文件 -m 生成数据迁移文件 -s 生成数据填充文件
# 执行后输出
INFO Migration [database/migrations/2023_08_17_041228_create_make_tests_table.php] created successfully.
INFO model [app/Models/api/common/MakeTest.php] created successfully.
INFO resource [app/Http/Resources/api/common/MakeTestResource.php] created successfully.
INFO request [app/Http/Requests/api/common/MakeTestRequest.php] created successfully.
INFO filter [app/Http/Filters/api/common/MakeTestFilter.php] created successfully.
INFO permission [app/Http/Permissions/api/common/MakeTestPermission.php] created successfully.
INFO controler [app/Http/Controllers/api/common/MakeTestController.php] created successfully.
# 这个时候已经生成了 数据库迁移文件(Migration) 模型(Model) 解释器(Resource) 验证器(Request) 过滤器(Filter) 权限验证(Permission) 控制器(Controller)
# 2. 修改migration迁移文件 修改up方法 具体文件看生成的路径
public function up(): void
{
Schema::create('make_tests', function (Blueprint $table) {
$table->comment("测试restful表");
$table->id();
$table->string('field1', 200)->nullable()->comment('field1字段');
$table->string('field2', 200)->default("default")->comment('field2字段');
$table->integer('field3')->default(0)->comment('field3字段');
$table->boolean('is_del')->default(0)->comment('是否删除[0=否,1=是]');
$table->timestamps();
});
}
# 3. 执行数据库迁移文件
$ php artisan migrate
# 这个时候生成表成功了 当然也可以跳过这一步 手动去创建表
CREATE TABLE `make_tests` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`field1` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'field1字段',
`field2` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'default' COMMENT 'field2字段',
`field3` int(11) NOT NULL DEFAULT '0' COMMENT 'field3字段',
`is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除[0=否,1=是]',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='测试restful表';
# 4. 配置模型(Model)文件 把$fillable=[]配置上 具体文件看生成的路径
namespace App\Models\api\common;
use Stevema\Restful\RestfulModel;
class MakeTest extends RestfulModel
{
protected $table="make_tests";
/**
* 批量赋值的字段
* @var string[]
*/
protected $fillable = ['field1','field2','field3','is_del'];
}
# 5.添加路由 路由文件就不放路径了
Route::apiResource('maketest', \App\Http\Controllers\api\common\MakeTestController::class);
# 这个时候 php artisan route:list 就可以查看路由了
GET|HEAD api/maketest ...................... maketest.index › api\common\MakeTestController@index
POST api/maketest ...................... maketest.store › api\common\MakeTestController@store
GET|HEAD api/maketest/{maketest} ........... maketest.show › api\common\MakeTestController@show
PUT|PATCH api/maketest/{maketest} ........... maketest.update › api\common\MakeTestController@update
DELETE api/maketest/{maketest} ........... maketest.destroy › api\common\MakeTestController@destroy
# 简单的restful接口就已经完成了 更多的配置信息请向下看
目录说明
├─ src
│ ├─ Consoles # 命令目录
│ │ └─ Commands # 命令目录
│ │ └─ Stubs # 命令生成文件模版目录
│ ├─ Traits # use 目录
│ │ └─ Destroy.php # 删除方法
│ │ └─ ForceDelete.php # 真实删除方法
│ │ └─ Index.php # 列表方法
│ │ └─ Restore.php # 软删除恢复方法
│ │ └─ Show.php # 详情方法
│ │ └─ SoftDeletes.php # 软删除-模型使用
│ │ └─ SoftDeletingScope.php # 软删除-模型使用
│ │ └─ Store.php # 创建方法
│ │ └─ Update.php # 修改方法
│ └─ PermissionException.php # permission异常
│ └─ RestfulCache.php # restful缓存
│ └─ RestfulController.php # restful控制器
│ └─ RestfulException.php # restful异常
│ └─ RestfulFilter.php # restful过滤器
│ └─ RestfulFilterResource.php # restful过滤解释器
│ └─ RestfulModel.php # restful模型
│ └─ RestfulPermission.php # restful权限验证
│ └─ RestfulProvider.php # restful服务提供者
│ └─ RestfulRequest.php # restful验证器
│ └─ RestfulResource.php # restful解释器
└─ composer.json # 配置
详细配置
控制器-Controller
#对于Controller来说 没什么需要改的 有新的接口直接加上然后写路由就行了
# 引入软删除之后 controller中就可以use Restore 和 ForceDelete了
namespace App\Http\Controllers\api\common;
Use Stevema\Restful\RestfulController;
Use Stevema\Restful\Traits\Index;
Use Stevema\Restful\Traits\Update;
Use Stevema\Restful\Traits\Store;
Use Stevema\Restful\Traits\Show;
Use Stevema\Restful\Traits\Destroy;
use Illuminate\Http\Request;
class MakeTestController extends RestfulController
{
use Index,Store,Update,Show,Destroy;
/**
* 路由绑定的参数名称
* ROUTE_KEY 模型在路由中应当保持一致 然后就是应当是Model的小写
* 比如 Route::get('/smorders/{smorder}', function(){}) -> 对应的模型应该是 SmOrder
* ROUTE_KEYMAP 关系模型时用到的
* 比如 Route::get('/smorders/{smorder}/smskus/{smsku}', function(){})
* SmOrder 和 SmSku 可以是一对一 也可以是一对多
* 这样就需要 ROUTE_KEY来确认接收哪个参数了
* ROUTE_KEYMAP 来对应相关的值 -> 在smsku 中 如果smorder关联的是 order_id
* ROUTE_KEYMAP = ['smorder' => 'order_id] 这样来与smorder对应
*
* 比如 Route::get('/smorders/{smorder}', function(){}) -> 对应的模型应该是 SmOrder
* 只有一个模型的时候不需要 ROUTE_KEY 和 ROUTE_KEYMAP
*
* @var string
*/
protected const ROUTE_KEY = null;
protected const ROUTE_KEYMAP = [];
/**
* 过滤插件 列表传过来的参数需要一些方法来走到模型里面
* 请继承 Stevema\Restful\Filters\RestfulFilter
* 可以没有 但是不能乱搞
*/
protected const FILTERS = \App\Http\Filters\api\common\MakeTestFilter::class;
/**
* 模型 对应的表
* 应当继承 Illuminate\Database\Eloquent\Model
*/
protected const MODEL = \App\Models\api\common\MakeTest::class;
/**
* 模型解释器 -> 模型查出来的数据 有些不想放出去的 就可以使用这个来处理
* 应当继承 Illuminate\Http\Resources\Json\JsonResource
*/
protected const RESOURCE = \App\Http\Resources\api\common\MakeTestResource::class;
/**
* request -> post put patch 使用到的表单验证 - 表单验证还包含权限验证
* 应当继承 Stevema\Restful\RestfulRequest 并且定义了 scene=>[store, update]
* 继承其他的验证也可以
*/
protected const REQUEST = \App\Http\Requests\api\common\MakeTestRequest::class;
/**
* 权限验证
*/
protected const PERMISSION = \App\Http\Permissions\api\common\MakeTestPermission::class;
}
# 若是我提供的方法不满足您的使用 可以定义方法直接覆盖
# 或者 把 use 去掉就行了
模型-Model-主要是软删除
# 配置模型(Model)文件 把$fillable=[]配置上 具体文件看生成的路径
# 因为我有设置 is_del 字段 所以把软删除加上
namespace App\Models\api\common;
use Stevema\Restful\RestfulModel;
use Stevema\Restful\Traits\SoftDeletes;
class MakeTest extends RestfulModel
{
use SoftDeletes;
protected $table="make_tests";
/**
* 批量赋值的字段
* @var string[]
*/
protected $fillable = ['field1','field2','field3','is_del'];
/**
* 设置软删除
*/
protected function getSoftDeleteSetting()
{
return [
"columnName" => 'is_del',
"columnType" => 'int',
"defaultValue" => 0,
"deletedValue" => 1,
];
}
}
# 引入 Stevema\Restful\Traits\SoftDeletes
# 并且设置 protected function getSoftDeleteSetting(){}
# 如果想使用laravel给出的软删除 不设置这个也可以
# 如果有设置 请把软删除的字段 放入 $fillable 中
过滤器-Filter
# 过滤器目前只给Index方法使用 - 列表才需要过滤器 详情都有主键来处理了
namespace App\Http\Filters\api\common;
use Stevema\Restful\RestfulFilter;
class MakeTestFilter extends RestfulFilter{
/**
* 默认排序规则 多个中间加逗号 比如 "-type,-id"
*/
protected const DEFAULT_ORDERING = '-id';
/**
* 允许的检索字段 keys 空则不限制 所有的参数都可以参与过滤
* 注意这里只有id 没有前面的-号
*/
protected const ACCEPT_ORDERINGS = ["id",];
/**
* 允许的检索字段 keys 空则不限制 所有的参数都可以参与过滤
*/
protected const ACCEPT_FILTER_KEYS = [];
/**
* 分页用到的页码参数key
*/
protected const KEY_PAGE = 'page';
/**
* 分页用到的每页显示条数参数key
*/
protected const KEY_SIZE = 'size';
/**
* 分页用到的 cursor 参数key
*/
protected const KEY_CURSOR = 'cursor';
/**
* 默认页数
*/
protected const DEFAULT_PAGE = 1;
/**
* 默认条数
*/
protected const DEFAULT_SIZE = 15;
/**
* 排序用到的参数key
*/
protected const KEY_ORDERING = 'ordering';
/**
* 分页方法 noPaginate 无分页 、 paginate 默认分页 、 simplePaginate 简单分页 、 cursorPaginate cursor分页
*/
protected const PAGINATOR = 'paginate';
/**
* 资源解释器 - 返回之前重新编辑一下输出的数组
* 默认提供一个 可以用 也可以不用
* \Stevema\Restful\RestfulFilterResource::class
*/
protected const FILTER_RESOURCE = null;
/**
* 检索 自定义字段 比如 name字段 方法名是 name_filter
* 可以获取 Builder 后执行操作
* $queryset = $this->getQuerySet();
* @param $key 字段名
* @param $value 值
* @return void
*/
// public function name_filter($key, $value){
// $query = $this->getQuery();
// $query->where($key, 'like', "%{$value}%");
// }
}
# 定义 允许排序的字段 ACCEPT_ORDERINGS=['id','field2'];
# 然后 ording=-id 就可以定义排序 => KEY_ORDERING="ording"
# 定义 允许过滤的字段 ACCEPT_FILTER_KEYS=['field2','field3'];
# 然后 当传入参数 field2=111 的时候就会执行 $query->where('field2', '=', 111);
# 当然你也可以自定义执行语句
public function field2_filter($key, $value){
$query = $this->getQuery();
$query->where($key, 'like', "%{$value}%");
}
# noPaginate 无分页 、 paginate 默认分页 、 simplePaginate 简单分页 、 cursorPaginate cursor分页
# 3种分页方法和无分页方法 PAGINATOR = 'paginate' 默认 paginate 默认分页
# 不同的方法会输出不同的格式 可以通过定义资源解释器来重新解释输出的格式
# 默认是null 不想自己写的可以使用 Stevema\Restful\Filters\RestfulFilterResource::class 来处理
protected const FILTER_RESOURCE = \Stevema\Restful\Filters\RestfulFilterResource::class;
验证器-Request
# 验证器和laravel提供的表单验证没什么区别- 我只是添加了scene
# 对不同的scene 可以过滤不同的参数 实现一个验证器对应一个Controller
# 注意 patch 方式修改的时候 required 会改成 sometimes 来实现部分修改
# 当然你可以自定义表单验证
namespace App\Http\Requests\api\common;
use Stevema\Restful\RestfulRequest;
use Illuminate\Contracts\Validation\Validator;
class MakeTestRequest extends RestfulRequest
{
// 第一个失败后停止
protected $stopOnFirstFailure = false;
/**
* 权限验证 false 会抛出权限异常中止请求
* @return bool
*/
public function authorize(): bool
{
return True;
// $comment = Comment::find($this->route('comment'));
// return $comment && $this->user()->can('update', $comment);
//路由模型绑定 - -
// return $this->user()->can('update', $this->comment);
}
/**
* 规则列表
* [
* 'field1' => ['required','string','between:2,50'],
* 'field2' => ['required','string','between:2,20'],
* 'field3' => ['required','string','between:2,20'],
* 'field4' => [],
* ]
*/
public function rules(): array
{
return [
'field1' => ['required','string','between:2,50'],
'field2' => ['required','string','between:2,20'],
'field3' => ['required','int'],
];
}
/**
* 场景
* [
* 'store' => ['field1', 'field2','field3','field4'],
* 'update' =>['field1', 'field2','field3','field4'],
* ]
* @var array[]
*/
public $scenes = [
'store' => ['field1', 'field2','field3'],
'update' => ['field1', 'field2','field3'],
];
/**
* 返回的提示
* @return string[]
*/
public function messages()
{
return [
// 'name.required' => ':attribute字段不能为空',
];
}
/**
* 字段的明明包 可以把上面的:attribute 替换
* @return string[]
*/
public function attributes()
{
return [
// 'name' => '姓名',
];
}
/**
* 准备验证数据。验证前数据处理
* 比如把user_id 从header中取出来放进去
*/
protected function prepareForValidation(): void
{
// var_dump("准备验证数据。验证前数据处理");
// $this->merge([
// 'slug' => Str::slug($this->slug),
// 'user_id' => Auth()->user['id']
// ]);
}
/**
* 配置验证实例。- 验证后数据处理前 可以添加错误信息-
* - - - 上面的规则总有一些是 不满足使用的
* somethingElseIsInvalid 并不存在这个方法 就是告诉你这里可以有一些错误
* @param Validator $validator
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator) {
// if ($this->somethingElseIsInvalid()) {
// $validator->errors()->add('field', 'Something is wrong with this field!');
// }
});
}
/**
* 验证后数据处理
* 有些数据是不想写入数据库的 比如 _token 等 就需要去掉
* 如果删除了这个 仔细看父的实现- 返回$scenes内定义的参数,没定义的参数完全不返回
* @return void
*/
protected function passedValidation(): void
{
// var_dump("验证后数据处理");
// $this->replace(['name' => 'Taylor']);
}
}
资源解释器-Resource
# 直接在toArray方法中重新编辑返回值
# $this 指的是 单条的Model 关联关系可以直接$this->关系 来查找
# 最后return 的是最终显示的值
namespace App\Http\Resources\api\common;
use Illuminate\Http\Request;
use Stevema\Restful\RestfulResource;
class MakeTestResource extends RestfulResource
{
public function toArray(Request $request)
{
// return [
// "id" => $this->id,
// "field1" => $this->field1,
// ];
return parent::toArray($request);
}
}
权限验证-Permission
# 权限验证只有俩个方法
namespace App\Http\Permissions\api\common;
use Stevema\Restful\RestfulPermission;
class MakeTestPermission extends RestfulPermission
{
/**
* 权限验证
* 可以通过 $action = request()->route()->getActionMethod();获取当前的action
* 然后判断是不是可以给权限
* @return bool
*/
public static function hasPermission(): bool
{
$action = request()->route()->getActionMethod();
if($action == 'store'){
// 新增不给权限 - 所有人不能新增
return False;
}
return True;
}
/**
* 获取currentModel后判断一下 有没有权限
* @param $currentModel
* @return bool
*/
public static function hasObjectPermission($currentModel): bool
{
$action = request()->route()->getActionMethod();
if($action == 'show'){
//详情都给权限 - 修改 删除 等就需要权限了
return True;
}
if($currentModel->user_id == auth()->user()->id){
return True;
}
return False;
}
}
命令行
# 1.生成整套的restful文件
$ php artisan make:restful api/common/make_test -m
# 其中 api/common/ 是命名空间 make_test 是想要的模型名称
# 参数解释 {name : 数据库表名称 比如 sm_test_t1}
# {--i|illustrate : 生成带说明的文件}
# {--m|migration : 生成数据迁移文件}
# {--s|seed : 生成数据填充文件}';
# 执行后输出
INFO Migration [database/migrations/2023_08_17_041228_create_make_tests_table.php] created successfully.
INFO model [app/Models/api/common/MakeTest.php] created successfully.
INFO resource [app/Http/Resources/api/common/MakeTestResource.php] created successfully.
INFO request [app/Http/Requests/api/common/MakeTestRequest.php] created successfully.
INFO filter [app/Http/Filters/api/common/MakeTestFilter.php] created successfully.
INFO permission [app/Http/Filters/api/common/MakeTestPermission.php] created successfully.
INFO controler [app/Http/Controllers/api/common/MakeTestController.php] created successfully.
# 这个时候已经生成了 数据库迁移文件(Migration) 模型(Model) 解释器(Resource) 验证器(Request) 过滤器(Filter) 权限验证(Permission) 控制器(Controller)
# 2.生成controller文件
$ php artisan make:restcontroller api/common/MakeTestController
# 参数解释 {name : 控制器名称}
# {--i|illustrate : 生成带说明的文件}
# {--f|filter= : 过滤器::class}
# {--m|model= : 模型::class}
# {--r|resource= : 解释器::class}
# {--R|request= : 表单验证::class}
# {--p|permission= : 权限::class}';
# 3.生成filter文件
$ php artisan make:restfilter api/common/MakeTestFilter
# 参数解释 {name : 过滤器名称}
# {--i|illustrate : 生成带说明的文件}
# {--r|resource= : 分页解释器[解释器::class]}';
# 4.生成filter文件
$ php artisan make:restmodel api/common/MakeTestModel
# 参数解释 {name : 模型名称}
# {--i|illustrate : 生成带说明的文件但是没什么用}
# {--t|table= : 表名}';
# 5.生成permission文件
$ php artisan make:restpermission api/common/MakeTestPermission
# 参数解释 {name : 权限名称}
# {--i|illustrate : 生成带说明的文件但是没什么用};
# 6.生成request文件
$ php artisan make:restrequest api/common/MakeTestRequest
# 参数解释 {name : 过滤器名称}
# {--i|illustrate : 生成带说明的文件但是没什么用};
# 7.生成resource文件
$ php artisan make:restresource api/common/MakeTestResource
# 参数解释 {name : 解释器名称}
# {--i|illustrate : 生成带说明的文件但是没什么用};
# 8.生成cache文件
$ php artisan make:restcache api/common/MakeTestCache
# 参数解释 {name : 缓存文件名}
# {--i|illustrate : 生成带说明的文件但是没什么用};
备注
已添加permssion(权限验证) - 不是所有的页面都没有权限 主要是request里面的那个authorize 不是很好用 1、还不是很完善 - 下一版本会想办法加上缓存机制 - 已添加 - 目前只有 getOne setOne geetList setList flush forgetOne 2、测试里面的那些仅供参考-很多都是旧版本的东西了-跑不起来是正常事 3、删除了 Traits/UseTableNameAsMorphClass 因为我新写了 laravel-morphmap 功能更全 链接:https://packagist.org/packages/stevema/laravel-morphmap