如何覆盖hasMany关系的结果?

时间:2016-06-06 23:08:21

标签: php laravel eloquent

想象一下,我有几个像这样的简单对象:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{

    public function posts()
    {
        return $this->hasMany("App\Post");
    }
}

class Post extends Model
{
    public function user()
    {
        return $this->belongsTo("App\User");
    }
}

我们会说\App\Post对象有一个名为jsondata的数据库列,其中包含JSON编码的数据。当我想在解码该列的视图中显示用户的帖子时,我需要在控制器中执行此操作:

$posts = Auth::user()->posts()->get();
foreach ($posts as $post) {
    $post->jsondata = json_decode($post->jsondata);
}
return view("user.show", ["posts"=>$posts]);

有没有办法避免我的控制器中的foreach循环并在较低级别进行JSON解码?

我确信我可以在App\User::posts()中执行此操作,但这对我需要显示解码数据的其他地方没有帮助。我尝试定义App\Post::get()来覆盖父方法,但它不起作用,因为hasMany()似乎根本不返回模型的实例。

2 个答案:

答案 0 :(得分:3)

它可以在不同的地方/方式完成,但如果您希望此数据始终在每个地方解码并且每次检索Post模型或仅仅是mutator时,我建议在模型中使用此属性的附加。

请参阅https://laravel.com/docs/master/eloquent-mutators

在您的模型中,您可以定义:

protected $appends = [
    'name_of_property'
];

// calculated / mutated field
public function getNameOfPropertyAttribute()
{
    return jsondecode($this->jsondata);
}

然后,您可以随时访问此属性:

$后&GT; name_of_property

请注意从CamelCase到snake_case的转换以及从getNameOfPropertyAttribute转换为&gt; name_of_property。默认情况下,您需要遵守此约定以使其自动运行。

您可以将name_of_property和NameOfProperty替换为您想要的内容。

干杯

答案 1 :(得分:0)

亚历山德罗的答案似乎是最好的答案;它向我指出了关于访问器和变换器的Laravel文档。但是,在页面底部附近是一种更简单的方法:attribute casting

在典型的Laravel方式中,他们实际上并未列出您可以投射的所有类型,但他们确实提到能够将JSON格式的数据库列转换为数组。稍微戳了一下the source,事实证明你可以对一个对象做同样的事情。所以我的答案,添加到App\Post控制器,是:

/**
 * The attributes that should be casted to native types.
 *
 * @var array
 */
protected $casts = ["jsondata"=>"object"];

这会自动进行解码并使原始数据可用。作为奖励,它在保存时会自动执行JSON编码!