aldeebhasan / naive-crud
一个轻量级的包,用于处理laravel的crud操作
Requires
- php: ^8.2
- intervention/image: ^3.6.2
- maatwebsite/excel: ^3.1
Requires (Dev)
- laravel/legacy-factories: ^1.0.4
- orchestra/testbench: 9.x-dev
- phpunit/phpunit: ^11.0.1
README
一个轻量级包,用于处理laravel api的crud操作
安装
使用composer安装
composer require aldeebhasan/naive-crud
可选:安装后运行以下代码以发布配置
php artisan vendor:publish --tag=naive-crud
基本用法
此包可以帮助你完全自定义crud,并对开发中的每个部分都有巨大的控制权> 将不再出现重复的代码。
项目结构
理解包的工作方式最好的方法是看例子,假设我们想要创建一个用于博客的crud
假设我们有一个博客模型 App\Models\Blog.php
控制器
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; //optional: define the blog policy class protected string $policy = BlogPolicy::class; //optional: define the blog request class //The package is smart enough to it will look for this class under app/http/Requests folder protected ?string $modelRequestForm = BlogRequest::class //optional: define the blog resource class //The package is smart enough to it will look for this class under app/http/Resources folder protected ?string $modelResource = BlogResource::class }
查询处理
我们可以使用重新定义的查询辅助器列表来控制需要返回或导出的数据访问
//applied over all the routes public function baseQuery(Builder $query): Builder { return $query; } //applied over the index routes + along with base query protected function indexQuery(Builder $query): Builder { return $query; } //applied over the show routes + along with base query protected function showQuery(Builder $query): Builder { return $query; } //applied over the search routes + along with base query protected function searchQuery(Builder $query): Builder { return $query; } //applied over the export routes + along with base query protected function exportQuery(Builder $query): Builder { return $query; }
路由
我们有两个路由组
-
资源路由:将启用以下路由
- [GET] /resource/search : 搜索项
- [POST]/resource/import : 从基于文件导入模板的文件导入项
- [GET] /resource/import-template: 下载一个模板文件用于导入
- [GET] /resource/export: 导出数据
- [POST] /resource/bulk : 批量存储
- [PUT] /resource/bulk : 批量更新
- [DELETE] /resource/bulk: 批量删除
- [GET] /resource/fields : 获取过滤器和排序字段
- [PUT] /resource/toggle: 切换列值
- [GET] /resource : 浏览模型分页数据
- [POST] /resource, : 添加新项
- [GET] /resource/{id} : 获取项的详细信息
- [PUT] resource/{id} : 更新特定项
- [DELETE] resource/{id} : 删除特定项
NCRoute::ncResource('blogs', BlogController::class);
-
文件辅助路由:将启用以下路由
- [POST]/base_path/upload-image : 上传图片
- [POST]/base_path/upload-file : 上传文件
NCRoute::files('base_path');
授权
使用authorize
参数可以控制器使用授权访问控制器资源,默认为True
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; protected bool $authorize = true; //optional: define the blog policy class protected string $policy = BlogPolicy::class; } //policy class class BlogPolicy extends BasePolicy { }
我们期望用户有如下形式的定义门控:action_resource,
在我们的例子中,如果我们想让用户访问索引路由,他应该有以下能力
$user->can('index_blogs',Blog::class) // => true
大多数规则和权限包根据分配给用户的权限为我们定义这些策略
资源
默认情况下,包将搜索与模型名匹配的资源。在我们的例子中,包将在App\\Http\\Resources
命名空间下查找BlogResource
。如果未找到,则将返回响应到所有检索模型路由的$model->toArray()
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; // auto-discovered, use this if you are using custom name protected ?string $modelResource = BlogResource::class } //resource class class BlogResource extends BaseResource { // response for index route public function toIndexArray(Request $request): array { return [ 'id' => $this->id, 'slug' => str($this->title)->slug(), 'title' => $this->title, ]; } // response for show route public function toShowArray(Request $request): array { return [ 'id' => $this->id, 'slug' => str($this->title)->slug(), 'title' => $this->title, 'description' => $this->description, ]; } // response for search route public function toSearchArray(Request $request): array { return [ 'key' => $this->id, 'value' => $this->title, ]; } }
请求表单
默认情况下,包将搜索与模型名匹配的请求表单。在我们的例子中,包将在App\\Http\\Requests
命名空间下查找BlogRequest
。如果未找到,则将使用默认请求类,其中没有规则来控制接收到的数据
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; // auto-discovered, use this if you are using custom name protected ?string $modelRequestForm = BlogRequest::class } //Request class class BlogRequest extends BaseRequest { public function storeRules(): array { return [ 'title' => 'required|string', 'description' => 'required|string', 'image' => 'nullable|string', ]; } public function updateRules(): array { return [ 'title' => 'required|string', 'description' => 'nullable|string', 'image' => 'nullable|string', ]; } public function toggleRules(): array { return [ 'active' => 'nullable|boolean', ]; } }
过滤器
我们可以为每个控制器定义一个过滤器列表,以根据发送到API请求的某些查询参数过滤返回的数据
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; protected array $filters = [ CommonFilter::class ]; } //Request class class CommonFilter implements FilterUI { public function fields(): array { return [ new FilterField(field: 'search', callback: fn ($q, $val) => $q->search($val)), new FilterField(field: 'category_id'), ]; } }
当我们调用索引端点 .../api/blogs
时,我们可以通过以下方式传递过滤器: .../api/blogs?filters[search]=title&filters[category_id]=1
,然后根据它们过滤结果。您可以在任何过滤器类中按需分组过滤器字段,并且可以根据需要使用任意数量的过滤器类
排序器
类似于 过滤器
,我们可以定义一些字段来按我们的需求对返回的数据进行排序,如下所示
use Aldeebhasan\NaiveCrud\Http\Controllers\BaseController; class BlogController extends BaseController { //required: define the model class protected string $model = Blog::class; protected array $sorters = [ CommonSorter::class ]; } //Request class class CommonSorter implements SortUI { public function fields(): array { return [ new SortField( field: 'category_id', callback: fn ($q, $direction) { $q->orderBy( Category::whereColumn('categories.id','blogs.category_id')->select('categories.priority')), $direction ); }, new SortField(field: 'id'), ]; } }
当我们调用索引端点 .../api/blogs
时,我们可以按照以下方式传递排序器 .../api/blogs?sorts[id]=desc&filters[tag]=asc
,它将根据排序器对结果进行排序。您可以在任何排序器类中按需对排序器字段进行分组,并且您可以使用任意数量的排序器类
批量操作
一般来说,批量操作使用为存储/更新定义的规则,如果您愿意,可以覆盖 bulkStoreRules
以添加更多规则
批量存储的示例请求
//For bulk store
[POST] .../api/blogs/bulk
[BODY] {
resources : [
{
"name" => "blog 1",
"description" => "description for blog 1"
},
{
"name" => "blog 2",
"description" => "description for blog 2"
}
]
}
//For bulk update
[PUT] .../api/blogs/bulk
[BODY] {
resources : {
1 => {
"name" => "blog 1",
"description" => "description for blog 1"
},
2 => {
"name" => "blog 2",
"description" => "description for blog 2",
},
}
}
// to bluk delete blog with id = 1 and 2 and 3
[DELETE] .../api/blogs/bulk
[BODY] {
resources : [1,2,3]
}
导出 & 导入
简单来说,您可以导入来自外部文件的数据。首先,您需要使用 .../api/blogs/import-template
下载示例模板文件。然后,在填写了一些数据后,您可以通过发送以下请求来导入数据
[POST] .../api/blogs/import
[BODY] {
file : "path/to/file.csv"
}
注意:我们期望文件通过提供的文件路径上传并可供访问,所有导入操作都是分块使用队列导入的
另一方面,要导出任何数据,您可以使用
[POST] .../api/blogs/export
[BODY] {
'type' => 'excel|csv|html',
'target' => 'all|page'
}
对于需要大量数据导出的情况,您可以发送导出操作由队列稍后处理。您可以通过将控制器中的 $exportAllShouldQueue
修改为 `True` 来控制此操作。
这样做后,将向当前用户发送通知
**重要:** 当您将 exportAllShouldQueue 设置为 True 时,您必须定义将用于通知当前用户的通知类
... completedJobNotification = ExportDoneNotification::class ... class ExportDoneNotification extends Notification{ public function __construct(protected string $path) {} }
重要
要使任何模型能够导入和导出,它应该实现 ExcelUI
接口
许可
Laravel Naive Crud 包在 MIT 许可证 (MIT) 下授权。
安全联系方式
要报告安全漏洞,请直接联系开发者的联系邮箱 此处。