rutatiina / orchid-crud
在Laravel Orchid中用更少的代码行构建CRUD应用。
Requires
- rutatiina/orchid-platform: ^10.0
Requires (Dev)
- orchestra/testbench: ^6.0
- phpunit/phpunit: ^9.3
README
简介
Laravel Orchid提供了独特的应用程序编写体验。然而,有时在不需要的时候,仍需要进行简单的CRUD操作。因此,我们为希望快速为Eloquent模型创建具有创建、读取、更新和删除等功能的用户界面的开发者创建了一个新的包。
您可以使用一个文件描述整个过程。当您需要更多选项时,切换到使用平台非常容易。所有字段、过滤器和特质都是兼容的。
安装
您可以使用Composer安装此包。在命令行运行以下命令
$ composer require orchid/crud
这将更新composer.json
并将包安装到vendor/
目录。
定义资源
资源存储在您的应用程序的app/Orchid/Resources
目录中。您可以使用orchid:resource
Artisan命令生成一个新的资源
php artisan orchid:resource PostResource
资源最基本属性是它的model
属性。该属性告诉生成器资源对应哪个Eloquent模型
use App\Models\Post; /** * The model the resource corresponds to. * * @var string */ public static $model = Post::class;
这些类完全是静态的。由于它们的声明性,它们没有任何状态。它们只告诉做什么。它们不持有任何数据。因此,如果您添加自定义方法,请确保它们是静态的。
新创建的资源中什么也没有。请不要担心。我们很快会向我们的资源添加更多字段。
注册资源
默认情况下,所有在app/Orchid/Resources
目录中的资源都将自动注册。您不需要手动注册它们。但如果需要,例如创建附加包时,最好的方法将是
use App\Orchid\Resources\UserResource; use Illuminate\Support\ServiceProvider; use Orchid\Crud\Arbitrator; class CrudServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot(Arbitrator $arbitrator) { $arbitrator->resources([ UserResource::class, ]); } }
扩展模型
Orchid平台的功能很多都依赖于模型自定义。您可以根据目标添加或删除特质。但我们将假设您已经为您的模型设置了这些。
use Illuminate\Database\Eloquent\Model; use Orchid\Attachment\Attachable; use Orchid\Filters\Filterable; use Orchid\Screen\AsSource; class Post extends Model { use AsSource, Filterable, Attachable; }
定义字段
每个资源都包含一个fields
方法。此方法返回一个字段数组,通常扩展了Orchid\Screen\Field
类。要向资源添加字段,我们可以在资源的fields
方法中添加它。通常,字段可以使用它们的静态make
方法创建。此方法接受多个参数;然而,您通常只需要传递字段的名称。
use Orchid\Screen\Fields\Input; /** * Get the fields displayed by the resource. * * @return array */ public function fields(): array { return [ Input::make('title') ->title('Title') ->placeholder('Enter title here'), ]; }
在生成CRUD的包中,您可以使用Orchid平台上的字段。请参阅文档网站上所有可用的字段。
定义列
每个资源都包含一个columns
方法。要向资源添加列,我们可以在资源的column
方法中添加它。通常,列可以使用它们的静态make
方法创建。
use Orchid\Screen\TD; /** * Get the columns displayed by the resource. * * @return TD[] */ public function columns(): array { return [ TD::make('id'), TD::make('title'), ]; }
CRUD生成包完全基于表层。您可以在文档页面上了解更多信息。
定义图例
每个资源都包含一个legend
方法。它决定了模型在查看时的外观。要添加到资源中,我们可以将其添加到资源的legend
方法中。通常,可以使用它们的静态make
方法创建列。
use Orchid\Screen\Sight; /** * Get the sights displayed by the resource. * * @return Sight[] */ public function legend(): array { return [ Sight::make('id'), Sight::make('title'), ]; }
CRUD生成包完全基于legend层。你可以在文档页面了解更多。
定义规则
每个资源都包含一个rules
方法。在提交创建或更新表单时,数据可以被验证,这已在rules
方法中描述。
/** * Get the validation rules that apply to save/update. * * @return array */ public function rules(Model $model): array { return [ 'slug' => [ 'required', Rule::unique(self::$model, 'slug')->ignore($model), ], ]; }
你可以在Laravel的验证页面了解更多。
定义过滤器
每个资源都包含一个filters
方法。它期望你返回一个应渲染的类名列表,如果需要,可以替换为查看的模型。
/** * Get the filters available for the resource. * * @return array */ public function filters(): array { return []; }
要创建一个新的过滤器,有一个命令
php artisan orchid:filter QueryFilter
这将创建一个在app/Http/Filters
文件夹中的类过滤器。要在自己的资源中使用过滤器,你需要
public function filters(): array { return [ QueryFilter::class ]; }
我们已经提供了一些准备好的过滤器
Orchid\Crud\Filters\DefaultSorted
- 设置默认列排序Orchid\Crud\Filters\WithTrashed
- 显示已删除的记录
public function filters(): array { return [ new DefaultSorted('id', 'desc'), ]; }
你可以在Orchid的过滤页面了解更多。
导航
如果你不希望资源出现在导航中,你可以覆盖资源类的displayInNavigation
方法
/** * Get the resource should be displayed in the navigation * * @return bool */ public static function displayInNavigation(): bool { return false; }
预加载
假设你通常需要在字段中访问资源的关联。在这种情况下,将关联添加到资源的with
属性可能是一个好主意。此属性指示在检索资源时始终预加载列出的关联。
/** * Get relationships that should be eager loaded when performing an index query. * * @return array */ public function with(): array { return ['user']; }
分页
要定义每页应显示多少结果,请设置perPage
方法
/** * Get the number of models to return per page * * @return int */ public static function perPage(): int { return 30; }
资源事件
每个资源有两个处理方法,即onSave
和onDelete
。每个方法在事件执行时启动,你可以更改或补充逻辑。
/** * Action to create and update the model * * @param ResourceRequest $request * @param Model $model */ public function onSave(ResourceRequest $request, Model $model) { $model->forceFill($request->all())->save(); } /** * Action to delete a model * * @param Model $model * * @throws Exception */ public function onDelete(Model $model) { $model->delete(); }
权限资源
每个资源都包含一个permission
方法,它应该返回用户需要访问此资源的字符串键。默认情况下,所有资源都对每个用户可用。
/** * Get the permission key for the resource. * * @return string|null */ public static function permission(): ?string { return null; }
对于每个返回非空值的注册资源方法,将创建一个新的权限。
/** * Get the permission key for the resource. * * @return string|null */ public static function permission(): ?string { return 'private-post-resource'; }
必须授予用户管理权限。要点击左侧列中的个人资料,转到系统页面,然后转到用户页面,你可以给他们发布命令或分配角色。之后,它们将显示在左侧菜单中。
操作
可以使用orchid:action
Artisan命令生成操作。
php artisan orchid:action CustomAction
默认情况下,所有操作都放置在app/Orchid/Actions
目录中。操作必须包含两个方法。方法button
定义名称、图标、对话框等。而handler
方法直接处理操作与模型。
namespace App\Orchid\Actions; use Illuminate\Support\Collection; use Orchid\Crud\Action; use Orchid\Screen\Actions\Button; use Orchid\Support\Facades\Toast; class CustomAction extends Action { /** * The button of the action. * * @return Button */ public function button(): Button { return Button::make('Run Custom Action')->icon('fire'); } /** * Perform the action on the given models. * * @param \Illuminate\Support\Collection $models */ public function handle(Collection $models) { $models->each(function () { // action }); Toast::message('It worked!'); } }
在handle
方法中,你可以执行完成操作所需的任何任务。
即使在操作仅针对单个模型执行的情况下,
handle
方法也始终接收一个模型的Collection
。
一旦定义了操作,你就可以将其附加到资源。每个资源都包含一个actions方法。要将操作附加到资源,你应该将其添加到此方法返回的操作数组中
/** * Get the actions available for the resource. * * @return array */ public function actions(): array { return [ CustomAction::class, ]; }
策略
为了限制哪些用户可以查看、创建、更新或删除资源,可以利用Laravel的授权策略。策略是简单的PHP类,用于组织特定模型或资源的授权逻辑。例如,如果您的应用程序是一个博客,您可能有一个Post
模型和应用程序中的相应PostPolicy
。
通常,这些策略将在应用程序的AuthServiceProvider
中注册。如果CRUD检测到已为模型注册了策略,它将在执行各自操作之前自动检查该策略的相关授权方法,例如
- 查看所有
- 查看
- 创建
- 更新
- 删除
- 恢复
- 强制删除
不需要额外的配置!因此,例如,为了确定哪些用户可以更新Post
模型,您需要在模型对应策略类中定义一个update
方法。
namespace App\Policies; use App\Models\User; use App\Models\Post; use Illuminate\Auth\Access\HandlesAuthorization; class PostPolicy { use HandlesAuthorization; /** * Determine whether the user can update the post. * * @param User $user * @param Post $post * @return mixed */ public function update(User $user, Post $post) { return true; } }
如果策略存在但缺少特定的操作方法,用户将不允许执行该操作。所以,如果您已经定义了一个策略,不要忘记定义其所有相关授权方法。
如果您不希望策略影响CRUD生成用户,您可能希望在给定的策略中授权所有操作。为此,在策略上定义一个before
方法。在执行其他策略方法之前,将首先执行before方法,允许您在实际调用策略方法之前授权操作。
namespace App\Policies; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; class PostPolicy { use HandlesAuthorization; /** * Perform pre-authorization checks. * * @param User $user * @param string $ability * @return void|bool */ public function before(User $user, $ability) { if ($user->hasAccess('private-post-resource')) { return true; } } }
防止冲突(交通警察)
如果此选项处于活动状态,则在编辑表单打开后更新模型时,将检查模型的最后更改。将抛出验证错误。默认情况下,功能交通警察是禁用的。
/** * Indicates whether should check for modifications between viewing and updating a resource. * * @return bool */ public static function trafficCop(): bool { return false; }
描述
要在资源的每一页上显示附加描述,请使用description
/** * Get the descriptions for the screen. * * @return null|string */ public static function description(): ?string { return null; }
面包屑
在资源的每一页上都有面包屑。您可以使用以下方法来监控消息
/** * Get the text for the list breadcrumbs. * * @return string */ public static function listBreadcrumbsMessage(): string { return static::label(); } /** * Get the text for the create breadcrumbs. * * @return string */ public static function createBreadcrumbsMessage(): string { return __('New :resource', ['resource' => static::singularLabel()]); } /** * Get the text for the edit breadcrumbs. * * @return string */ public static function editBreadcrumbsMessage(): string { return __('Edit :resource', ['resource' => static::singularLabel()]); }
本地化
可以通过覆盖资源类上的label
和singularLabel
方法来本地化资源名称
/** * Get the displayable label of the resource. * * @return string */ public static function label() { return __('Posts'); } /** * Get the displayable singular label of the resource. * * @return string */ public static function singularLabel() { return __('Post'); }
操作按钮和通知也可以翻译,例如
/** * Get the text for the create resource button. * * @return string|null */ public static function createButtonLabel(): string { return __('Create :resource', ['resource' => static::singularLabel()]); } /** * Get the text for the create resource toast. * * @return string */ public static function createToastMessage(): string { return __('The :resource was created!', ['resource' => static::singularLabel()]); }
您可以在Laravel本地化页面上了解更多信息。
支持者
感谢所有支持者!🙏 [成为支持者]
路线图
这个路线图并不意味着要涵盖我们将要做的所有工作。我们将继续投资于使CRUD更容易使用和管理。我们想要做
- 添加用于显示和恢复使用
Illuminate\Database\Eloquent\SoftDeletes
删除的模型的设置; - 添加执行多个模型操作的能力;
- 在查看时支持嵌套关系;
这是一个活跃的社区,因此请期待更多补充其各种其他改进的贡献,以帮助提高生产。
变更日志
请参阅CHANGELOG以获取有关最近更改的更多信息。
贡献
请参阅CONTRIBUTING以获取详细信息。
通讯渠道
您可以在以下地方找到帮助和讨论
- 开始新的讨论 https://github.com/orchidsoftware/platform/discussions/new
- 创建问题 https://github.com/orchidsoftware/crud/issues/new
- Telegram聊天(英语)
- Telegram聊天(俄语)
安全漏洞
请查阅我们如何报告安全漏洞的安全策略。
许可证
有关更多信息,请参阅许可证文件。