brandonkerr/eloquent-from-settings

轻松从 JSON 或数组生成 eloquent 模型和关系

1.0.0 2023-04-17 18:58 UTC

This package is auto-updated.

Last update: 2024-09-17 22:02:08 UTC


README

Packagist Version Tests Static Analysis codecov

此包允许您通过通过传递给模型工厂的数组或 JSON 数据设置轻松构建 Eloquent 模型和它们的关系。

安装

使用 composer 安装此包

composer require brandonkerr/eloquent-from-settings

首先,确保您的模型有一个工厂

namespace App\Models;

// ...
use Illuminate\Database\Eloquent\Factories\HasFactory;

class User extends Authenticatable 
{
    use HasFactory;
    // ...
}

然后只需将 FromSettings 特性添加到您的工厂中

namespace Database\Factories;

// ...
use Brandonkerr\EloquentFromSettings\Traits\FromSettings;

class UserFactory extends Factory
{
    use FromSettings;
    // ...
}

配置

默认情况下,FromSettings 特性行为严格,如果键关系没有使用 FromSettings 特性,则将抛出

  • MissingTraitException
  • 如果无法将键匹配到属性、关系或函数,则抛出 UnknownKeyException

尽管这是确保数据完整性的推荐行为,但您有自由更改这些设置。

如果您想允许键关系不使用 FromSettings 特性,您可以设置 $throwsMissingTraitException 属性为 false

class FooFactory extends Factory
{
    use FromSettings;
    
    public bool $throwsMissingTraitException = false;
    
    // ...
}

或实现 FromSettingsInterface 并完成 getThrowsMissingTraitException() 函数以进行自定义逻辑

class BarFactory extends Factory implements FromSettingsInterface
{
    use FromSettings;
    
    public function getThrowsMissingTraitException(): bool
    {
        return $this->someCustomSettingOrLogic;
    }
    
    // ...
}

如果您想允许静默删除未知键,您可以设置 $throwsUnknownKeyException 属性为 false

class FooFactory extends Factory
{
    use FromSettings;
    
    public bool $throwsUnknownKeyException = false;
    
    // ...
}

或实现 FromSettingsInterface 并完成 getThrowsUnknownKeyException() 函数以进行自定义逻辑

class BarFactory extends Factory implements FromSettingsInterface
{
    use FromSettings;
    
    public function getThrowsUnknownKeyException(): bool
    {
        return $this->someCustomSettingOrLogic;
    }
    
    // ...
}

用法

简单地将所需的设置通过数组传递给工厂的 fromSettingsArray 函数

$data = [
        "name" => "Brandon Kerr",
        "books" => [
            [
                "title" => "How to Use Eloquent From Settings",
                "reviews" => [
                    [
                        "reviewer" => "Jane Doe",
                        "score" => 80,
                    ],
                    [
                        "reviewer" => "John Smith",
                        "score" => 45,
                    ],
                ],
            ],
        ],
    ];
Author::factory()->fromSettingsArray(...$data)->create();

或通过 JSON 传递给工厂的 fromSettingsJson 函数

$json = '{
   "name":"Brandon Kerr",
   "books":[
      {
         "title":"How to Use Eloquent From Settings",
         "reviews":[
            {
               "reviewer":"Jane Doe",
               "score":80
            },
            {
               "reviewer":"John Smith",
               "score":45
            }
         ]
      }
   ]
}';
Author::factory()->fromSettingsJson($json)->create();

最终结果将是

  • 一个名为 Brandon Kerr 的作者模型
  • 一个作者模型,其作者是上面创建的,标题是 如何使用 Eloquent From Settings
  • 对上面创建的书的评论,评论者是 Jane Doe,评分为 80
  • 对上面创建的书的评论,评论者是 John Smith,评分为 45

完整示例

此示例涵盖作者撰写书籍,这些书籍有评论。完整详情可在此包的测试目录中找到。

模型和模式

有关详细信息,请参阅 tests/Stubs 下的 Models 和 Migrations 目录。

作者

  • 一个作者 HasMany 书籍
  • 一个作者 HasManyThrough 评论(通过书籍)

