我在Yii2中遇到了一个奇怪的问题。我有一个查询,它有一个与代理表的联接,以及作业与任务的(一对多)关系。它工作正常,但问题是它返回字符串中的所有内容。以下是查询:
$query = self::find()
->select("job.*, agent.first_name,agent.last_name")
->leftJoin('agent', 'job.agent_id = agent.id')
->with('tasks')
->asArray()
->all();
JSON编码结果:
{
"success": true,
"data": [
{
"id": "10",
"customer_id": "1",
"job_type": "normal",
"created": "2016-06-22 10:19:25",
"first_name": "Shayan",
"last_name": "",
"tasks": [
{
"id": "10",
"job_id": "10",
"title": "bring food",
"instruction": null,
"created": "2016-06-22 10:19:25",
},
{
"id": "10",
"job_id": "10",
"title": "bring pizza",
"instruction": null,
"created": "2016-06-22 10:19:25",
},
]
}
如果注意到id、customer_id和job_id等字段,它们都是整数,但返回为字符串。但是,如果我从上面的查询中删除->asArray(),它会返回有效的类型转换,但问题是它跳过了关系和leftJoin代理表字段,它只返回作业表字段。
{
"success": true,
"data": [
{
"id": 10,
"customer_id": 1,
"name": null,
"job_type": "normal",
"created": "2016-06-22 10:19:25",
},
如果您在上面的响应中注意到,它并没有完全跳过代理表first_name、last_name和关系数据任务,但id和customer_id是整数。
有人面临同样的问题吗?非常感谢您的帮助。提前谢谢。
我想确保事实确实如此。我自己用非常相似的查询进行了测试,结果非常相似:
array(2) {
[0]=>
array(5) {
["id"]=>
string(1) "1"
["name"]=>
string(5) "Admin"
// ...
}
// ...
}
在我的情况下,我还将所有类型都作为字符串。所以,如果你要用if ($data[0]['id'] === 1)
检查输入及其类型,你会得到false
的结果,因为它是string
。
但您需要做的是在变量之前添加(int)
,以便将其转换为不同的类型转换。这将是:(int) $data[0]['id']
。
那么var_dump((int) $data[0]['id']);
(在我的情况下)将给出int(1)
而不是string(1) "1"
。
您也可以签入条件:
((int) $data[0]['id'] === 1) ? exit('Integer') : exit('Not integer');
不写(int)
作为前缀将得到Not integer
的结果,而写前缀将产生Integer
。
如果你不想在每个函数中都写这些前缀,你可以写一些类似的东西:
$data[0]['id'] = (int) $data[0]['id'];
现在$data[0]['id']
在将来的使用中将是integer
。
新解决方案:
这个新的解决方案将返回一个带有数组的对象,而不仅仅是数组。
// Method that gives data back. In this case, user with ID == 10.
public static function getData()
{
$dataProvider = new ActiveDataProvider([
'query' => self::findOne(['id' => 10])->attributes
]);
return $dataProvider;
}
在控制器中,您(一如既往)传递此对象:
$data = User::getData();
return $this->render('user', [
//...
'data' => $data
]);
然后在查看器中,您可以访问如下值(正确的类型):
$data->query['columnName'];
因此,对于ID检查:
($data->query['id'] === 10 ? exit('ok') : exit('nok'));
您将得到响应ok
(typecast:integer,value:10)。
这是预期的行为,也有记录:
注意:虽然此方法节省了内存并提高了性能,但它更接近于较低的DB抽象层,您将失去大部分Active Record功能。一个非常重要的区别在于列值的数据类型。当您在活动记录实例中返回数据时,列值将根据实际列类型自动进行类型转换;另一方面,当您在数组中返回数据时,列值将是字符串(因为它们是PDO的结果,不需要任何处理),而不管它们的实际列类型如何。
对于第二个问题,要检索活动记录类中的附加字段,必须在类中为它们创建附加属性:
class MyRecord extends 'yii'db'ActiveRecord
{
public $first_name;
public $last_name;
// ...
}
方法"asArray"将所有变量的类型转换为字符串。因此,您不应该使用此选项。
您可以在文档中找到正确的解决方案:https://www.yiiframework.com/doc/guide/2.0/en/rest-resources#overriding-额外字段
您需要在API请求的URI中使用"字段"answers"扩展"参数。
例如:http://localhost/posts?fields=id,标题&expand=作者
首先添加与模型的关系:
/**
* @return 'yii'db'ActiveQuery
*/
public function getAuthor()
{
return $this->hasOne(Profile::class, ['id' => 'author_id']);
}
此外,您还需要将字段和extraFields方法添加到模型中:
public function fields()
{
return ['id', 'title'];
}
public function extraFields()
{
return ['author'];
}
以及变更响应:
public function actionIndex()
{
return new ActiveDataProvider([
'query' => Post::find(),
]);
}
p.S.很抱歉发布死讯,但我最近遇到了同样的问题