rutatiina/orchid-crud

在Laravel Orchid中用更少的代码行构建CRUD应用。

支持包维护!
Open Collective

3.1 2021-10-12 11:20 UTC

README

Laravel Orchid CRUD

Tests Open Collective backers and sponsors Packagist Packagist Version

简介

Laravel Orchid提供了独特的应用程序编写体验。然而,有时在不需要的时候,仍需要进行简单的CRUD操作。因此,我们为希望快速为Eloquent模型创建具有创建、读取、更新和删除等功能的用户界面的开发者创建了一个新的包。

您可以使用一个文件描述整个过程。当您需要更多选项时,切换到使用平台非常容易。所有字段、过滤器和特质都是兼容的。

安装

手册假设您已经有一个LaravelOrchid的副本

您可以使用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;
}

资源事件

每个资源有两个处理方法,即onSaveonDelete。每个方法在事件执行时启动,你可以更改或补充逻辑。

/**
 * 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()]);
}

本地化

可以通过覆盖资源类上的labelsingularLabel方法来本地化资源名称

/**
 * 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以获取详细信息。

通讯渠道

您可以在以下地方找到帮助和讨论

安全漏洞

请查阅我们如何报告安全漏洞的安全策略

许可证

有关更多信息,请参阅许可证文件