Laravel:从关系查询

时间:2015-10-22 17:34:19

标签: php laravel laravel-5.1 relationships

我试图从模型的belongsToMany关系查询的第一个结果中获取单个列值,因为我正在返回我希望的关系的->first()结果$code->reward->title会起作用,但事实并非如此。

我收到Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation错误

我想要做的是获取与特定代码相关联的当前奖励的标题 - code_reward数据透视表有{{1} }和valid_from日期,因为与代码相关联的奖励会随着时间的推移而变化,因此需要获得该代码的当前有效奖励。

这是我的代码:

型号:代码

expires_at

控制器:CodeController

public function rewards()
{
    return $this->belongsToMany('App\Reward')->withPivot('valid_from', 'expires_at')->withTimestamps();
}



public function reward()
{
    $now = Carbon::now();
    return $this->rewards()
        ->wherePivot('valid_from', '<', $now)
        ->wherePivot('expires_at', '>', $now)
        ->first();
}

查看:代码/索引

public function index()
    {
        $codes = Code::all();
        return view('codes/index')->with('codes', $codes);
    }

非常感谢任何帮助!

更新

不幸的是,以下两条建议(@foreach ($codes as $code) {{$code->id}} {{$code->reward->title}} @endforeach $code->reward()->title都会返回getRewardAttribute()错误。

如果我从Code-&gt; reward()方法中移除Trying to get property of non-object并在视图中将->first()替换为$code->reward->title,则将整个奖励模型回显为json,但是{{ 1}}仍会返回$code->reward->first()错误

更新2 如果我在视图中$code->reward->first()->title获得奖励标题,但如果我只是Trying to get property of non-object,我就不会!

并且{{dd($code->reward->title)}}{{$code->reward->title}}视图中按预期工作,因此控制器的$code->reward->title方法提供的代码集合可能不是这样的传递必要的数据或不以必要的格式传递?

解决 该问题是由索引视图中@Show循环中的@index之一返回$code->reward引起的!第一个没有,因此foreach工作,但一旦循环命中null它就崩溃了。 一旦我擦除并刷新数据库(并确保我的种子只添加有效数据!)它工作。执行dd()修复了问题。哎呀。

2 个答案:

答案 0 :(得分:3)

您的陈述失败,因为$code->reward->title告诉Laravel您已在名为reward()的方法中为您的代码模型定义了关系。但是,您的关系实际上是在方法rewards()中定义的。相反,reward()是您组建的模型上的自定义方法。将其称为方法而不是关系是获得所需内容的最快捷方式。

{{$code->reward()->title}}

正如@andrewtweber在下面指出的那样,您还可以将自定义reward()方法转换为属性访问器。要做到这一点,只需将该功能重命名为getRewardAttribute(),然后就可以像您最初那样在视图中调用它。

或者,您可以完全摆脱reward()方法并将所有逻辑移动到控制器,这可能更有意义。你必须使用受约束的预先加载才能将其拉下来。所以在你的控制器中你会有这样的东西:

$codes = App\Code::with(['rewards' => function ($query) {
    $query->wherePivot('valid_from', '<', $now)
          ->wherePivot('expires_at', '>', $now);
])->get();

当然,这会返回已过滤代码的所有。这是因为您无法在嵌套的急切关系中将limit应用为outlined here。所以在你看来,你必须做这样的事情:

{{$code->rewards->first()->title}}

然而,使用我的第一个解决方案会更简单,所以这完全取决于你。

答案 1 :(得分:0)

尝试在代码模型中设置此方法,因为查询构建器将valid_from和expired_at视为字符串,而不是日期?

public function getDates()
    {
        return ['valid_from','expired_at'];
    }