shopapps/has-table-relation

提供了一个 hasTable Eloquent 关系,用于从表中获取所有记录。

1.0.5 2023-11-10 10:19 UTC

This package is auto-updated.

Last update: 2024-09-13 11:14:03 UTC


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,但您也可以使用 lastall 来调用父模型查询上的相应方法。

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);
    }
};