雄辩的ORM - 为什么Laravel不认为这两个对象是一样的?

Eri*_*ich 0 php laravel

我对Laravel来说还是很新的.在我能够在两个模型之间定义多个Eloquent关系之后,我注意到可以将实例传递给它不属于的父模型实例中的方法.所以我认为在方法本身内强制执行这种关系可能会很好.

在Organization.php中:

/**
 * @param \App\Contact The Contact to delete
 */
public function deleteContact(Contact $contact)
{
    if($contact->organization == $this)
    {
        $this->contacts->find($contact->id)->delete();
    }
    else
    {
        dd('Error: Contact ' . $contact->fname . ' ' . $contact->lname . ' #' . $contact->id . ' does not belong to Organization ' . $this->name . ' #' . $this->id);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我传递实际属于的联系人时,我一直收到自定义错误消息,或者至少我认为他们做了!当我测试关系时tinker,它id为Bob和Bob的组织返回了不同的实例.

>>> $org = Organization::find(17)
=> App\Organization {#2929
     id: 17,
     name: "Test Org",
     primary_contact_id: 33,
   }
>>> $org->contacts
=> Illuminate\Database\Eloquent\Collection {#2925
     all: [
       App\Contact {#2926
         id: 33,
         organization_id: 17,
         fname: "Alice",
         lname: "Abbot",
       },
       App\Contact {#2943
         id: 34,
         organization_id: 17,
         fname: "Bob",
         lname: "Baker",
       },
     ],
   }
>>> $bob = Contact::find(34)
=> App\Contact {#2940
     id: 34,
     organization_id: 17,
     fname: "Bob",
     lname: "Baker",
   }
>>> $bob->organization == $org
=> false
>>> $bob->organization
=> App\Organization {#2932
     id: 17,
     name: "Test Org",
     primary_contact_id: 33,
   }
Run Code Online (Sandbox Code Playgroud)

显然它正在比较两个不同的实例.为了解决这个问题,我不得不改变有效的条件$contact->organization->id == $this->id.然而,这样做的雄辩要少得多.

  1. 为什么要生成两个不同的实例?这些是后续调用,应该(理论上)产生相同的实例(或者我认为).

  2. 这甚至是必要的额外保护吗?由于内部代码,我们至少部分受到保护,但不能用try/ 可以catch优雅地处理违规 - 我需要先测试,然后尝试删除.(如果传递的Contact是不是一个有效的相关实例的Organization,find()回报率null,导致PHP错误,也不例外.)是否有更好的方式来做到这一点,还是我这得太多?

Moz*_*mil 6

从Laravel的角度来看,我们不能仅仅依靠等式运算符来比较对象,这在Eloquent模型的情况下可能非常不可靠且难以比较.

正如@Devon和@N Mahurin也正确地说,如果你比较更可预测的stdClass对象,使用相等运算符来比较对象会很有效.

这是当时的一场斗争.幸运的是,这部PR在5.3中成为Laravel的核心.

要知道两个模型是否基本相同,Laravel会检查是否

  1. 主键是相同的
  2. 表格是一样的
  3. 数据库连接是相同的.

基于此,我们可以假设我们正在比较两个相等的行.因此,在您的情况下,以下应该工作:

$bob->organization->is($org);
Run Code Online (Sandbox Code Playgroud)

请参阅比较模型的文档.