Yii2通过自定义RequestParser对请求数据进行预处理

在项目中,后台接口输出的数据键遇到多个单词统一转换为了驼峰,前端请求的json数据中的键同样是驼峰,但是数据库里的字段都是用的小写字母加下划线去分割,这样表单提交数据给AR模型直接load()使用就有问题,所以在接收到数据之后,应该做一下预处理,将数据中驼峰转换成下划线加小写字母。

在Yii2中通过实现RequestParserInterface接口,自定义一个RequestParser来解决这个问题。

解决

在根目录新建一个components组件文件夹,新建一个RequestParamsParser.php文件,在官方yii\web\JsonParser解析器的基础上做一些修改,代码如下:

<?php

namespace app\components;

use yii\base\InvalidArgumentException;
use yii\helpers\Json;
use yii\web\BadRequestHttpException;
use yii\web\RequestParserInterface;

class RequestParamsParser implements RequestParserInterface
{
    public $asArray = true;
    public $throwException = true;


    /**
     * Parses a HTTP request body.
     * @param string $rawBody the raw HTTP request body.
     * @param string $contentType the content type specified for the request body.
     * @return array parameters parsed from the request body
     * @throws BadRequestHttpException if the body contains invalid json and [[throwException]] is `true`.
     */
    public function parse($rawBody, $contentType)
    {
        try {
            $parameters = Json::decode($rawBody, $this->asArray);
            if($parameters === null) {
                return [];
            } else {
                $this->upperToUnderline($parameters);
                return $parameters;
            }
        } catch (InvalidArgumentException $e) {
            if ($this->throwException) {
                throw new BadRequestHttpException('Invalid JSON data in request body: ' . $e->getMessage());
            }
            return [];
        }
    }

    // 驼峰转下划线
    public function upperToUnderline(&$array)
    {
        foreach ($array as $key => &$value) {
            if(!is_int($key)) {
                // 关联数组
                $newKey = strtolower(preg_replace('/([A-Z])/', '_$1', $key));
                if($key !== $newKey) {
                    $array[$newKey] = $value;
                    unset($array[$key]);
                    if(is_array($array[$newKey])) {
                        $this->upperToUnderline($array[$newKey]);
                    }
                } elseif(is_array($value)) {
                    $this->upperToUnderline($value);
                }
            } else {
                // 数字数组
                $this->upperToUnderline($value);
            }

        }
    }

}

修改配置

修改web.php下的componentsrequest下的parsers配置为刚才新建的解析器:

'components' => [
    'request' => [
        'parsers' => ['application/json' => 'app\components\RequestParamsParser',],
        ...
    ],
    ...
]

测试

这样请求body中的json数据就会被解析器预处理,执行:

$data = Yii::$app->getRequest()->getBodyParams();
var_dump($data);

打印处理后的结果:

自定义RequestParser处理结果

总结

在Yii2中通过自定义RequestParser可以对请求中的数据进行统一预处理,这样就避免了在每个接口中进行重复的操作了,非常方便。

发表评论

电子邮件地址不会被公开。 必填项已用*标注