jfheinrich-eu/laravel-make-commands

此包旨在成为一个 artisan 命令和工具套件,以帮助简化工作。


README

Laravel Make Commands

Owner Package Release Code Coverage Last Activity

此包旨在成为一个 artisan 命令和工具套件,以帮助简化工作。

安装

$ composer require jfheinrich-eu/laravel-make-commands

要发布资产和配置文件,请运行以下命令

$ php artisan make-commands:install

这将安装配置文件到[项目根]/app/config/make-commands.php,并将模板安装到[项目根]/stubs/make-commands。

要仅安装配置文件,请使用此命令

$ php artisan vendor:publish --tag make-commands-config

要仅安装模板,请使用此命令

$ php artisan vendor:publish --tag make-commands-assets

Make 接口(make-commands:interface)

app\Contracts 中创建一个新接口

php artisan make-commands:interface Interface

示例

$ php artisan make-commands:interface TestInterface
$ cat app/Contracts/TestInterface.php
<?php declare(strict_types=1);

namespace App\Contracts;

interface TestInterface
{

}

Make 仓库(make-commands:repository)

创建一个新的仓库。

您可以选择指定一个仓库应基于的模型。在这种情况下,命令创建了一个具有以下特性的仓库:

  • 一个受保护的模型属性,可以通过构造函数依赖注入创建。
  • 创建 CRUD 框架
    • all() : 返回所有记录的 Eloquent 集合

    • create(): 创建一个新记录并返回新记录的 Eloquent 模型。记录的数据将作为 RepositoryDto 类的属性集合提供。

    • update(): 更新现有记录并返回布尔值。要更新的数据将作为 RepositoryDto 类的属性集合提供。

    • delete(): 删除现有记录并返回布尔值。删除通过主键运行。

    • find(): 通过主键返回 Eloquent 模型。如果没有找到具有给定主键的记录,将抛出 ModelNotFoundException

泛型类 RepositoryDto

<?php

declare(strict_types=1);

namespace JfheinrichEu\LaravelMakeCommands\Dto;

use Illuminate\Support\Collection;

/**
 * @property int $id
 * @property Collection<int,array<string,mixed>> $attributes
 */
final class RepositoryDto extends DataTransferObject
{
    /**
     * @param null|int $id
     * @param null|Collection<int,array<string,mixed>> $attributes
     */
    public function __construct(
        protected ?int $id = null,
        protected ?Collection $attributes = null
    ) {
    }
}

RepositoryDto 的属性属性从模型获取所需的列,作为 illuminate\Support\Collection。

此集合可以按以下方式构建

