我有一个表posts
,此表包含一些列,例如pst_id
,pst_title
,pst_content
,pst_category_id
等。我想在json输出上用一些更好的名字来表示这些字段,实际上我正在尝试从列名中删除前缀pst_
。
我测试了多种方法。起初我尝试在DB层上为这些列创建别名,例如Post::select(['pst_id as id'])->get()
。这个想法通常很糟糕,因为它使得列名在整个软件中不一致(每个开发人员可能有一个命名字段的约定)。所以我坚持找到一种方法来命名模型层上的列。
下一个解决方案是使用Accessors
和Mutators
。虽然它涵盖了以前的问题,但是每个模型实现20种方法真的很难! 20x100~2000方法!!! :/
我测试的最后一个解决方案是使用https://github.com/jarektkaczyk/eloquence的mappable
功能。这非常好,我可以将所有旧字段放到$hidden
属性中,并将新字段添加到$appends
以显示输出。但是这个解决方案也存在问题。如果我将所有新字段添加到$appends
,当我使用select
语句选择某些列时,未选择的列将在输出中显示null
值:|。好吧,我试图在基础模型上覆盖mappedselect
和parseMappings
方法,以便动态地向$appends
添加新名称,但它并不能让我满意。事实上,它在使用时变得非常棘手,我不确定团队是否可以接受并轻松使用它。
所以这就是问题所在:“有没有办法在输出中重命名列的名称以进行雄辩?”。 GoLang有一个非常好的功能,称为结构标签。您可以为结构定义一些标记,例如:
type Post struct {
Pst_id int `json:"id"`
Pst_title string `json:"title"`
Pst_content string `json:"content"`
}
当你使用Post
生成一个json.Marshal
结构的json时,根据标签,它会给你一个像这样的json:
{
"id": 23,
"title": "Custom Field Tags for Eloquent",
"content": "I tried a lot of things, but they are hard. I'm a programmer so I'm lazy! What can I do?",
}
我认为我们在php世界中没有这样的东西,但有没有办法使用后面的doctrine's annotation概念来实现Go中的标记结构?
欢迎任何评论和想法!
答案 0 :(得分:3)
第一步是在这些模型上覆盖几个方法。第一种方法是getAttribute()
,当您访问模型的属性时可以调用它,以便您可以访问它。您希望能够在没有pst_
前缀的情况下访问该属性,以便执行以下操作:
public function getAttribute($key)
{
if(array_key_exists($prefixedKey = 'pst_'.$key, $this->attributes)) {
return $this->attributes[$prefixedKey];
}
return parent::getAttribute($key);
}
然后为了确保在转换为json时键不具有前缀,您将覆盖输出json时调用的attributesToArray()
方法,并且还会尊重您的$hidden
, $visible
,$casts
和$dates
数组。那将是这样的:
public function attributesToArray()
{
$attributes = parent::attributesToArray();
$mutated = [];
foreach ($attributes as $key => $value) {
$mutated[preg_replace('/^pst_/', '', $key)] = $value;
}
return $mutated;
}
要实现这些,您可以使用实现这些方法的抽象类扩展Model
类,并让您的类扩展该基类或使用这些方法创建特征,并让您的类实现该特征。
答案 1 :(得分:2)
我可能会使用联盟中的Fractal Transformer。
您基本上创建了一个映射类并将其应用于集合。
Transformer类看起来像这样
<?php
namespace App;
use App\Post;
use League\Fractal;
use League\Fractal\TransformerAbstract;
class PostTransformer extends TransformerAbstract{
public function transform(Post $post)
{
return [
'id' => (int) $post->pst_id,
'title' => $post->pst_name,
'content' => $post->pst_uuid,
];
}
}
然后在您的控制器中或您转换集合的地方。
$posts = Post::all();
$manager = new Manager();
$manager->setSerializer(new CursorSerializer());
$resource = new Collection($posts, new PostTransformer());
$formattedCollection = $manager->createData($resource);
文档相当不错,实现它非常简单。