calebporzio / sushi
Eloquent 缺失的 "array" 驱动器。
资助包维护!
calebporzio
Requires
- php: ^7.1.3|^8.0
- ext-pdo_sqlite: *
- ext-sqlite3: *
- illuminate/database: ^5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/support: ^5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
Requires (Dev)
- doctrine/dbal: ^2.9 || ^3.1.4
- orchestra/testbench: 3.8.* || 3.9.* || ^4.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0
- phpunit/phpunit: ^7.5 || ^8.4 || ^9.0 || ^10.0
README
Eloquent 缺失的 "array" 驱动器。
有时你想使用 Eloquent,但又不想处理数据库。
此包是赞助软件 💰💰💰
最初,这个包仅对我的 GitHub Sponsors 上的赞助者可用,直到我达到了 75 个赞助者。
现在我们已经达到目标,这个包是完全开源的。
享受吧,感谢您的支持! ❤️
在 github.com/sponsorware/docs 了解更多关于 赞助软件 的信息 💰。
需求
您必须安装系统上的 pdo-sqlite
PHP 扩展 才能使用此包。
安装
composer require calebporzio/sushi
使用
使用此包包括两个步骤
- 将
Sushi
特性添加到模型中。 - 向模型添加一个
$rows
属性。
就是这样。
class State extends Model { use \Sushi\Sushi; protected $rows = [ [ 'abbr' => 'NY', 'name' => 'New York', ], [ 'abbr' => 'CA', 'name' => 'California', ], ]; }
现在,您可以在任何您喜欢的地方使用此模型,它将表现得好像您创建了一个包含您提供的行的表。
$stateName = State::whereAbbr('NY')->first()->name;
这对于“固定”数据非常有用,如州、国家、邮编、用户角色、站点设置等...
关系
假设您创建了一个 Role
模型,使用 Sushi 通过数组创建,如下所示
class Role extends Model { use \Sushi\Sushi; protected $rows = [ ['id' => 1, 'label' => 'admin'], ['id' => 2, 'label' => 'manager'], ['id' => 3, 'label' => 'user'], ]; }
您可以像通常一样添加到另一个标准模型的关系
class User extends Model { ... public function role() { return $this->belongsTo(Role::class); } }
假设 users
表有一个 role_id
列,您可以这样做
// Grab a User. $user = User::first(); // Grab a Role. $role = Role::whereLabel('admin')->first(); // Associate them. $user->role()->associate($role); // Access like normal. $user->role; // Eager load. $user->load('role'); User::with('role')->first();
注意:处理 Sushi 模型关系时有一个注意事项。`whereHas` 方法将不会工作。这是因为两个模型分布在两个不同的数据库中。
使用数据库检查验证规则
您甚至可以使用 Laravel 的 exists:table,column
数据库检查请求验证规则。
$data = request()->validate([ 'state' => ['required', 'exists:App\Models\State,abbr'], ]);
注意:请务必使用模型的完全限定命名空间,而不是表名。这确保 Laravel 正确解析模型的连接。
自定义模式
如果 Sushi 的模式自动检测系统不能满足您对提供的行数据的特定要求,您可以使用 $schema
属性或 getSchema()
方法来自定义它们。
class Products extends Model { use \Sushi\Sushi; protected $rows = [ ['name' => 'Lawn Mower', 'price' => '226.99'], ['name' => 'Leaf Blower', 'price' => '134.99'], ['name' => 'Rake', 'price' => '9.99'], ]; protected $schema = [ 'price' => 'float', ]; }
高级用法
当您需要更多灵活性时,您可以实现 afterMigrate(BluePrint $table)
方法,允许您在表创建后自定义它。这可能对向某些列添加索引很有用。
class Products extends Model { use \Sushi\Sushi; protected $rows = [ ['name' => 'Lawn Mower', 'price' => '226.99'], ['name' => 'Leaf Blower', 'price' => '134.99'], ['name' => 'Rake', 'price' => '9.99'], ]; protected function afterMigrate(Blueprint $table) { $table->index('name'); } }
工作原理
在内部,此包只为该模型创建并缓存一个 SQLite 数据库。它创建一个表并填充行。如果由于任何原因它无法缓存 .sqlite 文件,它将默认使用内存中的 SQLite 数据库。
使用 ->getRows()
您可以选择不使用 protected $rows
属性,而是直接实现自己的 getRows()
方法。
这将允许您在运行时确定模型的行。您甚至可以从第三方 API 等外部来源生成模型的行。
class Role extends Model { use \Sushi\Sushi; public function getRows() { return [ ['id' => 1, 'label' => 'admin'], ['id' => 2, 'label' => 'manager'], ['id' => 3, 'label' => 'user'], ]; } }
Caching ->getRows()
如果您选择使用自己的 ->getRows()
方法,则默认情况下不会在请求之间缓存行。
您可以使用以下方法强制 Sushi 缓存您的数据集:`sushiShouldCache()`。
以下是一个示例配置,其中 ->getRows()
数据集将被缓存
class Role extends Model { use \Sushi\Sushi; public function getRows() { return [ ['id' => 1, 'label' => 'admin'], ['id' => 2, 'label' => 'manager'], ['id' => 3, 'label' => 'user'], ]; } protected function sushiShouldCache() { return true; } }
默认情况下,Sushi会查看您的模型PHP文件的“最后修改”时间戳,并将其与内部的.sqlite
缓存文件进行比较。如果模型文件比.sqlite
缓存文件更早更改,那么Sushi将销毁并重建.sqlite
缓存。此外,您还可以配置一个外部文件,以便Sushi在确定缓存是否是最新的或需要刷新时进行参考。
例如,如果您使用Sushi为外部的数据源文件(如.csv
文件)提供Eloquent模型,则可以使用sushiCacheReferencePath
强制Sushi在确定缓存是否已过时时引用.csv
文件。
例如
class Role extends Model { use \Sushi\Sushi; public function getRows() { return CSV::fromFile(__DIR__.'/roles.csv')->toArray(); } protected function sushiShouldCache() { return true; } protected function sushiCacheReferencePath() { return __DIR__.'/roles.csv'; } }
现在,只有在roles.csv
更改时,Sushi才会“清除”其内部缓存,而不是查看Role.php
模型。
处理空数据集
Sushi会读取数据集的第一行来推断SQLite表的架构。如果您使用getRows()
并且这返回一个空数组(例如API返回空数据),则Sushi会引发错误。
如果您希望即使数据集为空,Sushi也能正常工作,您可以在可选的protected $schema
数组中定义您的架构。
注意:如果您选择使用自己的
->getRows()
方法,则请求之间不会缓存行。
class Currency extends Model { use \Sushi\Sushi; protected $schema = [ 'id' => 'integer', 'name' => 'string', 'symbol' => 'string', 'precision' => 'float' ]; public function getRows() { return []; } }
处理基于字符串的主键
如果Sushi使用基于字符串的主键,则需要在模型中添加两个属性 - $incrementing
和$keyType
class Role extends Model { use \Sushi\Sushi; public $incrementing = false; protected $keyType = 'string'; protected $rows = [ ['id' => 'admin', 'label' => 'Admin'], ['id' => 'manager', 'label' => 'Manager'], ['id' => 'user', 'label' => 'User'], ]; }
故障排除
错误: SQLSTATE[HY000]: General error: 1 too many SQL variables
默认情况下,Sushi使用100
个数据块来在SQLite数据库中插入您的数据。在某些场景中,这可能会遇到一些SQLite限制。您可以在模型中配置块大小:public $sushiInsertChunkSize = 50;