$dto->setAttributes(collect(['id' => 42, 'email' => 'dummy@localhost.tld']);

用法

$ php artisan make-commands:repository <Repository name> --model=<Modelname>

示例

$ php artisan make-commands:repository UserRepository --model=User

app/Repositories/UserRepository.php

<?php declare(strict_types=1);

namespace App\Repositories

use Illuminate\Database\Eloquent\Collection;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use JfheinrichEu\LaravelMakeCommands\Dto\RepositoryDto;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class TestRepository
{
    public function __construct(protected User $user) {}

    public function all(): Collection
    {
        return $this->user::all();
    }

    /**
     * @inheritdoc
     */
    public function create(RepositoryDto $dto): Model|User
    {
        return $this->user::create($dto->attributes->toArray());
    }

    /**
     * @inheritdoc
     */
    public function update(RepositoryDto $dto): bool
    {
        return $this->user->whereId($dto->id)
            ->update($dto->attributes->toArray());
    }

    /**
     * @inheritdoc
     */
    public function delete(int $id): bool
    {
        return $this->user->whereId($id)->delete($id);
    }

    /**
     * @inheritdoc
     */
    public function find(int $id): Model| User
    {
        $model = $this->user->find($id)
        if (null == $model)
        {
            throw new ModelNotFoundException("Resource not found");
        }

        return $model;
    }
}

创建服务(make-commands:service)

创建一个新的服务类,可以可选地实现现有的接口,并基于现有的仓库。

php artisan make-commands:service name [--interface=Interface] [--repository=Repository]

示例

使用现有接口 App\Contracts\UserPostInterface

<?php declare(strict_types=1);

namespace App\Contracts;

interface UserPostInterface
{
	public function get( string|array|null $title, ?int $userId = 0): array|string;
}
$ php artisan make-commands:service UserPostService --interface=UserPostInterface --repository=UserRepository

app/Services/UserPostService.php

<?php

declare(strict_types=1);

namespace App\Services;

use App\Contracts\UserPostInterface;
use App\Repositories\UserRepository;

class UserPostService implements UserPostInterface
{
    public function __construct(protected UserRepository $userRepository)
    {
    }


    public function get(array|string|null $title,?int $userId = 0): array|string
    {
        // Implementation
    }


}

数据传输对象(DTO)(make-commands:dto)

基于 Steve McDougall 的出色工作,他的包 laraval-data-object-tools

我通过实现“JsonSerializable”扩展了此包。

用法

要生成新的 DTO,您只需运行以下 artisan 命令

php artisan make-commands:dto MyDto

这将生成以下类: app/Dto/MyDto.php。默认情况下,此类将是一个 final 类,实现了 DtoContract,它扩展了 JsonSerializable,这强制执行两个方法

  • toArray,以便您可以轻松地将 DTOs 转换为数组
  • JsonSerialize,以便您可以轻松地序列化 DTOs

但是,如果您使用的是 PHP 8.2,则默认情况下将生成一个 readonly 类,因此您不必将每个属性声明为只读。

示例

$ php artisan make-commands:dto MyDto

app/Dto/MyDto.php

<?php

declare(strict_types=1);

namespace App\Dto;

use JfheinrichEu\LaravelMakeCommands\Dto\DataTransferObject;

final class MyDto extends DataTransferObject
{
    public function __construct(
        //
    ) {}
}

使用数据注入功能

要使用数据注入功能,您可以使用 Laravel 的 DI 容器或现成的外观。

使用容器

class StoreController
{
    public function __construct(
        private readonly HydratorContract $hydrator,
    ) {}

    public function __invoke(StoreRequest $request)
    {
        $model = Model::query()->create(
            attributes: $this->hydrator->fill(
                class: ModelObject::class,
                parameters: $request->validated(),
            )->toArray(),
        );
    }
}

要使用外观,您可以执行类似操作

class StoreController
{
    public function __invoke(StoreRequest $request)
    {
        $model = Model::query()->create(
            attributes: Hydrator::fill(
                class: ModelObject::class,
                parameters: $request->validated(),
            )->toArray(),
        );
    }
}

对象注入

在底层,这个包使用了由 Frank de Jonge 创建的 EventSauce 包。这可能是我在PHP中找到的最好的用于对象填充的包。如果您想了解如何使用此包满足您的需求,可以在此处找到文档

JSON 数据库种子

这个包中的数据库生成器

  • DatabaseJsonSeeder
  • JsonSeeder

是为了从JSON数据文件中为表生成种子数据而设计的。

用法

您需要做的只是将 DatabaseJsonSeeder 集成到 Database Seeder\Database Seeder 中。

<?php declare(strict_types=1);

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use JfheinrichEu\LaravelMakeCommands\Support\Database\Seeder\DatabaseJsonSeeder;

class DatabaseSeeder extends DatabaseJsonSeeder
{
    use WithoutModelEvents;

    protected array $nonJsonSeeders = [
        // Database\Seeders\MyNonJsonSeeder::class,
    ];

    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run(): void
    {
        parent::setCommand($this->command)->setContainer($this->container);
        parent::run();

        // run the non JSON seeders
        $this->call($this->nonJsonSeeders);
    }
}

之后,将JsonSeeder要考虑的模型输入到 config/make-commands.php 中,并在 seeders 键下配置种子类和数据文件的路径。模型的顺序必须根据依赖关系指定。

如果尚不存在,JsonSeeder类将自动创建。

<?php

declare(strict_types=1);

return [
    /*
     * List of all commands to be registered.
     */
    'commands' => [
        JfheinrichEu\LaravelMakeCommands\Console\Commands\DtoMakeCommand::class,
        JfheinrichEu\LaravelMakeCommands\Console\Commands\InterfaceMakeCommand::class,
        JfheinrichEu\LaravelMakeCommands\Console\Commands\RepositoryMakeCommand::class,
        JfheinrichEu\LaravelMakeCommands\Console\Commands\ServiceMakeCommand::class,
    ],
    'seeders' => [
        // Path to the seeder classes, must match the namespace Database\Seeders.
	    'path-seeder' => database_path('seeders'),
        // The directory where the data files goes in.
        'path-datafiles' => database_path('seeders/data'),
        // The models which will be used by the JsonSeeder.
        'models' => [
            App\Models\User::class,
            App\Models\Right::class,
        ],
    ],
];

现在您需要创建JSON格式的数据文件。文件名必须与模型的表名匹配。

以下是用户模型的示例。

database/seeders/data/users.json

[
    {
        "id": 1,
        "name": "Bastard Operator from hell",
        "email": "bofh@jfheinrich.eu",
        "email_verified_at": "2023-01-01 12:00:00",
        "password": "$2y$10$9wMEaiSx1KpwmHnbpH33pecbGd/FrRaY5SJXoqhdZ4mZnRVZmv0Ke",
        "two_factor_secret": null,
        "two_factor_recovery_codes": null,
        "remember_token": null
    },
    {
        "id": 2,
        "name": "backend",
        "email": "backend@jfheinrich.eu",
        "email_verified_at": "2023-01-01 13:00:00",
        "password": "$2y$10$VvIem6s7FgZIvdSiGqwG4.i0nEYYC.quHyb6SQkeALxa8lZXQnf6K",
        "two_factor_secret": null,
        "two_factor_recovery_codes": null,
        "remember_token": null
    }
]

之后,您可以使用以下命令运行生成器

php artisan db:seed

从数据库创建 JSON 数据文件(make-commands:seeder-data)

您可以直接从数据库创建生成器JSON数据文件。

使用以下命令

php artisan make-commands:seeder-data [Model…]

示例

$ php artisan make-commands:seeder-data \App\Models\User \App\Models\UserPost
  App\Models\User(users.json) .............................................................................................................. RUNNING
  App\Models\User(users.json) ........................................................................................................ 74.14 ms DONE

  App\Models\Right(rights.json) ............................................................................................................ RUNNING
  App\Models\Right(rights.json) ....................................................................................................... 2.43 ms DONE

这将在配置的种子数据目录中创建 users.jsonuser_posts.json 文件。

扩展 Eloquent 模型以使用视图

UseView 特性允许基于 Views 创建 eloquent 模型,这些模型是

  • 可选择的
  • 可更新的
  • 可插入的

对于 View 的底层表,必须存在 eloquent 模型。

Model 必须扩展 ViewModel 并至少定义以下三个属性

  • protected $table = '视图的名称'
  • protected $mainTable = '作为主表的表'。
  • protected $baseTables = ['所有底层表']

ViewModelModel 添加以下属性和方法。

  • 静态方法 create(array $attributes): ViewModel|Collection
  • public function insert(array|array>> $values): bool
  • public function update(array $attributes, array $options): bool
  • public function delete(): bool|null
  • public function truncateView(): void
  • public function getModelByTableName(string $table): Model
  • public function getMainTable(): string
  • public function getBaseTables(): string[]
  • public function getMainTableAttributes(): string[]
  • public function getAllTableAttributes(): array
  • 属性 bool is_view

示例

<?php

declare(strict_types=1);

namespace App\Models;

use JfheinrichEu\LaravelMakeCommands\Models\ViewModel;

class MyView extends ViewModel
{
    /**
     * @var string
     */
    protected $table = 'my_view';

    /** @var string */
    protected string $mainTable = 'data_table1';

    /** @var string[] */
    protected array $baseTables = [
        'data_table1',
        'data_table2',
        'data_table3',
    ];

...
}

IDE - 视图模型辅助支持

由于Eloquent和Doctrine没有回退到视图的列,出现了两个问题

  • Artisan模型:show 返回视图的列
  • IDE - 助手:也没有识别出列,因此不会为列生成注释。

对于第二个问题,此包中有 artisan 命令 make-commands:view-model-hook,该命令在 app/Support/IdeHelper 目录中创建钩子类。然后只需在 IDE-Helper 配置文件下的 hooks 中添加即可。

致谢