bakle/crud-core

Laravel Crud 核心文件

1.2.0 2024-01-14 22:27 UTC

README

此包包含所有创建 CRUD 所需的样板逻辑的基础文件。

安装

composer require bakle/crud-core

此包中包含什么内容?

UrlPresenter

URL 展示器封装了在 Route::resource('users, UserController::class) 中生成的路由

对于单个模型

class UserUrlPresenter extends BaseUrlPresenter
{

    function getRouteName(): string
    {
        return 'users';
    }
}

// --- Examples ---

// Url presenter for routes that doesn't depend on a specific model (index, create)
$userUrlPresenter = new UserUrlPresenter();
$userUrlPresenter->index(); // --> /users
$userUrlPresenter->create(); // --> /users/create
$userUrlPresenter->store(); // --> /users (for post method)

// Url presenter for routes that depend on a specific model (show, edit, update, delete )
$user = User::first();
$userUrlPresenter = new UserUrlPresenter($user);
$userUrlPresenter->index(); // --> /users
$userUrlPresenter->show(); // --> /users/1
$userUrlPresenter->create(); // --> /users/create
$userUrlPresenter->store(); // --> /users (for post method)
$userUrlPresenter->edit(); // --> /users/1/edit
$userUrlPresenter->update(); // --> /users/1
$userUrlPresenter->destroy(); // --> /users/1

对于相关模型

class UserPostCommentUrlPresenter extends BaseUrlPresenter
{

    function getRouteName(): string
    {
        return 'users.posts.comments';
    }
}

class Post extends \Illuminate\Database\Eloquent\Model
{

    public function getRouteKeyName(): string
    {
        return 'slug';
    }
}

// Example

$user = User::first();
$post = Post::first();
$comment = Comment::first();

$urlPresenter = new UserPostCommentUrlPresenter($user, $post, $comment);
$userUrlPresenter->index(); // --> /users/1/posts/the-post-slug/comments
$userUrlPresenter->show(); // --> /users/1/posts/the-post-slug/comments/1
$userUrlPresenter->create(); // --> /users/1/posts/the-post-slug/comments/create
$userUrlPresenter->store(); // --> /users/1/posts/the-post-slug/comments (for post method)
$userUrlPresenter->edit(); // --> /users/1/posts/the-post-slug/comments/1/edit
$userUrlPresenter->update(); // --> /users/1/posts/the-post-slug/comments/1
$userUrlPresenter->destroy(); // --> /users/1/posts/the-post-slug/comments/1

实体

实体是一个额外的层,用于包装你的模型并添加额外的逻辑。BaseEntity 仅需要实现 url() 方法

class UserEntity extends BaseEntity
{

    public function url(): ?BaseUrlPresenter
    {
        return new UserUrlPresenter($this->model);
    }
    ... // more methods
}

// Example single model
$user = User::first();
$userEntity = new UserEntity($user);

$user->entity->getCreatedAtDayDateFormat(); // Sat, Oct 7, 2023

// Example multiple model
$users = User::all();
$userEntities = UserEntity::collection($users);

$userEntities->first()->url()->show() // /users/1

视图模型

视图模型封装了你需要发送到视图的所有逻辑和数据。

IndexViewModel

此视图模型发送以下数据到视图:

  • entities: 模型定义在 IndexViewModel 中的实体集合(即:UserEntity)
  • 分页: 由于现在你接收的是实体集合而不是模型,这相当于执行 $users->links。现在你可以这样做
    <div class="flex w-full mt-4 justify-end">
      {!! $pagination !!}
    </div>
    
  • 标题: 这只是你在 getTitle() 方法中返回的字符串。在索引中很有用,可以在 blade 中添加,如下所示
    <h1 class="text-2xl">{{ $title }}</h1>

示例

class UserIndexViewModel extends BaseIndexViewModel
{
    public function getTitle(): string
    {
        return trans('Users');
    }

    public function getEntityClass(): string
    {
        return UserEntity::class;
    }
}


// In the UserController
class UserController extends Controller
{
    public function index(Request $request): View
    {
        $users = User::query()->with('roles');
    
        return view('users.index',
            (new UserIndexViewModel($users, $request))->build()
        );
    }
}

ShowViewModel

此视图模型发送以下数据到视图:

  • entity: 模型定义在 ShowViewModel 中的单个实体(即:UserEntity)

示例

class UserShowViewModel extends BaseShowViewModel
{
    public function getTitle(): string
    {
        return trans('User');
    }

    public function getEntityClass(): string
    {
        return UserEntity::class;
    }

    protected function getExtraData(): array
    {
        return [
            'title' => $this->getTitle()
        ];
    }
}

// In your UserController
class UserController extends Controller
{
    public function show(User $user)
    {
        $user->load('roles');
            
        return view('users.show', (new UserShowViewModel($user))->build());
    }
}

FormViewModel

此视图模型发送以下数据到视图:

  • entity: 模型定义在 ShowViewModel 中的单个实体(即:UserEntity)
  • 表单: 这包含提交表单的 URL、方法类型(POST 或 PUT)和一些其他辅助方法。在表单中很有用,如下所示
    <form method="POST" action="{{ $form->getUrl() }}">
        @csrf
        @method($form->getMethod())
    
    //...your fields

    <button class="btn btn-primary">
        @if($form->isEditType())
            {{ trans('Update') }}
        @else
            {{ trans('Create') }}
        @endif
    </button>
</form>
  • 标题: 这将自动解析标题,基于方法类型。例如,如果你使用 ->setFormType(FormTypes::CREATE),标题将是 创建用户,如果你使用 ->setFormType(FormTypes::EDIT),标题将是 编辑用户。你可以这样使用它
    <h1 class="text-2xl">{{ $title }}</h1>

示例

class UserFormViewModel extends BaseFormViewModel
{

    protected function getEntityClass(): string
    {
        return UserEntity::class;
    }

    protected function getExtraData(): array
    {
        return [
            'roles' => Role::query()->get();
        ];
    }
}

// In your UserController

class UserController extends Controller
{

    public function create(): View
    {
        return view('users.form',
            (new UserFormViewModel(new User()))->setFormType(FormTypes::CREATE)->build()
        );
    }
    
    public function edit(User $user): View
    {
        return view('users.form',
            (new UserFormViewModel($user))->setFormType(FormTypes::EDIT)->build()
        );
    }
}

所有 ViewModel 都包含一个 getExtraData() 方法,你可以返回一个数组,其中包含你需要发送到视图的额外数据。