从关系查询的first()结果中获取列值


Laravel: Get column value from first() result of relationship query

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

我得到一个Relationship method must return an object of type Illuminate'Database'Eloquent'Relations'Relation错误

我要做的是获得链接到特定代码的当前奖励的标题- code_reward数据透视表具有valid_fromexpires_at日期,因为链接到代码的奖励将随着时间的推移而变化,因此需要获得该代码的当前活动奖励。

下面是我的代码:

<<p> 模型:代码/strong>
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();
}

控制器:CodeController

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()->titlegetRewardAttribute()返回Trying to get property of non-object错误。

如果我从Code->reward()方法中删除->first(),并将$code->reward->title替换为视图中的$code->reward->first(),它将整个奖励模型作为json响应,但是$code->reward->first()->title仍然返回Trying to get property of non-object错误

更新2 如果我在视图中执行{{dd($code->reward->title)}},我就会获得奖励标题,但如果我只执行{{$code->reward->title}},我就不会!

AND $code->reward->title@Show视图中按预期工作,所以可能是控制器的@index方法提供的代码集合没有传递必要的数据或没有以必要的格式传递它?

这个问题是由索引视图中返回nullforeach循环中的$code->reward s之一引起的!第一个没有,因此dd()工作,但一旦循环遇到null,它就崩溃了。一旦我擦除并刷新数据库(并确保我的种子只添加有效的数据!),它就工作了。做{{$code->reward ? $code->reward->title : ''}}修复了这个问题。叽阿。

你的语句失败了,因为$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();

当然,这将返回所有过滤代码的。这是因为不能在嵌套的急切关系中应用sql limit。在你的视图中,你需要这样做:

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

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

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

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