shopapps / has-table-relation
提供了一个 hasTable Eloquent 关系,用于从表中获取所有记录。
Requires
- php: ^7.3|^8.0
- illuminate/database: ^8.0|^9.0|^10.0|^11.0
README
提供一个无需任何关联外键属性的关系,用于访问整个表。
此包提供了一种将模型链接到整个表的方法,无需任何外键属性。当您有一个包含应与模型相关联的数据的表但没有外键列将其链接时,这非常有用。
虽然始终建议为任何相关数据使用 local_key <=> foreign_key 映射(例如,numbers.customer_id
<=> customer.id
),以实现标准的 hasMany
/ belongsTo
关系,但有时您只是继承数据,没有精心设计的模型。:(
注意:在使用此包之前,您也可以考虑使用 belongsToMany
关系并在两个表之间创建一个中间表。确保您这样做后,您将种子中间表以映射所有需要的记录,并在您的代码添加或删除记录时保持它们同步。我在下面的 README 中添加了一个示例迁移文件,您可以根据我的客户 -> numbers 示例场景执行此操作。
安装
composer require shopapps/has-table-relation
HasTable 关系
示例
在此示例中,给定的 Customer 模型包含与它相关的 numbers
表中的所有记录。通常,您会期望在 numbers
表中看到相关的外键列,如 customer_id
,以实现此目的并使用 hasMany 关系,但是在我提供的数据中,这不存在,并且由于数据的敏感性,我无法向该表添加额外的列。
use ShopApps\HasTableRelation\Illuminate\Database\Eloquent\Concerns\HasOtherRelationships; use App\Models\Number; class Customer extends Model { use HasOtherRelationships; public function numbers() { return $this->hasTable(Number::class); } }
您现在可以使用以下方法检索 numbers
表中的所有记录:
$customer = Customer::find(1);
$customer->numbers;
$customer->numbers()->where( 'last_called', '=>', Carbon::now()->subDays(14) )->paginate();
BelongsToTable 关系
示例
hasTable 关系的逆关系。
在此示例中,numbers
表中的所有记录都属于给定的 Customer
模型。通常,您会期望在 numbers
表中看到相关的本地键列,如 customer_id
,以实现此目的并使用 belongsTo 关系,但是在我提供的数据中,这不存在,并且由于数据的敏感性,我无法向该表添加额外的列。
您可以向 belongsToTable 方法传递一个可选的第二个参数,以指定要在父模型上调用的方法。默认为 first
,但您也可以使用 last
或 all
来调用父模型查询上的相应方法。
use ShopApps\HasTableRelation\Illuminate\Database\Eloquent\Concerns\HasOtherRelationships; use App\Models\Customer; class Number extends Model { use HasOtherRelationships; public function customer() { return $this->belongsToTable(Customer::class); } // equivelent to ... public function customer() { return $this->belongsToTable(Customer::class, 'first'); // calls $query->first() on the parent model } // another example... public function customer() { return $this->belongsToTable(Customer::class, 'last'); // calls $query->last() on the parent model } // another example... public function customers() // plural since we will be returning more than one ;-) { return $this->belongsToTable(Customer::class, 'all'); // calls $query->get() on the parent model } }
您现在可以从任何数字记录中检索父记录。
$number = Number::find(1);
$number->customer;
// or if you have more than one customer record owner of this number
$number->customer()->where( 'active', true )->paginate();
BelongsToMany - Laravel 标准关系
在使用此包之前,您也可以考虑使用 belongsToMany
关系并在两个表之间创建一个中间表。确保您这样做后,您将种子中间表以映射所有需要的记录。我在下面的示例迁移文件中添加了此功能,该文件将按照我的客户 -> numbers 示例场景执行此操作。
<?php use App\Models\Customer; use App\Models\Number; use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public $table = 'customer_number'; // standard is to keep the table names in alphabetical order public $columnOne = 'customer'; public $columnTwo = 'number'; /** * Run the migrations. */ public function up(): void { if (!Schema::hasTable($this->table)) { Schema::create($this->table, function (Blueprint $table) { $table->unsignedInteger("{$this->columnOne}_id")->index(); $table->unsignedInteger("{$this->columnTwo}_id")->index(); /* setup index across the two */ $table->primary(["{$this->columnOne}_id", "{$this->columnTwo}_id"]); }); $this->buildData(); // populate the pivot table } } public function buildData() { /* * find the first record in $columnOne and populate the pivot table with all records from $columnTwo */ $connection = Schema::getConnection(); /** @var Customer $customer */ $customer = new Customer(); $customer->setConnection($connection->getName()); $customer = $customer->first(); // my table only has one record, yours may be different, so collect and loop accordingly. if($customer) { /** @var Number $customer */ $numbers = new Number(); $numbers->setConnection($connection->getName()); $numbers = $numbers->get(); // get all the rows if(count($numbers) > 0) { $numbers = $numbers->pluck('id')->toArray(); // put id's into an array $customer->numbers()->syncWithoutDetaching($numbers); // attach the id's to the pivot table } } } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists($this->table); } };