书籍

  • 一个书籍 BelongsTo 作者
  • 一个书籍 HasMany 评论

评论

  • 一个评论 BelongsTo 一本书

工厂

AuthorFactoryReviewFactory 类完全标准(除了使用 FromSettings 特性外),但 BookFactory 有两个自定义函数以展示此包的附加功能

 /**
 * Custom function to find or create the author, based on the given name
 *
 * @param string $name
 * @return $this
 */
public function forAuthor(string $name): self
{
    $author = Author::firstOrCreate([
        "name" => $name
    ]);

    return $this->state(["author_id" => $author->id]);
}

/**
 * Custom function to add reviews with a perfect score
 *
 * @param string ...$names
 * @return $this
 */
public function perfectReviews(string ...$names): self
{
    return $this->has(
        Review::factory()
            ->count(count($names))
            ->sequence(fn (Sequence $sequence) => [
                "reviewer" => $names[$sequence->index],
                "score" => 100,
            ])
    );
}

设置数据

以下是设置数组的示例,其中作者为数据根

$data = [
        // the author's name attribute
        "name" => "Bob",
        // the author's HasMany relationship with Book
        "books" => [
            // first book
            [  
                // the book's title attribute
                "title" => "Bob's First Book",
                // the book's HasMany relationship with Review
                "reviews" => [
                    // first review
                    [
                        // the review's reviewer attribute
                        "reviewer" => "Jane Doe",
                        // the review's score attribute
                        "score" => 80,
                    ],
                    // second review
                    [
                        // the review's reviewer attribute
                        "reviewer" => "John Smith",
                        // the review's score attribute
                        "score" => 45,
                    ],
                ],
            ],
            // second book
            [
                // the book's title attribute
                "title" => "Please Don't Review Me",
                // NOTE no reviews 
            ],
        ],
    ];

然后我们简单地调用作者的工厂

$author = Author::factory()->fromSettingsArray(...$data)->create();

最终结果是

  • 一个名为 Bob 的作者,该作者有两本书
    • 第一本书名为 Bob 的第一本书,有两篇评论
      • 一篇评论者是 Jane Doe,评分为 80,和
      • 一篇评论者是 John Smith,评分为 45
    • 第二本书名为 请不要评论我,没有评论。

BelongsTo

我们不仅限于像上面示例中的Has__关系。我们还可以将书作为数据根,并为它创建一个作者。

$data = [
    "title" => "My Book",
    "author" => [
        "name" => "Bob Jones",
    ],
];
Book::factory()->fromSettingsArray(...$data)->create();

最终结果是名为Bob Jones的一位作者,他有一本名为我的书的书。

自定义函数

但如果我们不想创建一个新的作者,也不知道可以用什么作者的ID来设置书的author_id值呢?你可以在书的工厂中创建一个自定义函数,通过名字找到作者,并将其分配给书。有关forAuthor()函数的详细信息,请参见上方。

Author::create([
    "name" => "Bob Jones"
]);
// ...
$data = [
    "title" => "My Book",
    "forAuthor" => [
        "name" => "Bob Jones",
    ],
];

$book = Book::factory()->fromSettingsArray(...$data)->create();

最终结果依然是名为Bob Jones的一位作者,他有一本名为我的书的书。但由于名为Bob Jones的作者已经存在,所以不会再次创建,也不会违反我们在作者表中对唯一名字的约束。

我们还可以使用自定义函数来接受非键值对设置。有关perfectReviews()函数的详细信息,请参见上方。

$data = [
    "title" => "My Book",
    "author" => [
        "name" => "Bob Jones",
    ],
    "perfectReviews" => [
        [
            "Jane Doe",
        ],
        [
            "John Smith",
        ],
    ],
];

最终结果依然是名为Bob Jones的一位作者,他有一本名为我的书的书。然而,这次书有两个评论:一个是评论者Jane Doe的评论,另一个是评论者John Smith的评论,两者评分都是100(由perfectReviews函数设置)。

许可证

本软件包是开源软件,采用MIT许可证授权。