[hyperf]关于数据返回封装的另一种实现思考

PHP技术
454
0
0
2022-05-04
标签   Hyperf

数据返回都需要这样的封装,return $this->success($result);

class IndexController extends AbstractController
{
    public function index()
    {
        $user = $this->request->input('user', '399001');
        $method = $this->request->getMethod();

        $result = [
            'method'  => $method,
            'message' => "Hello {$user}.",
        ];

        return $this->success($result);
    }
}

一般的实现方式是在基类中实现success方法,但会让基类愈加庞大,于是改良使用trait,基类中引入trait,这样也挺好。

突然无聊想到的方法,感觉挺好的:定义返回服务类,使用 __call 在基类中调用服务类的方法。感觉能更方便的解耦耶,贴代码

ResponseService

<?php


namespace App\Service\Utils;


use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\ResponseInterface;

/**
 * API请求返回服务类
 *
 * Class ResponseService
 *
 * @package App\Service\Utils
 */ 
class ResponseService
{
    /**
     * @var int
     */ 
    private $http_code = 200;

    /**
     * http头部信息
     *
     * @var string[]
     */ 
    private $http_headers = [
        'Author' => 'Colorado',
    ];

    /**
     * 业务返回码
     * 组成结构:xx(业务模块) xx(业务子模块) xx(细化编码)
     * 举例:110101 11(APP模块)01(鉴权模块)01(登录失败)
     *
     * @var int
     */ 
    private $business_code = 100000;

    /**
     * 业务返回消息
     *
     * @var string
     */ 
    private $business_msg = 'ok';

    /**
     * @Inject
     * @var ResponseInterface
     */ 
    private $response;

    /**
     * 设置http状态码
     *
     * @param int $code
     *
     * @return $this
     */ 
    public function setHttpCode(int $code = 200): self{
        $this->http_code = $code;

        return $this;
    }

    /**
     * 设置http头部信息
     *
     * @param string $name
     * @param mixed  $value
     *
     * @return $this
     */ 
    public function setHttpHeader(string $name, $value): self{
        $this->http_headers[$name] = (string)$value;

        return $this;
    }

    /**
     * 成功数据返回
     *
     * @param mixed $data           返回数据
     * @param int   $business_code  业务返回码
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */ 
    public function success($data, int $business_code = 100000)
    {
        $this->business_code = $business_code;

        return $this->response($data);
    }

    /**
     * 失败返回
     *
     * @param string $error_msg      错误信息
     * @param mixed  $data           返回数据
     * @param int    $business_code  错误业务码
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */ 
    public function fail(string $error_msg = 'fail', $data = null, int $business_code = 999999)
    {
        $this->business_code = $business_code;
        $this->business_msg = $error_msg;

        return $this->response($data);
    }

    /**
     * 返回数据
     *
     * @param $data
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */ 
    private function response($data)
    {
        $this->response = $this->response->json($this->normalizeData($data))->withStatus($this->http_code);

        if (! empty($this->http_headers)) {
            foreach ($this->http_headers as $name => $value) {
                $this->response = $this->response->withHeader($name, $value);
            }
        }

        return $this->response;
    }

    /**
     * 标准化返回数据格式
     *
     * @param mixed $data  业务返回数据
     *
     * @return array
     */ 
    private function normalizeData($data): array{
        return [
            'code'      => $this->business_code,
            'data'      => $data,
            'message'   => $this->business_msg,
            'timestamp' => time(),
        ];
    }
}

基类AbstractController

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */ 
namespace App\Controller;

use App\Service\Utils\ResponseService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;

/**
 * Class AbstractController
 * @method ResponseService setHttpCode(int $code = 200)
 * @method ResponseService setHttpHeader(string $name, $value)
 * @method success(mixed $data, int $business_code = 100000)
 * @method fail(string $error_msg = 'fail', mixed $data = null, int $business_code = 999999)
 * @package App\Controller
 */ 
abstract class AbstractController
{
    /**
     * @Inject
     * @var ContainerInterface
     */ 
    protected $container;

    /**
     * @Inject
     * @var RequestInterface
     */ 
    protected $request;

    /**
     * @Inject
     * @var ResponseInterface
     */ 
    protected $response;

    /**
     * @param $name
     * @param $arguments
     *
     * @return mixed
     */ 
    public function __call($name, $arguments)
    {
        if (method_exists(ResponseService::class, $name)) {
            return make(ResponseService::class)->{$name}(...$arguments);
        }
    }
}

使用demo

控制器中

class IndexController extends AbstractController
{
    public function index()
    {
        $user = $this->request->input('user', '399001');
        $method = $this->request->getMethod();

        $result = [
            'method'  => $method,
            'message' => "Hello {$user}.",
        ];

        // 成功返回  
        return $this->success($result);
        // 失败返回  
        return $this->fail('失败啦');
        // 设置http状态码  
        return $this->setHttpCode(201)->success($result);
        return $this->setHttpCode(500)->fail('服务器挂了');
        // 设置http头部信息  
        return $this->setHttpHeader('server', 'hyperf-server')->success($result);
    }
}

其他地方,如ExceptionHandler

使用make该类即可调用类的方法

class ValidationExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        $this->stopPropagation();
        $body = $throwable->validator->errors()->first();

        return make(ResponseService::class)->fail($body);
    }

    public function isValid(Throwable $throwable): bool{
        return $throwable instanceof ValidationException;
    }
}