Yii2 Active Record JSON响应,类型转换问题

时间:2016-08-02 15:32:26

标签: php json yii yii2

我在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代理表字段,它只返回作业表字段这里是从上面删除后的响应 - > asArray()查询。

{
"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是整数。

有没有人遇到同样的问题?非常感谢您的帮助。 提前谢谢。

3 个答案:

答案 0 :(得分:10)

我想确保实际情况如此。我已经用非常相似的查询测试了这个,我的结果非常相似:

  while($r = mysql_fetch_assoc($query)) {
    $root_names[] = $r;
   }
  echo json_encode(['root_name'=>$root_names]);

在我的情况下,我也将所有类型都作为字符串。因此,如果您要使用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

在Controller中你(一如既往)传递这个对象:

// 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;
}

然后在Viewer中你可以像这样访问值(正确的类型转换):

$data = User::getData();

return $this->render('user', [
            //...
            'data' => $data
        ]);

所以,对于ID检查:

$data->query['columnName'];

您将收到回复($data->query['id'] === 10 ? exit('ok') : exit('nok')); (类型转换:整数,值:10)。

答案 1 :(得分:7)

这是预期的行为,也是documented

  

注意:虽然此方法可以节省内存并提高性能,但它更接近较低的DB抽象层,您将失去大多数Active Record功能。一个非常重要的区别在于列值的数据类型。在Active Record实例中返回数据时,将根据实际列类型自动对列值进行类型转换;另一方面,当您在数组中返回数据时,列值将是字符串(因为它们是PDO的结果,没有任何处理),无论它们的实际列类型如何。

对于第二个问题,要检索活动记录类中的其他字段,您必须在类中为它们创建其他属性:

class MyRecord extends \yii\db\ActiveRecord
{
    public $first_name;
    public $last_name;

    // ...
}

答案 2 :(得分:1)

方法“ asArray”会将所有变量的类型转换为字符串。 因此,您不应使用此功能。

您可以在文档中找到正确的解决方案:https://www.yiiframework.com/doc/guide/2.0/en/rest-resources#overriding-extra-fields

您需要在URI中对API请求使用“字段”和“扩展”参数。

例如:http://localhost/posts?fields=id,title&expand=author

首先添加与模型的关系:

    /**
     * @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。很抱歉为您发布尸体,但最近我遇到了同样的问题