【问题标题】:Yii2 Active Record JSON response, type casting issueYii2 Active Record JSON 响应,类型转换问题
【发布时间】:2016-08-02 15:32:25
【问题描述】:

我在 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 是整数。

有人遇到同样的问题吗?您的帮助将不胜感激。 提前致谢。

【问题讨论】:

    标签: php json yii yii2


    【解决方案1】:

    我想确保确实如此。我自己用非常相似的查询对此进行了测试,结果非常相似:

    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'];
    

    所以,对于身份检查:

    ($data->query['id'] === 10 ? exit('ok') : exit('nok'));
    

    您将收到回复ok(类型转换:整数,值:10)。

    【讨论】:

    • 应该是自动类型转换而不是手动进行,有什么解决方法吗?
    • 不幸的是,根据开发人员的说法,由于它是default behavior,我看不到任何改变它的方法(或者至少我不知道)。但它可能是一个错误或什么的。我也使用前缀,习惯它并不难。
    • 但如果你只使用 all() 而不是 asArray()->all() 它会返回有效的数据类型,但问题是它只返回单个表数据,它会跳过关系和连接。
    • 是的。我其实不知道为什么会这样。它看起来很奇怪,到目前为止似乎没有任何帮助(尝试了ArrayHelper:: 和一些不同的查询)。如果我能找到其他解决方案,我会告诉你。 :) 现在我想这个临时解决方案应该仍然适合。
    • @KamranKhatti 好的,所以我找到了一种方法来做到这一点,但这会极大地改变您编写的代码。我希望你没问题。请等到我的电脑有空。
    【解决方案2】:

    这是预期行为,也是documented:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      例如: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(),
          ]);
      }
      

      附:很抱歉发布了 necroposting,但我最近遇到了同样的问题

      【讨论】:

      • na necroposting 很好,有时人们会将隐藏的宝藏发布到旧帖子中!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多