本篇概要:
1. Http Server;
1.1 控制器;
- 包含:RequestMapping 註釋、請求與響應、返回 JSON 格式、路由 path 參數、GET \ POST 參數獲取
- PhpStorm 安裝插件
- 新建
App/Http/Controller/ProductController.php
<?php
namespace App\Http\Controller;
use App\lib\MyRequest;
use function foo\func;
use Swoft\Context\Context;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Http\Server\Annotation\Mapping\Middleware;
use App\Http\Middleware\ControllerMiddleware;
/**
* 商品模塊
* // @Controller()
* @Controller(prefix="/product")
* 使用一箇中間件
* @Middleware(ControllerMiddleware::class)
*/
class ProductController{
/**
* 1.1.1 RequestMapping 註釋
*
* @RequestMapping(route="/product", method={RequestMethod::GET})
*/
public function prod_list(){
// 1.1.2 請求與響應
// 參考:https://www.swoft.org/documents/v2/core-components/http-server/#http-1
// 上下文對象:Contexts
// 獲取請求對象
$req = Context::mustGet()->getRequest();
// 獲取響應對象
$res = Context::mustGet()->getResponse();
// 返回內容
// return $res->withContent("abc");
// 1.1.3 返回 JSON 格式
// return $res->withContentType("application/json")->withContent("abc");
// 1.2 調用全局函數
// return $res->withContentType("application/json")
// ->withContent(json_encode([NewProduct(101, "測試商品"), NewProduct(102, "測試商品2")]));
return $res->withContentType("application/json")
->withData([NewProduct(101, "測試商品"), NewProduct(102, "測試商品2")]);
}
/**
* //@RequestMapping(route="/product/{pid}", method={RequestMethod::GET})
* 路由 path 參數前綴,正則控制路由參數
* 注入參數 Response,可能或造成參數過多
* 1.1.4 路由 path 參數
* @RequestMapping(route="{pid}", params={"pid"="\d+"}, method={RequestMethod::GET, RequestMethod::POST})
*/
public function prod_detail(int $pid, Response $response){
$p = NewProduct($pid, "測試商品");
//return \response()->withContentType("application/json")->withData([$p]);
// return $response->withContentType(ContentType::JSON)->withData([$p]);
// 1.3 此處返回值會調用中間件
// return [$p];
// 1.1.5 GET \ POST 參數獲取
// echo request()->get("type", "default type");
// if(request()->getMethod() == RequestMethod::GET){
// *1.5 JSON 參數轉實體對象
/** @var $product ProductEntity */
// $product = jsonForObject(ProductEntity::class);
// var_dump($product);
if(isGet()){
return $p;
}else if(isPost()) {
$p->pname = "修改產品" . request()->post('title', 'none');
return $p;
}
// *1.4 鏈式調用
// $my = new MyRequest();
// $my->if(isGet())
// ->then(function() use ($p){
// return $p;
// })
// ->if(isPost())
// ->then(function() use ($p){
// $p->pname = "修改產品" . request()->post('title', 'none');
// return $p;
// })
// ->getResult();
}
}
- 實例操作
# 終端進入項目目錄
cd /data/test/php/swoft/
# 啓動 Swoft
php ./bin/swoft http:start
# 返回
SERVER INFORMATION(v2.0.8)
********************************************************************************
* HTTP | Listen: 0.0.0.0:18306, Mode: Process, Worker: 6, Task worker: 12
********************************************************************************
HTTP Server Start Success!
# 瀏覽器訪問:http://localhost:18306/product
1.2 全局函數;
- 修改
App/Helper/Functions.php
<?php
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
require_once (__DIR__ . "/WebFunctions.php");
require_once (__DIR__ . "/OrderFunctions.php");
/**
* This file is part of Swoft.
*
* @link https://swoft.org
* @document https://swoft.org/docs
* @contact [email protected]
* @license https://github.com/swoft-cloud/swoft/blob/master/LICENSE
*/
function user_func(): string
{
return 'hello';
}
function NewProduct(int $pid, string $pname){
$p = new stdClass();
$p->pid = $pid;
$p->pname = $pname . $p->pid;
return $p;
}
function response($contentType=false){
if($contentType){
return Swoft\Context\Context::mustGet()->getResponse()->withContentType($contentType);
}
return Swoft\Context\Context::mustGet()->getResponse();
}
function request(){
return Swoft\Context\Context::mustGet()->getRequest();
}
function isGet(){
return request()->getMethod() == RequestMethod::GET;
}
function isPost(){
return request()->getMethod() == RequestMethod::POST;
}
function ip(){
$req = request();
if($req->server('http_x_forwarded_for')){
return $req->server('http_x_forwarded_for');
}else if($req->server('http_client_ip')){
return $req->server('http_client_ip');
}else{
$req->server('remote_addr');
}
}
// 事務封裝(也可以用 AOP)
function tx(callable $func, &$result=null){
\Swoft\Db\DB::beginTransaction();
try{
$result = $func();
\Swoft\Db\DB::commit();
}catch(Exception $exception){
$result = OrderCreateFail($exception->getMessage());
\Swoft\Db\DB::rollBack();
}
}
1.3 中間件;
- 參考:https://www.swoft.org/documents/v2/core-components/http-server/#heading13
- 新建
App/Http/Middleware/ControllerMiddleware.php
<?php
namespace App\Http\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Http\Message\Request;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Contract\MiddlewareInterface;
use Swoft\Http\Message\ContentType;
/**
* @Bean()
*/
class ControllerMiddleware implements MiddlewareInterface
{
/**
* Process an incoming server request.
*
* @param ServerRequestInterface|Request $request
* @param RequestHandlerInterface|Response $handler
* 放到控制器裏面進行對應,也可以設置全局的中間件
*
* @return ResponseInterface
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
/** @var $ret \Swoft\Http\Message\Response */
// response 對象
$ret = $handler->handle($request);
$data = $ret->getData();
//$p2 = NewProduct(10000, "中間件測試商品");
//$data[] = $p2;
if(is_object($data)){
return \response(ContentType::JSON)->withContent(json_encode($data));
}
return \response(ContentType::JSON)->withData($data);
}
}
*1.4 鏈式調用;
- 新建
App\lib\MyRequest.php
<?php
namespace App\lib;
class MyRequest{
private $result;
private $do = false;
function if($bool){
$this->do = $bool;
return clone $this;
}
function then(callable $func){
if($this->do){
$this->result = $func();
$this->do = !$this->do;
}
return clone $this;
}
function getResult(){
return $this->result;
}
}
*1.5 JSON 參數轉實體對象;
- 新建
App\lib\ProductEntity.php
<?php
namespace App\lib;
class ProductEntity{
private $prod_id;
private $prod_name;
private $prod_price;
/**
* @return mixed
*/
public function getProdId(){
return $this->prod_id;
}
/**
* @param mixed $prod_id
*/
public function setProdId($prod_id): void{
$this->prod_id = $prod_id;
}
/**
* @return mixed
*/
public function getProdName(){
return $this->prod_name;
}
/**
* @param mixed $prod_name
*/
public function setProdName($prod_name): void{
$this->prod_name = $prod_name;
}
/**
* @return mixed
*/
public function getProdPrice(){
return $this->prod_price;
}
/**
* @param mixed $prod_price
*/
public function setProdPrice($prod_price): void{
$this->prod_price = $prod_price;
}
}
- 新建
App/Helper/WebFunction.php
<?php
/**
* @param $class
* $class 不是實例化對象,而是 function 名稱
* 需要用到反射
*/
function jsonForObject($class=""){
$req = request();
try {
$contentType = $req->getHeader('content-type');
if (!$contentType || false === stripos($contentType[0], \Swoft\Http\Message\ContentType::JSON)) {
return false;
}
// 獲取原始的 body 內容
$raw = $req->getBody()->getContents();
// 把得到的對象和 $class 做比對
$map = json_decode($raw, true); // kv 數組
if($class == "") return $map; // 實現 2.0.2 版本前的 request()->json() 方法
$class_obj = new ReflectionClass($class); // 反射對象
$class_instance = $class_obj->newInstance(); // 根據反射對象創建實例
// 獲取所有方法(公共方法)
$methods = $class_obj->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method){
// 正則獲取 set 方法
if(preg_match("/set(\w+)/", $method->getName(), $matches)){
// echo $matches[1] . PHP_EOL; // 得到方法名 ProdId,ProdName,ProdPrice
invokeSetterMethod($matches[1], $class_obj, $map,$class_instance);
}
}
return $class_instance;
}catch (Exception $exception){
return false;
}
}
// 把數組映射成實體(一維數組)
function mapToModel(array $map, $class){
try {
$class_obj = new ReflectionClass($class);
$class_instance = $class_obj->newInstance(); // 根據反射對象創建實例
// 獲取所有方法(公共方法)
$methods = $class_obj->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method){
// 正則獲取 set 方法
if(preg_match("/set(\w+)/", $method->getName(), $matches)){
// echo $matches[1] . PHP_EOL; // 得到方法名 ProdId,ProdName,ProdPrice
invokeSetterMethod($matches[1], $class_obj, $map,$class_instance);
}
}
return $class_instance;
} catch (Exception $exception){
return null;
}
}
// 二維數組
// $fill 填充新字段
// $toarray=false 返回實體數組
function mapToModelsArray(array $maps, $class, $fill=[], $toarray=false){
$ret = [];
foreach ($maps as $map){
$getObject = mapToModel($map, $class);
if($getObject){
if($fill && count($fill) > 0){
$getObject->fill($fill);
}
if($toarray){
// 數組
$ret[] = $getObject->getModelAttributes();
}else{
// 實體對象
$ret[] = $getObject;
}
}
}
return $ret;
}
function invokeSetterMethod($name, ReflectionClass $class_obj, $jsonMap, &$class_instance){
// 把 ProdId 轉化成 Prod_Id
$filter_name = strtolower(preg_replace("/(?<=[a-z])([A-Z])/", "_$1", $name));
// 兼容 swoft
// 把 ProdId 轉化成 prodId
$filter_name_ForSwoft = lcfirst($name);
$props = $class_obj->getProperties(ReflectionProperty::IS_PRIVATE);
foreach ($props as $prop) {
// 存在對應的私有屬性
if(strtolower($prop->getName()) == $filter_name || $prop->getName() == $filter_name_ForSwoft){
$method = $class_obj->getMethod("set" . $name);
$args = $method->getParameters(); // 取出參數
if(count($args) == 1 && isset($jsonMap[$filter_name])){
// 對實例對象進行賦值(通過引用)
$method->invoke($class_instance, $jsonMap[$filter_name]);
}
}
}
}
2. 數據庫;
2.1 基本配置;
- 參考:https://www.swoft.org/documents/v2/mysql/config/
- 修改文件:
App\bean.php
<?php
// 設置配置文件如下
db' => [
'class' => Database::class,
'dsn' => 'mysql:dbname=test;host=127.0.0.1',
'username' => 'root',
'password' => 'asdf',
'charset' => 'utf8mb4',
'config' => [
'collation' => 'utf8mb4_unicode_ci',
'strict' => true,
'timezone' => '+8:00',
'modes' => 'NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES',
'fetchMode' => PDO::FETCH_ASSOC
]
],
# 連接池主要作用:保護數據庫
# 有內置連接池需要自己調控
'db.pool' => [
'class' => Pool::class,
'database' => bean('db'),
'minActive' => 10,
'maxActive' => 20,
'minWait' => 0,
'maxWaitTime' => 0
],
# 實際開發應該使用中間件,而非框架給的方法
# 切換數據源需要創建新的 db 和 db.pool
2.2 原生操作、查詢構造器;
- 參考:https://www.swoft.org/documents/v2/mysql/origin/
- 新建
App/Http/Controller/Product2Controller.php
<?php
namespace App\Http\Controller;
use App\lib\ProductEntity;
use App\Model\Product;
use Swoft\Db\DB;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Validator\Annotation\Mapping\Validate;
/**
* @Controller(prefix="/product2")
*/
class Product2Controller{
/**
* 2.3 驗證器:https://www.swoft.org/documents/v2/core-components/validator/
* 註解使用
* // @Validate(validator="product") // type="get"
* @RequestMapping(route="{pid}", params={"pid"="\d+"}, method={RequestMethod::GET, RequestMethod::POST})
*/
public function prod_detail(int $pid){
// 2.2.1 原生查詢
// $product = DB::selectOne("SELECT * FROM product WHERE id = ?", [$pid]);
// 切換數據庫
// $product = DB::db('test')->selectOne("SELECT * FROM product WHERE id = :pid", ["pid" => $pid]);
// 切換數據源
// $product = DB::query("db.pool")->getConnection()->selectOne("SELECT * FROM product WHERE id = :pid", ["pid" => $pid]);
// 2.2.2 查詢構造器使用、關聯表:https://www.swoft.org/documents/v2/mysql/query/
// 獲取所有
// $product = DB::table("product")->get();
// 獲取一條
// $product = DB::table("product")->where("id", "=", $pid)->select("id")->first();
// 關聯表
// $product = DB::table("product")
// ->join("product_class", "product.id", "product_class.pid")
// ->select("product.*", "product_class.pid")
// ->where("product.id", $pid)
// ->first();
// 2.4 模型的使用
$product = Product::find($pid);
// 不影響界面展示,代碼加入協程,加快取值過程
// 參考:https://www.swoft.org/documents/v2/basic-components/public-function/#heading1
if($product){
// 代碼塊 作用域
{
sgo(function () use ($product){
\Swoole\Coroutine::sleep(3);
// 指定字段遞增1
$product->increment("prod_click");
});
}
{
sgo(function () use ($pid){
\Swoole\Coroutine::sleep(5);
// 每次商品被訪問,都會增加商品訪問日誌
// 方法 1 : 模型方式插入
$product_view = ProductView::new();
{
$product_view->setProdId($pid);
$product_view->setViewIp(ip());
$product_view->setViewNum(1);
$product_view->save();
}
// 方法 2 : 數組方式插入
$pviewData = [
"prod_id" => $pid,
"view_ip" => ip(),
"view_num" => 1
];
$product_view = ProductView::new($pviewData)->save();
// 如果一個 ip 在當天訪問過每個商品,只需要 view_num +1 就行
// ProductView::updateOrCreate() // 更新和創建過程中需要取數據,使用這個方法
// 僅僅執行新增或者插入 用以下方法,每次 view_num +1
ProductView::updateOrInsert(
[
"prod_id" => $pid,
"view_ip" => ip()
],
[
"view_num" => DB::raw("view_num+1")
]
);
});
}
}
/** //@var $product ProductEntity */
//$product = jsonForObject(ProductEntity::class);
//var_dump($product);
if(isGet()){
return response(ContentType::JSON)->withData($product);
}else if(isPost()) {
// 非註解使用:https://www.swoft.org/documents/v2/core-components/validator/#heading15
\validate(jsonForObject(),"product");
$product['prod_name'] = "修改產品" . request()->post('prod_name', 'none');
$product['prod_price'] = "修改價格" . request()->post('prod_price', 0);
return response(ContentType::JSON)->withData($product);
}
}
}
2.3 驗證器;
- 註解使用
- 新建
App\Http\MyValidator\ProductValidator.php
<?php
namespace App\Http\MyValidator;
use Swoft\Validator\Annotation\Mapping\IsFloat;
use Swoft\Validator\Annotation\Mapping\IsString;
use Swoft\Validator\Annotation\Mapping\Length;
use Swoft\Validator\Annotation\Mapping\Min;
use Swoft\Validator\Annotation\Mapping\Max;
use Swoft\Validator\Annotation\Mapping\Validator;
/**
* 驗證:https://www.swoft.org/documents/v2/core-components/validator/#heading4
* *** 遺留問題:空值判斷
* @Validator(name="product")
*/
class ProductValidator{
/**
* @IsString(message="商品名稱不能爲空")
* @Length(min=5,max=20,message="商品名稱長度爲5-20")
* @var string
*/
protected $prod_name;
/**
* @IsString(message="商品短名稱不能爲空")
* @Length(min=2,max=20,message="商品名稱長度爲2-20")
* @var string
*/
protected $prod_sname;
/**
* @IsFloat(message="商品價格不能爲空")
* @Min(value=20,message="價格最低20")
* @Max(value=1000,message="價格最高1000")
* @var float
*/
protected $prod_price;
}
2.4 模型的使用;
php ./bin/swoft entity:create --table=product,product_class --pool=db.pool --path=@app/Model
# 後期新加字段:定義私有變量後, PhpStorm 用 Alt + Ins 新生成 set 和 get 方法
2.5. 場景練習(數據驗證,主子訂單入庫,事務控制);
- 生成實體:
# 主訂單表
php ./bin/swoft entity:create --table=orders_main --pool=db.pool --path=@app/Model
# 子訂單表
php ./bin/swoft entity:create --table=orders_detail --pool=db.pool --path=@app/Model
- 修改
App\Model\OrdersMain.php
// Alt + ins 生成 set 和 get 方法
// 自己定義的屬性不要打註解
// 這個屬性在數據庫裏是沒有的,僅僅是映射成對象
private $orderItems;
/**
* @return mixed
*/
public function getOrderItems()
{
return $this->orderItems;
}
/**
* @param mixed $orderItems
*/
public function setOrderItems($orderItems): void
{
$this->orderItems = $orderItems;
}
- 主表驗證器:新建
App\Http\MyValidator\OrderValidator.php
<?php
namespace App\Http\MyValidator;
use App\Http\MyValidator\MyRules\OrderDetail;
use Swoft\Validator\Annotation\Mapping\IsArray;
use Swoft\Validator\Annotation\Mapping\IsFloat;
use Swoft\Validator\Annotation\Mapping\IsInt;
use Swoft\Validator\Annotation\Mapping\Min;
use Swoft\Validator\Annotation\Mapping\Max;
use Swoft\Validator\Annotation\Mapping\Validator;
/**
* @Validator(name="order")
*/
class OrderValidator{
// /**
// * @IsString(message="訂單號不能爲空")
// * @var string
// */
// protected $order_no;
/**
* @IsInt(message="用戶ID不能爲空")
* @Min(value=1,message="用戶id不正確")
* @var int
*/
protected $user_id;
/**
* @IsInt(message="訂單狀態不能爲空")
* @Min(value=0,message="狀態不正確min")
* @Max(value=5,message="狀態不正確max")
* @var int
*/
protected $order_status;
/**
* @IsFloat(message="訂單金額不能爲空")
* @Min(value=1,message="訂單金額不正確")
* @var int
*/
protected $order_money;
// 訂單明細數據,是一個數組,包換若干子訂單實體
// 自定義驗證器規則:https://www.swoft.org/documents/v2/core-components/validator/#heading7
/**
* @IsArray(message="訂單明細不能爲空")
* @OrderDetail(message="訂單明細不正確")
* @var array
*/
protected $order_items;
}
- 副表驗證器:新建 1
App\Http\MyValidator\OrderDetailValidator.php
<?php
namespace App\Http\MyValidator;
use Swoft\Validator\Annotation\Mapping\IsFloat;
use Swoft\Validator\Annotation\Mapping\IsInt;
use Swoft\Validator\Annotation\Mapping\IsString;
use Swoft\Validator\Annotation\Mapping\Min;
use Swoft\Validator\Annotation\Mapping\Max;
use Swoft\Validator\Annotation\Mapping\Validator;
/**
* @Validator(name="order_detail")
*/
class OrderDetailValidator{
/**
* @IsInt(message="商品ID不能爲空")
* @Min(value=1,message="商品id不正確")
* @var int
*/
protected $prod_id;
/**
* @IsString(message="商品名稱不能爲空")
* @var string
*/
protected $prod_name;
/**
* @IsFloat(message="商品價格不能爲空")
* @Min(value=0,message="商品價格不正確")
* @var int
*/
protected $prod_price;
/**
* @IsInt(message="折扣不能爲空")
* @Min(value=1,message="折扣不正確min")
* @Max(value=10,message="折扣不正確max")
* @var int
*/
protected $discount;
/**
* @IsInt(message="商品數量不能爲空")
* @Min(value=1,message="商品數量不正確")
* @var int
*/
protected $prod_num;
}
- 新建 2
App\Http\MyValidator\MyRules\OrderDetail.php
<?php
namespace App\Http\MyValidator\MyRules;
/**
* @Annotation
* @Attributes({
* @Attribute("message",type="string")
* })
*/
class OrderDetail{
/**
* @var string
*/
private $message = '';
/**
* @var string
*/
private $name = '';
/**
* StringType constructor.
*
* @param array $values
*/
public function __construct(array $values)
{
if (isset($values['value'])) {
$this->message = $values['value'];
}
if (isset($values['message'])) {
$this->message = $values['message'];
}
if (isset($values['name'])) {
$this->name = $values['name'];
}
}
/**
* @return string
*/
public function getMessage(): string
{
return $this->message;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
}
- 新建 3
App\Http\MyValidator\MyRules\OrderDetailParser.php
<?php
namespace App\Http\MyValidator\MyRules;
use Swoft\Annotation\Annotation\Mapping\AnnotationParser;
use Swoft\Annotation\Annotation\Parser\Parser;
use Swoft\Validator\ValidatorRegister;
/**
* Class OrderDetailParser
* @AnnotationParser(annotation=OrderDetail::class)
*/
class OrderDetailParser extends Parser{
/**
* Parse object
*
* @param int $type Class or Method or Property
* @param object $annotationObject Annotation object
*
* @return array
* Return empty array is nothing to do!
* When class type return [$beanName, $className, $scope, $alias] is to inject bean
* When property type return [$propertyValue, $isRef] is to reference value
*/
public function parse(int $type, $annotationObject): array
{
if ($type != self::TYPE_PROPERTY) {
return [];
}
//向驗證器註冊一個驗證規則
ValidatorRegister::registerValidatorItem($this->className, $this->propertyName, $annotationObject);
return [];
}
}
- 新建 4
App\Http\MyValidator\MyRules\OrderDetailRule.php
<?php
namespace App\Http\MyValidator\MyRules;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Validator\Contract\RuleInterface;
use Swoft\Validator\Exception\ValidatorException;
/**
* Class OrderDetailRule
* @Bean(OrderDetail::class)
*/
class OrderDetailRule implements RuleInterface {
/**
* @param array $data
* @param string $propertyName
* @param object $item
* @param mixed $default
*
* @return array
*/
public function validate(array $data, string $propertyName, $item, $default = null, $strict = false): array
{
$getData = $data[$propertyName];
if(!$getData || !is_array($getData) || count($getData) == 0){
throw new ValidatorException($item->getMessage());
}
foreach ($getData as $data) {
validate($data, "order_detail");
}
return $data;
}
}
- 新建
App/Http/Controller/OrderController.php
<?php
namespace App\Http\Controller;
use App\Exception\ApiException;
use App\Model\OrdersDetail;
use App\Model\OrdersMain;
use Swoft\Db\DB;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Validator\Annotation\Mapping\Validate;
/**
* @Controller(prefix="/order")
*/
class OrderController{
/**
* 創建訂單
* @Validate(validator="order")
* @RequestMapping(route="new",method={RequestMethod::POST})
*/
public function createOrder(){
// 獲取 POST 數據做基本驗證
/** @var OrdersMain $orderPost */
// 包含了主訂單和子訂單數據
$orderPost = jsonForObject(OrdersMain::class);
// 也可以使用菊花算法等
$orderNo = date("YmdHis") . substr(implode(NULL, array_map('ord',str_split(substr(uniqid(), 7, 13), 1))),0,8);
// ApiExceptionHandler 攔截
// throw new ApiException("api exception");
// 獲取子訂單數據,是一個數組
// 需要通過ORM方式插入,數組是不行的
// 需要一個函數把它映射成 ORM 實體
// 子訂單數據([],[]),模型實體的數組
// 最後一個 true 參數代表返回一個數組,字段和數據庫一致
$orderDetail_array = mapToModelsArray($orderPost->getOrderItems(), OrdersDetail::class, ["order_no" => $orderNo], true);
// var_dump($orderDetail_array);
// $orderPost->getModelAttributes() // 實體對象轉數組
// 訂單數據雙雙入庫
if($orderPost){
// $orderPost->setOrderNo($orderNo);
// $orderPost->setCreateTime(date("Y-m-d H:i:s"));
$orderPost->fill(["order_no" => $orderNo, "create_time" => date("Y-m-d H:i:s")]);
// 加入事務: https://www.swoft.org/documents/v2/mysql/transaction/
// DB::beginTransaction();
// if($orderPost->save() && OrdersDetail::insert($orderDetail_array) ){
// DB::commit();
// return OrderCreateSuccess($orderNo);
// }else{
// DB::rollBack();
// }
tx(function () use ($orderPost, $orderDetail_array, $orderNo){
if($orderPost->save() && OrdersDetail::insert($orderDetail_array) ){
return OrderCreateSuccess($orderNo);
}
throw new \Exception("創建訂單失敗");
}, $result);
return $result;
}
return OrderCreateFail();
}
}
- 拋異常相關修改:
# 文件 App\Exception\Handler\HttpExceptionHandler.php
# 修改以下部分,通用異常在此拋出
if (!APP_DEBUG) {
//return $response->withStatus(500)->withContent($e->getMessage());
return $response->withStatus(500)->withData(["message" => $e->getMessage()]);
}
# 文件 App\Exception\Handler\ApiExceptionHandler.php
# 代碼 throw new ApiException("api exception"); 進行以下輸出
public function handle(Throwable $except, Response $response): Response
{
// $data = [
// 'code' => $except->getCode(),
// 'error' => sprintf('(%s) %s', get_class($except), $except->getMessage()),
// 'file' => sprintf('At %s line %d', $except->getFile(), $except->getLine()),
// 'trace' => $except->getTraceAsString(),
// ];
//
// return $response->withData($data);
return $response->withStatus(500)->withData([
"apimessage" => $except->getMessage()
]);
}
- 添加:
App/Helper/OrderFunctions.php
<?php
function OrderCreateSuccess($orderNo){
return ["status" => "success", "orderNo" => $orderNo];
}
function OrderCreateFail($msg="error"){
return ["status" => $msg, "orderNo" => ""];
}
3. Redis 相關;
3.1 Redis 配置使用;
- 基礎配置:https://www.swoft.org/documents/v2/redis/config/
- 修改:
App\bean.php
'redis' => [
'class' => RedisDb::class,
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'asdf',
'database' => 0,
// 'option' => [
// 'prefix' => 'swoft:'
// ]
],
'redis.pool' => [
'class' => Swoft\Redis\Pool::class,
'redisDb' => bean('redis'),
'minActive' => 2,
'maxActive' => 5,
'maxWait' => 0,
'maxWaitTime' => 0,
'maxIdleTime' => 60,
],
- 新建
App/Http/Controller/testController.php
<?php
namespace App\Http\Controller;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Redis\Redis;
/**
* Class testController
* @Controller(prefix="/test")
*/
class TestController{
/**
* @RequestMapping(route="/test",method={RequestMethod::GET})
* 另外:連接池注入:https://www.swoft.org/documents/v2/redis/usage/#heading1
*/
public function test(){
$redis = Redis::connection("redis.pool");
$v = $redis->get("name");
return $v;
}
}