hasOneThrough 与数据透视表 Laravel 雄辩

Chr*_*nch 3 laravel eloquent

我有以下表格

mysql> describe records;
+-----------------+---------------------+------+-----+---------+----------------+
| Field           | Type                | Null | Key | Default | Extra          |
+-----------------+---------------------+------+-----+---------+----------------+
| id              | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| event_school_id | bigint(20) unsigned | NO   | MUL | NULL    |                |
| athlete_id      | bigint(20) unsigned | NO   | MUL | NULL    |                |
| year            | int(10) unsigned    | NO   |     | NULL    |                |
| place           | int(10) unsigned    | NO   |     | NULL    |                |
| created_at      | timestamp           | YES  |     | NULL    |                |
| updated_at      | timestamp           | YES  |     | NULL    |                |
| deleted_at      | timestamp           | YES  |     | NULL    |                |
+-----------------+---------------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

mysql> describe event_school;
+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| event_id   | bigint(20) unsigned | NO   | MUL | NULL    |                |
| school_id  | bigint(20) unsigned | NO   | MUL | NULL    |                |
| notes      | text                | NO   |     | NULL    |                |
| created_at | timestamp           | YES  |     | NULL    |                |
| updated_at | timestamp           | YES  |     | NULL    |                |
| deleted_at | timestamp           | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

mysql> describe events;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| name        | varchar(191)        | NO   |     | NULL    |                |
| category_id | bigint(20) unsigned | NO   | MUL | NULL    |                |
| created_at  | timestamp           | YES  |     | NULL    |                |
| updated_at  | timestamp           | YES  |     | NULL    |                |
| deleted_at  | timestamp           | YES  |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

从我的 Record Eloquent 模型中,我如何从记录中获取事件。它需要遍历 event_school 数据透视表;但我没有 EventSchool 的模型。我需要做一个吗?有没有办法在没有 EventSchool 模型的情况下做到这一点?

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class EventSchool extends Model
{
    use SoftDeletes;
    protected $guarded = ['id'];
    protected $table = 'event_school';

    public function event()
    {
        return $this->belongsTo('App\Event');
    }

    public function school()
    {
        return $this->belongsTo('App\School');
    }

}
namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Record extends Model
{
    use SoftDeletes;
    protected $guarded = ['id'];

    public function athlete()
    {
        return $this->belongsTo('App\Athlete');
    }

    function event_school()
    {
        return $this->belongsTo('App\EventSchool','event_school_id');
    }

    function event()
    {
        //What can I put here to complete method

        //right now have to do \App\Record::find(1)->event_school->event

        //Want to do \App\Record::find(1)->event
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这是答案之一的输出

>>> \App\Record::find(3)->event_school->event
=> App\Event {#3035
     id: 1,
     name: "100 Meter",
     category_id: 1,
     created_at: null,
     updated_at: null,
     deleted_at: null,
   }
>>> \App\Record::find(3)->event
=> null
Run Code Online (Sandbox Code Playgroud)

aze*_*eós 6

每次遇到这种情况,我最终都会为数据透视表创建一个模型。这样做的另一个好处是您可以直接访问该表,而无需引入关系的另一端。

您已经有了外键的附加信息 ( notes)。如果您有 aSchool并且需要notes来自 a 的Event,但您不需要Event,则如果数据透视表有模型,则可以这样做。
当然,您可以使用 a 来完成,join而不需要模型。

这里的关键是扩展 fromPivot而不是Model. 它所做的事情之一就是将表名设置为单数。但你不能使用SoftDeletes(你真的需要它吗?这没有多大意义)

注意:数据透视模型可能不使用 SoftDeletes 特征。如果您需要软删除数据透视记录,请考虑将数据透视模型转换为实际的 Eloquent 模型。

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class EventSchool extends Pivot
{
    protected $guarded = ['id'];

    public function event()
    {
        return $this->belongsTo(Event::class);
    }

    public function school()
    {
        return $this->belongsTo(School::class);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,hasOneThrough与您需要的相反。您需要类似的东西belongsToThrough,但它不存在。您可以使用的是访问器

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Record extends Model
{
    use SoftDeletes;

    protected $guarded = ['id'];

    public function athlete()
    {
        return $this->belongsTo(Athlete::class);
    }

    function eventSchool()
    {
        return $this->belongsTo(EventSchool::class);
    }

    function getEventAttribute()
    {
        return $this->eventSchool->event;
    }
}
Run Code Online (Sandbox Code Playgroud)

\App\Record::find(1)->event就会完全按照你期望的那样做。