拉拉维尔有许多反向关系问题



让我们设置一个示例:

我有一个显示所有发票的页面。

网站管理员可以通过搜索他们的名字或姓氏来过滤结果。

发票模型

public function clients()
{
return $this->belongsTo('AppClient');
}

客户端模型

public function invoices() {
return $this->hasMany('AppInvoice');
}

假设管理员希望按客户筛选发票,并键入例如"Jhon">

我的控制器:

1-选择Client where name LIKE'Jhon'或where lastname LIKE'Jhon'

2-如果$query返回一个数组,其中有很多客户端的名称为Jhon。

如何使用该关系为该客户获取发票

您可以同时使用这两种方法,具体取决于最适合的方法。

发票(whereHas(:

Invoice::whereHas('client', function ($query){
$query->where('name', 'like', 'Jhon')
->orWhere('lastname', 'like', 'Jhon');
})->get();

客户(平面地图+发票关系(:

Client::where('name', 'like', 'Jhon')
->orWhere('lastname', 'like', 'Jhon')
->get()
->flatMap->invoices;

请记住,第二个选项会受到N+1的影响,除非在执行查询(->get(((之前调用with('invoices')

你应该用它们所代表的事物的单数或复数形式来命名你的关系,以免在以后的项目开发中迷失方向。在您的情况下,

public function clients() {
return $this->belongsTo('AppClient', 'client_id');
}

应该是单数,因为发票只属于一个客户:

public function client() {
return $this->belongsTo('AppClient', 'client_id');
}

现在,为了真正回答您的问题,由于您正在列出发票,我建议您从您的发票模型开始。类似的东西会起作用:

$invoices = Invoice::with('client')->where(function($q){
$q->where('firstname', 'LIKE', 'Jhon');
$q->orWhere('lastname', 'LIKE', 'Jhon');
})->get();

注意with('client'),它会很有用,因为它会急切地加载所有发票的客户端,这样您就不会在foreach的每次迭代中都得到另一个查询。关于热切加载的文档可在此处获得

你还可以做另一件事:不用"like",用"REGEXP"。

$invoices = Invoice::with('client')->where(function($q){
$q->where('firstname', 'REGEXP', '([[:<:]])Jhon');
$q->orWhere('lastname', 'REGEXP', '([[:<:]])Jhon');
})->get();

它将为您提供每个人的发票,这些人的名字或姓氏以Jhno开头。用"Jhon"这个词没用,但在很多情况下非常有用:"J"会找到每个Jack、Jhon、John、Joe。。。

最后,我在示例中使用了with('client'),因为我假设您更正了关系的名称。如果没有,您应该使用"客户",因为它是发票模型中关系的名称:(

请记住,在我看来,Toyi是最好的方法。我只是想让这件事尽可能简单,但他100%支持Eagle Loading,因为它更高效。

因此,您使用的是一对多关系,其中您的客户模型是父模型,但现在您使发票模型反向,因此首先您必须确保每个发票都有一个整数"client_id",用于存储每个发票上的每个客户id。我也只是为了安全,并确保它看起来是正确的id设置你的模型这样。

客户端模型

public function invoices() {
return $this->hasMany('AppInvoice', 'client_id');
}

发票模型

public function clients() {
return $this->belongsTo('AppClient', 'client_id');
}

然后在你的控制器中,你会像这样提取数据。

$client = Client::where('name','like', '%' . Input::get('name') . '%')->orWhere('lastname', 'like', '%' . Input::get('name') . '%')->get();
foreach($client->invoices as $invoice) {
echo $invoice->title; //Or What ever data you need to pull from your invoice.
}

请注意,我还添加了将该输入添加到orWhere和where语句的方式。请记住,"%"有助于检查用户输入框中的意外%。

使用热切加载

更新到这篇文章我看到你有以下代码:

$invoices = Facture::with('client')->where(function($q) { 
$key = Input::get('client'); 
$q->where('nom', 'LIKE', '%'.$key.'%'); 
$q->orWhere('prenom', 'LIKE', '%'.$key.'%'); 
})->get();

我要做的是,我会像这样传递输入,它可能会修复你的错误。

$key = Input::get('client');
$invoices = Facture::with('client')->where(function($q) or ($key) {  
$q->where('nom', 'LIKE', '%'.$key.'%'); 
$q->orWhere('prenom', 'LIKE', '%'.$key.'%'); 
})->get();

这背后的原因是,无论出于何种原因,Eager加载都无法从外部放置字符串和变量,所以我通过将变量与函数一起传递给它,并在$invoices之前输入$key。如果这有道理的话。干杯,希望这对你有用。

最新更新