fuzz / magic-box
将 Laravel 的 Eloquent 模型以可注入、掩码的资源库形式进行神奇实现的包。
Requires
- illuminate/database: 5.3.x
Requires (Dev)
- fuzz/http-exception: 1.0.*
- orchestra/testbench: 3.3.*
- phpunit/phpunit: ~5.6
This package is not auto-updated.
Last update: 2024-04-30 09:52:03 UTC
README
⛔️ 已弃用 ⛔️
此项目不再受支持或维护。如果您需要与 Laravel 新版本兼容的现代 Magic Box 版本,请考虑使用此项目的精神继承者 — Koala Pouch。
Magic Box 将 Fuzz 对 Laravel Eloquent 模型的神奇实现模块化,将其作为可注入、掩码的资源库。
Magic Box 有两个目标
- 创建一个双向交换格式,以便 API 广播的模型的 JSON 表示可以重新应用到原始模型,以更新现有资源并创建新资源。
- 为 API 客户端提供一个接口,以便他们可以以他们想要的方式请求确切的数据。
安装/设置
-
composer require fuzz/magic-box -
将
Fuzz\MagicBox\Middleware\RepositoryMiddleware用到您的项目中,并在app/Http/Kernel.php中的$routeMiddleware数组下注册您的类。RepositoryMiddleware包含可以覆盖的多种配置选项。 -
如果您使用
fuzz/api-server,您可以通过更新app/Providers/RouteServiceProvider.php中的RouteServiceProvider@map来使用神奇的路由。/** * Define the routes for the application. * * @param \Illuminate\Routing\Router $router * @return void */ public function map(Router $router) { // Register a handy macro for registering resource routes $router->macro('restful', function ($model_name, $resource_controller = 'ResourceController') use ($router) { $alias = Str::lower(Str::snake(Str::plural(class_basename($model_name)), '-')); $router->resource($alias, $resource_controller, [ 'only' => [ 'index', 'store', 'show', 'update', 'destroy', ], ]); }); $router->group(['namespace' => $this->namespace], function ($router) { require app_path('Http/routes.php'); }); }
-
在您指定的
RepositoryMiddleware类的中间件键下设置您的 MagicBox 资源路由。 -
设置一个
YourAppNamespace\Http\Controllers\ResourceController,这里是一个 ResourceController 的示例。 -
根据
Model Setup部分设置模型。
测试
在 composer install 后,只需运行 phpunit。
Eloquent Repository
Fuzz\MagicBox\EloquentRepository 实现了一个 CRUD 存储库,它通过关系级联,无论相关模型是否已创建。
考虑一个简单的模型,其中用户拥有多个帖子。EloquentRepository 的基本用法如下
创建一个名为 Steve 的用户,他有一个标题为 Stuff 的单个帖子。
$repository = (new EloquentRepository) ->setModelClass('User') ->setInput([ 'username' => 'steve', 'nonsense' => 'tomfoolery', 'posts' => [ 'title' => 'Stuff', ], ]); $user = $repository->save();
当调用 $repository->save() 时,将创建一个用户名为 "Steve" 的用户,并创建一个具有 user_id 的帖子,该 user_id 属于该用户。无意义的 "nonsense" 属性被简单地忽略,因为它实际上不存在于存储用户的表中。
单独的 EloquentRepository 是一个无差别的武器,没有访问控制,在任何公共 API 中都应该避免使用。它将毫无偏见地覆盖它接触到的每一个关系。例如,以下是为我们刚刚创建的用户添加新帖子的错误方式。
$repository ->setInput([ 'id' => $user->id, 'posts' => [ ['title' => 'More Stuff'], ], ]) ->save();
这将删除可怜的 Steve 的第一条帖子——这不是预期的效果。追加帖子的更安全的方式可以是以下两种方式之一
$repository ->setInput([ 'id' => $user->id, 'posts' => [ ['id' => $user->posts->first()->id], ['title' => 'More Stuff'], ], ]) ->save();
$post = $repository ->setModelClass('Post') ->setInput([ 'title' => 'More Stuff', 'user' => [ 'id' => $user->id, ], ]) ->save();
总的来说,后者更受欢迎,不太可能让你失望。
从存储库返回模型的公共 API 方法有
createreadupdatedeletesave,它将根据其输入的状态调用create或updatefind,它将根据 ID 查找模型findOrFail,它将根据 ID 查找模型或抛出\Illuminate\Database\Eloquent\ModelNotFoundException
返回 \Illuminate\Database\Eloquent\Collection 的公共 API 方法有
all
筛选
Fuzz\MagicBox\Filter 处理基于通过 filters 参数传入的筛选值对 Eloquent 查询构建器的修改。
标记和用法
| 标记 | 描述 | 示例 |
|---|---|---|
^ |
字段以...开头 | https://api.yourdomain.com/1.0/users?filters[name]=^John |
$ |
字段以...结尾 | https://api.yourdomain.com/1.0/users?filters[name]=$Smith |
~ |
字段包含 | https://api.yourdomain.com/1.0/users?filters[favorite_cheese]=~cheddar |
< |
字段小于 | https://api.yourdomain.com/1.0/users?filters[lifetime_value]=<50 |
> |
字段大于 | https://api.yourdomain.com/1.0/users?filters[lifetime_value]=>50 |
>= |
字段大于等于 | https://api.yourdomain.com/1.0/users?filters[lifetime_value]=>=50 |
<= |
字段小于等于 | https://api.yourdomain.com/1.0/users?filters[lifetime_value]=<=50 |
= |
字段等于 | https://api.yourdomain.com/1.0/users?filters[username]==Specific%20Username |
!= |
字段不等于 | https://api.yourdomain.com/1.0/users?filters[username]=!=common%20username |
[...] |
字段是一个或多个 | https://api.yourdomain.com/1.0/users?filters[id]=[1,5,10] |
![...] |
字段不是其中一个 | https://api.yourdomain.com/1.0/users?filters[id]=![1,5,10] |
NULL |
字段为NULL | https://api.yourdomain.com/1.0/users?filters[address]=NULL |
NOT_NULL |
字段不为NULL | https://api.yourdomain.com/1.0/users?filters[email]=NOT_NULL |
筛选关系
假设我们有用户和相关表的结构如下
[
'username' => 'Bobby',
'profile' => [
'hobbies' => [
['name' => 'Hockey'],
['name' => 'Programming'],
['name' => 'Cooking']
]
]
]
我们可以通过 users?filters[profile.hobbies.name]=^Cook 来筛选用户的爱好。关系可以具有任意深度。
筛选连接
我们可以使用 AND 和 OR 语句来构建筛选,例如 users?filters[username]==Bobby&filters[or][username]==Johnny&filters[and][profile.favorite_cheese]==Gouda。从这个筛选中构建的 PHP 数组是
[
'username' => '=Bobby',
'or' => [
'username' => '=Johnny',
'and' => [
'profile.favorite_cheese' => '=Gouda',
]
]
]
这个筛选可以读作 select (username为Bobby的用户) OR (用户名Johnny且其profile.favorite_cheese属性为Gouda的用户)。
模型设置
模型需要在 MagicBox 允许它们作为 MagicBox 资源公开之前实现 Fuzz\MagicBox\Contracts\MagicBoxResource。这样做是为了使公开过程是显式的,并且不会公开不需要的内容。
模型还需要定义自己的 $fillable 数组,包括可以通过此模型填充的属性和关系。例如,如果用户有多个帖子并且有多个评论,但 API 消费者只能通过用户更新评论,则 $fillable 数组看起来如下
protected $fillable = ['username', 'password', 'name', 'comments'];
MagicBox 只会修改显式定义的属性/关系。
解析模型
魔盒很棒,但我们不想在实例化存储库之前自己解析模型类...
如果您已配置了具有复数资源的 RESTful URI 结构(即 https://api.mydowmain.com/1.0/users 映射到 User 模型),则可以使用 Fuzz\MagicBox\Utility\Modeler 从路由名称解析模型类名。
测试
phpunit :)
待办事项
- 路由服务提供商应该预先设置
- 通过级联保存支持更多关系(特别是多态关系)
- 支持分页嵌套关系