Laravel:每当我返回一个模型时,总是返回与它的关系

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25674143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 10:02:37  来源:igfitidea点击:

Laravel: Whenever I return a model always return a relationship with it

laravellaravel-4modeleloquent

提问by Mathius17

I have 2 tables:

我有2张桌子:

User        |   Doctor
----------  |  ----------
id          |  id
email       |  user_id
name        |  signature
last_name   |  photo
password    |  description
date_birth  |

Every Doctoris related to a User, but every Usermay not be related to a Doctor. I did it this way because I didn't want to use Single Table Inheritance and end up with a bunch of NULLfields.

EveryDoctor与 a 相关User,但 everyUser可能不与 a 相关Doctor。我这样做是因为我不想使用单表继承并最终得到一堆NULL字段。

Is there a way to make, something like this?

有没有办法制作,像这样?

// Instead of
$doctor = Doctor::with('User')->find(1);
$doctor->user->name;
// This
$doctor = Doctor::find(1);
$doctor->name;

P.S: Didn't know what to put in the title, what should I put instead so it is more relevant to the question?

PS:不知道在标题中放什么,我应该放什么,以便与问题更相关?

采纳答案by Mathius17

I ended up using Accessorsand $appendsand it worked as intended. It even appears in the docs Appends + Accessors (at the end). Thanks to Cyrode, whom showed me the Accessors (didn't know they exised).

我最终使用了Accessors并且$appends它按预期工作。它甚至出现在文档 Appends + Accessors(最后)中。感谢 Cyrode,他向我展示了 Accessors(不知道它们存在)。

I could've not use the $appendsarray, but you need it if you're returning the model in JSON.

我不能使用该$appends数组,但如果您以 JSON 形式返回模型,则需要它。

As Jarek Tkaczyk deczosuggested, you should use withproperty when you go with this approach, otherwise whenever you load multiple Doctormodels and call anything Userrelated, you end up with a db query (per each Doctorinstance) -> n+1 issue

正如 Jarek Tkaczyk deczo 所建议的,with当你采用这种方法时应该使用属性,否则每当你加载多个Doctor模型并调用任何User相关的东西时,你最终会得到一个 db 查询(每个Doctor实例)-> n+1 问题

Doctor class ended up looking like this:

博士班最终看起来像这样:

<?php

class Doctor extends Eloquent {

    protected $table = 'doctors';

    protected $with = ['user'];

    protected $appends = ['first_name','last_name','email','date_of_birth'];

    protected $hidden = ['signature','user'];

    public function user(){

        return $this->belongsTo('User');

    }

    public function getFirstNameAttribute() {

        return $this->user->first_name;

    }

    public function getLastNameAttribute() {

        return $this->user->last_name;

    }

  public function getEmailAttribute() {

      return $this->user->email;

  }

}

I had to put userinside the $hiddenarray or it would show up whenever I retireved Doctor(Besides I only needed some things of User, not everything)

我只好把user里面$hidden阵列或者它会显示,每当我retireved Doctor(除了我只需要对一些事情的User,不是一切)

回答by Aken Roberts

You can specify default eager loaded relationships using the $withproperty on the model.

您可以使用$with模型上的属性指定默认的预加载关系。

class Doctor extends Eloquent {

    protected $with = ['user'];

    // ...
}

(The property might need to be public, I forget. Laravel will yell at you if it does.)

(该属性可能需要公开,我忘记了。如果公开,Laravel 会冲你大喊大叫。)

You will still need to use $doctor->user->name, but the relationship will be automatically loaded without you needing to explicitly call it. If you reallywant to use the $doctor->namesyntax, you could create Accessorsfor those column names, which would then fetch and pass the appropriate User relationship columns.

您仍然需要使用$doctor->user->name,但关系将自动加载而无需您显式调用它。如果你真的想使用的$doctor->name语法,你可以创建访问者的那些列名,那么这将获取,并通过适当的用户关系的列。

回答by Jarek Tkaczyk

Yes, there is a way. Is it good design? Maybe, maybe not. Hard to say from your short description.

是的,有办法。这是好的设计吗?也许,也许不是。从你的简短描述很难说。

// Doctor model
public function __get($key)
{
    // check deafult behaviour
    if (is_null($value = parent::__get($key))) return $value;

    // if null, let's try related user
    return $this->user->__get($key);
}

public function __set($key, $value)
{
    $user = $this->user;

    // first try user
    if (array_key_exists($key, $user->getAttributes()) || $user->hasSetMutator($key))
    {
        return $user->__set($key, $value);
    }

    // then default
    parent::__set($key, $value);
}

This way you can do this:

这样你就可以做到这一点:

$doctor->name; // returns $doctor->user->name; unless you have accessors for name

$doctor->name = 'Some Name';
// then
$doctor->user->name; // 'Some Name';

// so finally push instead of save, in order to save related user too
$doctor->push();

Mind that this is pretty simple example, for brevity. There is a chance, that existing attribute of Doctormodel is null, so $this->user->__get()should not be called, for example. So to make it fully reliable, you need to check hasGetMutator(), relationsand so on. Check Models __getand __setfor details.

请注意,为简洁起见,这是一个非常简单的示例。例如,Doctor模型的现有属性有可能是null,因此$this->user->__get()不应调用。因此,要使其完全可靠,您需要检查hasGetMutator()relations等等。检查Models__get__set详细信息。