资源主要为后台的增删差改等控制器提供了路由、权限的整合配置,避免配置过于繁琐。
在一个系统中可能存在多个后台入口,例如商城中的总后台与店铺端,企业平台中的总后台与企业端,每个后台均有自己不同的功能,我们把每个后台统称为管理层。
路由即为通过 url 访问时定义的路径。
返回给接口数据时除去 data
的主数据外,meta
字段内的数据均为元数据,例如分页的列表数据为主数据,分页信息则为元数据。
自定义一个资源,该资源包含路由与权限中间件,通过该方法我们可以创建多个管理层。
资源需要在应用入口文件 App.php
中的 init
方法进行初始化,如下:
$app->getResource()->set(
"admin", // 资源名
(new DuxResource(
'admin', // 路由、权限注册名
'/admin' // 路由前缀
))
->addAuthMiddleware(
new PermissionMiddleware("admin", SystemUser::class), // 权限检测中间件
new AuthMiddleware("admin") // 登录鉴权中间件
)
);
初始化资源后您可以通过路由、权限、菜单类的各自方法来进行后续操作。
资源类需要继承框架内的基础类
,并配合资源注解
进行使用,继承后该类将会自动扩展 curd
等方法。
use Dux\Resources\Action\Resources;
use Dux\Resources\Attribute\Resource;
<?php
declare(strict_types=1);
namespace App\Example\Admin;
use Dux\Resources\Action\Resources;
class Page extends Resources{
...
使用注解方法将资源类注册到资源中:
<?php
declare(strict_types=1);
namespace App\Example\Admin;
use Dux\Resources\Action\Resources;
use Dux\Resources\Attribute\Resource;
#[Resource(app: 'admin', route: '/example/list', name: 'example.list')] class Example extends Resources
{
...
使用 Resource()
注解类注册资源时可用参数如下:
路由方法,自动生成子路由,如果为 false 则关闭任何继承方法,可用方法为 many 列表、one 详情、create 创建、edit 编辑、store 保存(单字段更新)、delete 删除、deleteMany 批量删除、trash 彻底删除(软删除)、restore 恢复(软删除),默认为 many、one、create、edit、delete、deleteMany、store 软删除支持,开启后将在默认值的路由方法中加入软删除的操作路由 权限检测,如果为 false 将强制忽略该资源的权限验证 创建后将会生成下面下面的路由,可以看到每个路由会自动加入资源路由的前缀 /admin
,生成的路由供管理前端进行使用。
GET /admin/example/list/page
GET /admin/example/list/page/{id}
POST /admin/example/list/page
PUT /admin/example/list/page/{id}
DELETE /admin/example/list/page/{id}
获取列表数据时执行该附加方法,可创建该方法来对前端传递的 url 参数做列表数据筛选。
public function queryMany(Builder $query, ServerRequestInterface $request, array $args): void
{
// 获取 url 参数 (slimphp 自带方法)
$params = $request->getQueryParams();
// 通过参数设置查询条件
if ($params['num']) {
$query->where('num', $params['num']);
}
}
获取单条数据时执行该方法附加方法。
public function queryOne(Builder $query, ServerRequestInterface $request, array $args): void
执行增删差改等任何资源方法时会调用该方法,该方法对于多管理层的继承很有用,可以使用处理不通管理层的权限。
public function query(Builder $query)
{
}
因为后台使用前后端分离,后端程序不建议将所有字段暴漏出来,所以需要将数据模型中查询出的数据进行过滤或者转换,声明如下方法进行转换。
public function transform(object $item): array
{
// $item 为通过模型查询出的单条对象,列表与详情数据公用该转换
return [
"id" => $item->id,
"name" => $item->name,
"time" => $item->created_at?->toDateTimeString(),
];
}
通过后台操作的添加、编辑或修改均通过此方法进行验证。
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
return [
// 验证规则
];
}
Read more in validator Docs
通过后台操作的添加、编辑或修改均通过此方法进行格式化,格式化后返回数据则为入库数据,需要和模型表字段对应。
public function format(Data $data, ServerRequestInterface $request, array $args): array
{
// $data 为通过表单验证后的数据对象
return [
"name" => $data->name,
"title" => $data->title,
"num" => $data->num,
// 可自定义保存数据
"status" => true,
];
}
/**
* @param object|array $query 模型对象
* @param array $data 数据转换后的主数据
* @param ServerRequestInterface $request 请求体对象
* @param array $args 路由参数
* @return array
*/
public function metaMany(object|array $query, array $data, ServerRequestInterface $request, array $args): array
/**
* @param object|array $query 模型对象
* @param array $data 数据转换后的主数据
* @param ServerRequestInterface $request 请求体对象
* @param array $args 路由参数
* @return array
*/
public function metaOne(object|array $query, array $data, ServerRequestInterface $request, array $args): array
/**
* @param Data $data 表单验证后数据
* @param mixed $info 详情数据对象
* @return void
*/
public function createBefore(Data $data, mixed $info): void
/**
* @param Data $data 表单验证后数据
* @param mixed $info 详情数据对象
* @return void
*/
public function createAfter(Data $data, mixed $info): void
/**
* @param Data $data 表单验证后数据
* @param mixed $model 详情数据对象
* @return void
*/
public function editBefore(Data $data, mixed $info): void
/**
* @param Data $data 表单验证后数据
* @param mixed $model 详情数据对象
* @return void
*/
public function editAfter(Data $data, mixed $info): void
/**
* @param Data $data 表单验证后数据
* @param mixed $model 详情数据对象
* @return void
*/
public function storeBefore(Data $data, mixed $info): void
/**
* @param Data $data 表单验证后数据
* @param mixed $model 详情数据对象
* @return void
*/
public function storeAfter(Data $data, mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function delBefore(mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function delAfter(mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function trashBefore(mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function trashAfter(mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function restoreBefore(mixed $info): void
/**
* @param mixed $model 详情数据对象
* @return void
*/
public function restoreAfter(mixed $info): void
软删除支持需要开启资源参数 softDelete: true
,并且需要在模型中进行使用复用类
和增加软删除字段
,示例如下:
<?php
declare(strict_types=1);
namespace App\Example\Models;
use Dux\Database\Attribute\AutoMigrate;
use Illuminate\Database\Connection;
use Illuminate\Database\Schema\Blueprint;
#[AutoMigrate]
class Example extends \Dux\Database\Model
{
public $table = 'example';
use \Illuminate\Database\Eloquent\SoftDeletes;
public function migration(Blueprint $table)
{
$table->id();
$table->timestamps();
$table->softDeletes();
}
public function seed(Connection $db)
{
}
}
::: tip
增加字段后别忘记同步结构至数据库,使用 php dux db:sync 应用名
:::
资源类中配置该参数让列表数据支持树形数据。
protected bool $tree = true;
开启后模型必须声明树形方法和增加树形结构字段:
<?php
declare(strict_types=1);
namespace App\Example\Models;
use Dux\Database\Attribute\AutoMigrate;
use Illuminate\Database\Connection;
use Illuminate\Database\Schema\Blueprint;
#[AutoMigrate]
class Example extends \Dux\Database\Model
{
public $table = 'example';
use \Kalnoy\Nestedset\NodeTrait;
public function migration(Blueprint $table)
{
$table->id();
$table->timestamps();
\Kalnoy\Nestedset\NestedSet::columns($table); }
public function seed(Connection $db)
{
}
}
::: tip
增加字段后别忘记同步结构至数据库,使用 php dux db:sync 应用名
:::
分页数量主要通过 url
传递 pageSize
参数来定义,并且如果 pageSize
参数为空,则不开启分页。此处设置为不传递参数情况下的默认配置。
protected array $pagination = [
'status' => true, // 默认开启分页
'pageSize' => 10, // 默认每页数量
];
自带方法不够处理可以使用自定义方法的资源注解,如下:
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Dux\Resources\Attribute\Action;
#[Action(methods: 'POST', route: '/custom')] public function list(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
{
return send($response, 'ok');
}
使用 Action()
注解是可以使用以下参数:
参数 | 类型 | 必填 | 默认 | 说明 |
---|
methods | array | * | | http 请求方法,GET、POST、DELETE 等支持的方法。 |
route | string | * | | 子路径,该路径会和资源路径拼接 |
name | string | | '' | 权限名,不填会自动使用 类名.方法名 作为权限名 |
auth | bool | | null | 授权检查 - 如果为 true 则制登录,配合资源注解的 auth 使用 |
can | bool | | true | 权限检测,如果为 false 将不验证该方法权限,配合资源注解的 can 使用 |
通过指引中的创建一个示例应用
我们已经创建了一个基础的资源控制器,下面是最基本的常用示例。
<?php
declare(strict_types=1);
namespace App\Example\Admin;
use Dux\Resources\Action\Resources;
#[Resource(app: 'admin', route: '/example/example', name: 'example.example')]
class Page extends Resources
{
protected string $model = \App\Example\Models\Example::class;
public function queryMany(Builder $query, ServerRequestInterface $request, array $args): void
{
$params = $request->getQueryParams();
}
public function transform(object $item): array
{
return [
"id" => $item->id,
];
}
public function validator(array $data, ServerRequestInterface $request, array $args): array
{
return [
"name" => ["required", "please enter name"],
];
}
public function format(Data $data, ServerRequestInterface $request, array $args): array
{
return [
"name" => $data->name,
];
}
// 自定义动作路由
#[Action(methods: 'POST', route: '/custom')]
public function list(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
{
return send($response, 'ok');
}
}