如何将带关联关系的Yii2 ActiveRecord查询结果转为JSON?
我来帮你梳理下在Yii2里把关联的ActiveRecord转成支持特殊内容的JSON的具体方案,一步步来:
将Yii2关联ActiveRecord转换为含特殊内容的JSON方案
1. 先确认模型关联关系是否正确
首先得保证TextAreas模型(对应textAreas表)里,已经正确定义了和TextCtrl(对应text表)的一对多关联:
// models/TextAreas.php class TextAreas extends ActiveRecord { // ... 其他模型代码 /** * 获取当前文本区域关联的多语言文本 */ public function getTexts() { return $this->hasMany(TextCtrl::class, ['textControllerId' => 'id']); } }
2. 查询时预加载关联数据
查询的时候一定要用with('texts')预加载关联数据,避免讨厌的N+1查询问题:
// 查询单条记录 $textArea = TextAreas::find() ->where(['id' => $targetId]) ->with('texts') ->one(); // 查询多条记录 $textAreaList = TextAreas::find() ->with('texts') ->all();
3. 转换为JSON的几种实用方式
方式一:直接用Yii自带的Json助手类编码
Yii的yii\helpers\Json类会自动处理ActiveRecord对象和关联数据,而且能正确转义数学公式这类特殊字符(比如LaTeX符号、特殊Unicode字符),非常省心:
use yii\helpers\Json; // 单条记录转JSON $singleJson = Json::encode($textArea); // 多条记录转JSON $listJson = Json::encode($textAreaList);
方式二:自定义输出字段(推荐)
如果需要控制输出的字段(比如只返回textAreas的核心字段,以及texts里的lang和content),可以重写模型的fields()方法来定制输出结构:
// models/TextAreas.php public function fields() { // 先继承父类的默认字段(比如id、你自己定义的其他字段) $fields = parent::fields(); // 把关联的texts字段加入输出,同时只保留lang和content $fields['texts'] = function ($model) { return array_map(function($text) { return [ 'lang' => $text->lang, 'content' => $text->content ]; }, $model->texts); }; // 移除不需要的字段(比如创建时间、更新时间这类内部字段) unset($fields['created_at'], $fields['updated_at']); return $fields; }
之后再编码就会得到你想要的精简结构:
$customJson = Json::encode($textArea);
方式三:手动组装数组后编码
如果需要完全自定义JSON结构,可以手动把数据组装成数组再转JSON,灵活性最高:
$customData = [ 'id' => $textArea->id, // 这里添加textAreas的其他字段 'multilingual_content' => [] ]; foreach ($textArea->texts as $textItem) { $customData['multilingual_content'][] = [ 'language' => $textItem->lang, 'content' => $textItem->content ]; } $manualJson = Json::encode($customData);
4. 几个关键注意事项
- 特殊字符不用额外处理:Yii的
Json::encode会自动处理数学公式里的\、^、_等特殊符号,只要数据库里存的是原始内容就行。 - 一定要预加载关联:如果不用
with('texts'),转JSON时关联的多语言数据不会被包含进去,除非你在fields()里延迟加载,但那样会触发N+1查询,性能很差。 - 编码选项可以按需调整:如果想保留Unicode字符不转义,或者格式化JSON方便阅读,可以加编码参数:
$formattedJson = Json::encode($textArea, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
内容的提问来源于stack exchange,提问作者Christiaan Van Vliet
相关产品推荐
相关产品推荐

