v-Brocloni 3 years ago
parent
commit
6f3a61cd4b
100 changed files with 4387 additions and 0 deletions
  1. +129
    -0
      Config/DataBaseConfig.class.php
  2. +19
    -0
      Config/app.php
  3. +45
    -0
      Config/dbs.php
  4. +26
    -0
      Config/sys.php
  5. +35
    -0
      Ctrip/Api/Default.php
  6. +320
    -0
      Ctrip/Api/Hotel.php
  7. +202
    -0
      Ctrip/Api/HotelPush.php
  8. +93
    -0
      Ctrip/Api/Mapping.php
  9. +128
    -0
      Ctrip/Common/SoapDiscovery.class.php
  10. +138
    -0
      Ctrip/Common/Utils.php
  11. +19
    -0
      Ctrip/Domain/hotel.php
  12. +20
    -0
      Ctrip/Model/hotel.php
  13. +9
    -0
      Data/phalapi_test.sql
  14. +2
    -0
      Data/user.sql
  15. +39
    -0
      Demo/Api/Default.php
  16. +70
    -0
      Demo/Api/User.php
  17. +33
    -0
      Demo/Domain/User.php
  18. +27
    -0
      Demo/Model/User.php
  19. +21
    -0
      Demo/ModelProxy/UserBaseInfo.php
  20. +59
    -0
      Demo/Tests/Api/Api_Default_Test.php
  21. +84
    -0
      Demo/Tests/Api/Api_User_Test.php
  22. +48
    -0
      Demo/Tests/Domain/Domain_User_Test.php
  23. +48
    -0
      Demo/Tests/Model/Model_User_Test.php
  24. +34
    -0
      Demo/Tests/phpunit.xml
  25. +25
    -0
      Demo/Tests/phpunit_user_getbaseinfo.xml
  26. +16
    -0
      Demo/Tests/test_env.php
  27. +10
    -0
      LICENSE.md
  28. +6
    -0
      Language/en/common.php
  29. +14
    -0
      Language/zh_cn/common.php
  30. +6
    -0
      Language/zh_tw/common.php
  31. +7
    -0
      Library/README.md
  32. +33
    -0
      Library/Task/Config/app.php
  33. +21
    -0
      Library/Task/Config/dbs.php
  34. +109
    -0
      Library/Task/Data/phalapi_task_mq.sql
  35. +13
    -0
      Library/Task/Data/phalapi_task_progress.sql
  36. +3
    -0
      Library/Task/Data/task_mq.sql
  37. +8
    -0
      Library/Task/Data/task_progress.sql
  38. +44
    -0
      Library/Task/Lite.php
  39. +25
    -0
      Library/Task/MQ.php
  40. +34
    -0
      Library/Task/MQ/Array.php
  41. +21
    -0
      Library/Task/MQ/DB.php
  42. +27
    -0
      Library/Task/MQ/File.php
  43. +60
    -0
      Library/Task/MQ/KeyValue.php
  44. +39
    -0
      Library/Task/MQ/Memcached.php
  45. +50
    -0
      Library/Task/MQ/Redis.php
  46. +87
    -0
      Library/Task/Progress.php
  47. +15
    -0
      Library/Task/Progress/Trigger.php
  48. +22
    -0
      Library/Task/Progress/Trigger/Common.php
  49. +81
    -0
      Library/Task/Runner.php
  50. +34
    -0
      Library/Task/Runner/Local.php
  51. +60
    -0
      Library/Task/Runner/Remote.php
  52. +80
    -0
      Library/Task/Runner/Remote/Connector.php
  53. +10
    -0
      Library/Task/Runner/Remote/Connector/Http.php
  54. +60
    -0
      Library/Task/Task/Model/Task/TaskMq.php
  55. +76
    -0
      Library/Task/Task/Model/Task/TaskProgress.php
  56. +68
    -0
      Library/Task/Tests/MQ/Task_MQ_Array_Test.php
  57. +70
    -0
      Library/Task/Tests/MQ/Task_MQ_DB_Test.php
  58. +59
    -0
      Library/Task/Tests/MQ/Task_MQ_File_Test.php
  59. +59
    -0
      Library/Task/Tests/MQ/Task_MQ_Memcached_Test.php
  60. +60
    -0
      Library/Task/Tests/MQ/Task_MQ_Redis_Test.php
  61. +68
    -0
      Library/Task/Tests/Runner/Task_Runner_Local_Test.php
  62. +57
    -0
      Library/Task/Tests/Runner/Task_Runner_Remote_Test.php
  63. +54
    -0
      Library/Task/Tests/Task_Lite_Test.php
  64. +40
    -0
      Library/Task/Tests/Task_Progress_Test.php
  65. +65
    -0
      Library/Task/Tests/Task_Runner_Test.php
  66. +14
    -0
      Library/Task/Tests/test_env.php
  67. +32
    -0
      Library/Task/check.php
  68. +15
    -0
      Library/Task/crontab.php
  69. +23
    -0
      PhalApi/.gitignore
  70. +15
    -0
      PhalApi/Config/app.php
  71. +45
    -0
      PhalApi/Config/dbs.php
  72. +26
    -0
      PhalApi/Config/sys.php
  73. +33
    -0
      PhalApi/Ctrip/Api/Default.php
  74. +59
    -0
      PhalApi/Ctrip/Tests/Api/Api_Default_Test.php
  75. +34
    -0
      PhalApi/Ctrip/Tests/phpunit.xml
  76. +16
    -0
      PhalApi/Ctrip/Tests/test_env.php
  77. +9
    -0
      PhalApi/Data/phalapi_test.sql
  78. +2
    -0
      PhalApi/Data/user.sql
  79. +33
    -0
      PhalApi/Demo/Api/Default.php
  80. +70
    -0
      PhalApi/Demo/Api/User.php
  81. +33
    -0
      PhalApi/Demo/Domain/User.php
  82. +27
    -0
      PhalApi/Demo/Model/User.php
  83. +21
    -0
      PhalApi/Demo/ModelProxy/UserBaseInfo.php
  84. +59
    -0
      PhalApi/Demo/Tests/Api/Api_Default_Test.php
  85. +84
    -0
      PhalApi/Demo/Tests/Api/Api_User_Test.php
  86. +48
    -0
      PhalApi/Demo/Tests/Domain/Domain_User_Test.php
  87. +48
    -0
      PhalApi/Demo/Tests/Model/Model_User_Test.php
  88. +34
    -0
      PhalApi/Demo/Tests/phpunit.xml
  89. +25
    -0
      PhalApi/Demo/Tests/phpunit_user_getbaseinfo.xml
  90. +16
    -0
      PhalApi/Demo/Tests/test_env.php
  91. +10
    -0
      PhalApi/LICENSE.md
  92. +6
    -0
      PhalApi/Language/en/common.php
  93. +14
    -0
      PhalApi/Language/zh_cn/common.php
  94. +6
    -0
      PhalApi/Language/zh_tw/common.php
  95. +7
    -0
      PhalApi/Library/README.md
  96. +33
    -0
      PhalApi/Library/Task/Config/app.php
  97. +21
    -0
      PhalApi/Library/Task/Config/dbs.php
  98. +109
    -0
      PhalApi/Library/Task/Data/phalapi_task_mq.sql
  99. +13
    -0
      PhalApi/Library/Task/Data/phalapi_task_progress.sql
  100. +3
    -0
      PhalApi/Library/Task/Data/task_mq.sql

+ 129
- 0
Config/DataBaseConfig.class.php View File

@@ -0,0 +1,129 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2016/10/12
* Time: 10:56
*/
require_once __DIR__ . '/../Utils/commonUtil.class.php';

class DataBaseConfig
{
//正式数据库
private $MYSQL_HOST = "180.168.4.58";
private $MYSQL_USER = "root";
private $MYSQL_PASSWORD = "123456";
private $MYSQL_DB = "ctsdata";
private $MYSQL_PORT = "8090";

//测试数据库
private $MYSQL_HOST1 = "180.168.4.58";
private $MYSQL_USER1 = "root";
private $MYSQL_PASSWORD1 = "123456";
private $MYSQL_DB1 = "ctsdata_test";
private $MYSQL_PORT1 = "8090";

//waice数据库
private $MYSQL_HOST2 = "180.168.4.58";
private $MYSQL_USER2 = "root";
private $MYSQL_PASSWORD2 = "123456";
private $MYSQL_DB2 = "waice";
private $MYSQL_PORT2 = "8090";

//waice2数据库
private $MYSQL_HOST3 = "192.168.6.245";
private $MYSQL_USER3 = "root";
private $MYSQL_PASSWORD3 = "123456";
private $MYSQL_DB3 = "waice2";
private $MYSQL_PORT3 = "3306";


//Memcache配置
private $MEMCACHE_HOST = "139.224.30.29";
private $MEMCACHE_PORT = "11211";
private $MEMCACHE_USER = "memcached";
private $API_GPS_ACCOUNT = "15618818219";
private $API_GPS_PASSWORD = "123456";

/**
* 链接正式数据库
* @return PDO
*/
function conn()
{
try {
$pdo = new PDO("mysql:host=" . $this->MYSQL_HOST . ";port=" . $this->MYSQL_PORT . ";dbname=" . $this->MYSQL_DB, $this->MYSQL_USER, $this->MYSQL_PASSWORD, array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8"));
return $pdo;
} catch (PDOException $e) {
utils::writeLog('new PDO failed:' . $e->getMessage());
}
}

/**
* 链接测试数据库
* @return PDO
*/
function conn_test()
{
try {
$pdo = new PDO("mysql:host=" . $this->MYSQL_HOST1 . ";port=" . $this->MYSQL_PORT1 . ";dbname=" . $this->MYSQL_DB1, $this->MYSQL_USER1, $this->MYSQL_PASSWORD1, array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8"));
return $pdo;
} catch (PDOException $e) {
utils::writeLog('new PDO failed:' . $e->getMessage());
}
}

/**
* 链接waice数据库
* @return PDO
*/
function conn_waice()
{
try {
$pdo = new PDO("mysql:host=" . $this->MYSQL_HOST3 . ";port=" . $this->MYSQL_PORT3 . ";dbname=" . $this->MYSQL_DB3, $this->MYSQL_USER3, $this->MYSQL_PASSWORD3, array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8"));
return $pdo;
} catch (PDOException $e) {
utils::writeLog('new PDO failed:' . $e->getMessage());
}
}

/**
* 添加缓存
* @param $key
* @param $value
*/
public function set_memcache($key, $value)
{
$mem = new Memcache;
$mem->connect($this->MEMCACHE_HOST, $this->MEMCACHE_PORT);
$mem->set($key, $value);
}

/**
* 获取内存中的数据
* @param $key
* @return array|string
*/
public function get_memcache($key)
{
$mem = new Memcache;
$mem->connect($this->MEMCACHE_HOST, $this->MEMCACHE_PORT);
$value = $mem->get($key);
return $value;
}

/**
* 删除键值对应的数据
* @param $key
* @return bool
*/
public function delete_memcache($key)
{
$mem = new Memcache;
$mem->connect($this->MEMCACHE_HOST, $this->MEMCACHE_PORT);
$value = $mem->delete($key);
return $value;
}

}

+ 19
- 0
Config/app.php View File

@@ -0,0 +1,19 @@
<?php
/**
* 请在下面放置任何您需要的应用配置
*/

return array(

/**
* 应用接口层的统一参数
*/
'apiCommonRules' => array(
//'sign' => array('name' => 'sign', 'require' => true),
//客户端App版本号,如:1.0.1
'version' => array(
'name' => 'version', 'default' => '',
),
),

);

+ 45
- 0
Config/dbs.php View File

@@ -0,0 +1,45 @@
<?php
/**
* 分库分表的自定义数据库路由配置
*/

return array(
/**
* DB数据库服务器集群
*/
'servers' => array(
'db_demo' => array( //服务器标记
'host' => '106.14.56.77', //数据库域名
'name' => 'ctsdata_mirror', //数据库名字
'user' => 'spider', //数据库用户名
'password' => 'PjGPWNUgOYe6i1Ef', //数据库密码
'port' => '3306', //数据库端口
'charset' => 'UTF8', //数据库字符集
),
),

/**
* 自定义路由表
*/
'tables' => array(
//通用路由
'__default__' => array(
'prefix' => '',
'key' => 'id',
'map' => array(
array('db' => 'db_demo'),
),
),

/**
'demo' => array( //表名
'prefix' => 'pa_', //表名前缀
'key' => 'id', //表主键名
'map' => array( //表路由配置
array('db' => 'db_demo'), //单表配置:array('db' => 服务器标记)
array('start' => 0, 'end' => 2, 'db' => 'db_demo'), //分表配置:array('start' => 开始下标, 'end' => 结束下标, 'db' => 服务器标记)
),
),
*/
),
);

+ 26
- 0
Config/sys.php View File

@@ -0,0 +1,26 @@
<?php
/**
* 以下配置为系统级的配置,通常放置不同环境下的不同配置
*/

return array(
/**
* 默认环境配置
*/
'debug' => true,

/**
* MC缓存服务器参考配置
*/
'mc' => array(
'host' => '127.0.0.1',
'port' => 11211,
),

/**
* 加密
*/
'crypt' => array(
'mcrypt_iv' => '12345678', //8位
),
);

+ 35
- 0
Ctrip/Api/Default.php View File

@@ -0,0 +1,35 @@
<?php
/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/9
* Time: 22:52
* 默认接口服务类
*/

class Api_Default extends PhalApi_Api {

public function getRules() {
return array(
'index' => array(
'username' => array('name' => 'username', 'default' => 'PHPer', ),
),
);
}

/**
* 默认接口服务
* @return string title 标题
* @return string content 内容
* @return string version 版本,格式:X.X.X
* @return int time 当前时间戳
*/
public function index() {
return array(
'title' => 'Hello World11111111!',
'content' => T('Hi {name}, welcome to use PhalApi!', array('name' => $this->username)),
'version' => PHALAPI_VERSION,
'time' => $_SERVER['REQUEST_TIME'],
);
}
}

+ 320
- 0
Ctrip/Api/Hotel.php View File

@@ -0,0 +1,320 @@
<?php
/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/12
* Time: 0:40
* 接口调用方:携程
* 接口返回方:合作方(us)
*/

require_once dirname(__DIR__) . '/Common/Utils.php';

class Hotel
{
public $obj_utils = '';
public $Currency = 'RMB';

public function __construct()
{
$this->obj_utils = new roomOrderUtils();
}

/**
* User:Steven
*
* Desc:DomesticCheckRoomAvail (可定检查)
* 1.接口调用方:携程
* 2.接口返回方:合作方
* 3.调用频率:订单量的10倍以上
* 4.使用说明:携程在给酒店下订单前,调用合作方接口。通过传入客人入住信息,得 到该房型是否可订。该接口响应时间(含网络)需要在3秒以内
*/
public function DomesticCheckRoomAvail()
{
$rec_info = file_get_contents("php://input");
$OrderData = $this->obj_utils->data_to_xml($rec_info); //将xml转化成数组
$roomInfo = $OrderData['HotelGroupInterfaceRoomTypeListRequest'];
$hotel = $roomInfo['Hotel']; //酒店编号
$Arrival = $roomInfo['Arrival ']; //到店日期
$Departure = $roomInfo['Departure ']; //离店日期
$Room = $roomInfo['Room ']; //房型编号
$CurrencyCode = $roomInfo['CurrencyCode ']; //币种(可空)
$RoomNumber = $roomInfo['RoomNumber ']; //预定间数
$Person = $roomInfo['Person']; //入住人数
$BalanceType = $roomInfo['BalanceType']; //价格类型
foreach ($roomInfo['RoomPrices'] as $item) {
$EffectDate = $item['EffectDate']; //入住日期
$Price = $item['Price']; //卖价
$CNYPrice = $item['CNYPrice']; //汇率后的卖价(可空)
$Cost = $item['Cost']; //底价
$CNYCost = $item['CNYCost']; //汇率后的底价(可空)
$BreakFast = $item['BreakFast']; //含早餐数
$pdo = conn();
//$sql="CALL HT_CHECKROOM_AVAIL($Arrival,$Departure,$Room,$RoomNumber)";
$sql = "CALL HT_CHECKROOM_AVAIL('2016-08-23','2016-08-28','152248',3)";
if (is_object($pdo)) {
$result = $pdo->query($sql);
$json2 = $result->fetchAll(PDO::FETCH_ASSOC); //返回一个包含结果集中所有行的数组
var_dump($json2);
}
}
$roomInfo_arr['RequestResponse']['RequestResult'] = array();
$RequestResult = $roomInfo_arr['RequestResponse']['RequestResult'];
$pdo = conn();
//$sql="CALL HT_CHECKROOM_AVAIL($Arrival,$Departure,$Room,$RoomNumber)";
$sql = "CALL HT_CHECKROOM_AVAIL('2016-08-23','2016-08-23','152248',3,0,0)";
if (is_object($pdo)) {
$result = $pdo->query($sql);
$res_arr = $result->fetchAll(PDO::FETCH_ASSOC); //返回一个包含结果集中所有行的数组
//var_dump($res_arr);
$RequestResult['Message'] = empty($res_arr) ? '不可定' : '可定';
$RequestResult['ResultCode'] = empty($res_arr) ? 101 : 0;
$availInfo['IsBookable'] = empty($res_arr) ? 0 : 1;
$availInfo['Room'] = empty($res_arr) ? '' : $res_arr[0]['PROD_ID'];
$availInfo['InterFaceAmount'] = empty($res_arr) ? '' : '';//接口订单金额
$availInfo['ReturnDescript'] = empty($res_arr) ? '' : ''; //错误描述
if (!empty($res_arr) && is_array($res_arr) || count($res_arr) > 0)
foreach ($res_arr as $item) {
$roomPrice['RoomPrice'] = array();
$roomPrice['RoomPrice']['EffectDate'] = $item['RUN_DATE'];
$roomPrice['RoomPrice']['Price'] = 0;
$roomPrice['RoomPrice']['CNYPrice'] = 0;
$roomPrice['RoomPrice']['Cost'] = $item['HT_ORDER_PRICE'];
$roomPrice['RoomPrice']['CNYCost'] = 0;
$roomPrice['RoomPrice']['BreakFast'] = $item['HT_BREAKFAST'];
$availInfo['RoomPrices'][] = $roomPrice;
}
$RequestResult['DomesticCheckRoomAvailResponse'] = $availInfo;
$roomInfo_arr['RequestResponse']['RequestResult'] = $RequestResult;
}
return $roomInfo_arr;
}

/**
* User:Steven
*
* Desc: DomesticSubmitNewHotelOrder (新订订单)
* 1-1.接口调用方:携程/合作方
* 1-2.接口返回方:合作方/携程
* 1-3.调用频率:频繁
* 1-4.使用说明:通过该接口,提交订单给对方系统
* @return mixed
*/
public function DomesticSubmitNewHotelOrderRequest()
{
$rec_info = file_get_contents("php://input");
$OrderData = $this->obj_utils->data_to_xml($rec_info); //将xml转化成数组
$orderInfo = $OrderData['DomesticSubmitNewHotelOrderRequest'];
//var_dump($orderInfo);
$OrderID = $orderInfo['OrderID']; //订单号
$InterFaceSendID = $orderInfo['InterFaceSendID']; //订单接口发送号,同一订单每次发送编号会不同,接收方需落地保存
$Hotel = $orderInfo['Hotel']; // 酒店编号
$HotelName = $orderInfo['HotelName']; //酒店名
$Arrival = $orderInfo['Arrival']; //入住日期
$Departure = $orderInfo['Departure']; //离店日期
$EarlyArrivalTime = $orderInfo['EarlyArrivalTime']; //最早到店时间
$LastArrivalTime = $orderInfo['LastArrivalTime']; //最晚到店时间
$Person = $orderInfo['Person']; //实际入住人数
foreach ($orderInfo['Guests']['GuestEntity'] as $item) {
$FirstName = $item['FirstName'];
$LastName = $item['LastName'];
$ChinesName = $item['ChinesName'];
}
$MobilePhone = $orderInfo['MobilePhone']; //携程联系电话
$Currency = $orderInfo['Currency']; //订单币种
$Amount = $orderInfo['Amount']; //订单卖价总金额(原币种),预付一般不传或者传0
$CNYAmount = $orderInfo['CNYAmount']; //订单卖价总金额(人民币),预付一般不传或者传0
$GuaranteeType = $orderInfo['GuaranteeType']; //担保方式
$BalanceType = $orderInfo['BalanceType']; //支付方式
$Room = $orderInfo['Room']; //Ctrip房型编号,供应商需要转成自己的对应编号
$RoomPerson = $orderInfo['RoomPerson']; //房型最大入住人数
$RoomName = $orderInfo['RoomName']; //房型名称
$Quantity = $orderInfo['Quantity']; //预定间数
$CostAmount = $orderInfo['CostAmount']; //订单底价金额(原币种),现付一般不传或者传0
$CNYCostAmount = $orderInfo['CNYCostAmount']; //订单底价金额(人民币),现付一般不传或者传0
foreach ($orderInfo['RoomPrices']['RoomPrice'] as $item) { //每个RoomPrice对应一天价格
$EffectDate = $item['EffectDate'];
$Price = $item['Price']; //订单卖价金额(原币种),预付一般不传或者传0
$CNYPrice = $item['CNYPrice']; //订单卖价金额(人民币),预付一般不传或者传0
$Cost = $item['Cost']; //订单底价金额(原币种),现付一般不传或者传0
$CNYCost = $item['CNYCost']; //-订单底价金额(人民币),现付一般不传或者传0
$BreakFast = $item['BreakFast']; //早餐数量
}
//先判断此房间是否可定

$pdo = conn();
echo $sql = "CALL HT_CHECKROOM_AVAIL($Arrival,$Departure,$Room,$Quantity,$CostAmount,$BreakFast)";
//$sql = "CALL HT_CHECKROOM_AVAIL('2016-08-23','2016-08-23','152248',3,0,0)";
if (is_object($pdo)) {
$result = $pdo->query($sql);

$json = $result->fetchAll(PDO::FETCH_ASSOC); //返回一个包含结果集中所有行的数组
if ($json) {
//TODO:添加订单信息
$sql = "";
//返回信息
$orderInfo_arr['RequestResponse']['RequestResult'] = array();
$RequestResult = $orderInfo_arr['RequestResponse']['RequestResult'];
$RequestResult['Message'] = "";
$ResultCode['ResultCode'] = "";
$orderStatus['OrderStatus'] = ''; //订单状态(0:发送中;1:已发送;2:发送失败;3:酒店确认成功;4:酒店 拒绝;5其他)
$orderStatus['InterFaceConfirmNO'] = ""; //接口确认号,酒店确认号
$orderStatus['HotelConfirmNo'] = ""; //供应商确认号
$orderStatus['InterFaceAmount'] = ""; //接口订单金额
$orderStatus['ReturnCode'] = ""; //错误代码
$orderStatus['ReturnDescript'] = ""; //返回描述
$RequestResult['DomesticSubmitNewHotelOrderResponse'] = $orderStatus;
return $RequestResult;
}
}

}


/**
* User:Steven
*
* Desc: DomesticModifyHotelOrder(修改酒店订单)
* 1-1.接口调用方:携程/合作方
* 1-2.接口返回方:合作方/携程
* 1-3.调用频率:频繁
* 1-4.使用说明:通过该接口,提交订单给对方系统
* @return mixed
*/
public function DomesticModifyHotelOrder()
{
$rec_info = file_get_contents("php://input");
$OrderData = $this->obj_utils->data_to_xml($rec_info); //将xml转化成数组
$orderInfo = $OrderData['DomesticModifyHotelOrderRequest'];
$OrderID = $orderInfo['OrderID']; //订单号
$InterFaceSendID = $orderInfo['InterFaceSendID']; //订单接口发送号,同一订单每次发送编号会不同,接收方需落地保存
$OldOrderID = $orderInfo['OldOrderID']; //上一个订单号
$Ori_OrderID = $orderInfo['Ori_OrderID']; //原始订单号
$Hotel = $orderInfo['Hotel']; //-Ctrip酒店编号,供应商需要转成自己的对应编号
$HotelName = $orderInfo['HotelName'];
$Arrival = $orderInfo['Arrival'];
$Departure = $orderInfo['Departure'];
$EarlyArrivalTime = $orderInfo['EarlyArrivalTime'];
$LastArrivalTime = $orderInfo['LastArrivalTime'];
$Person = $orderInfo['Person'];
foreach ($orderInfo['Guests'] as $k => $v) {
$FirstName = $v;
$LastName = $v;
$ChinesName = $v;
}
$MobilePhone = $orderInfo['MobilePhone']; //-携程联系电话
$Currency = $orderInfo['Currency'];
$Amount = $orderInfo['Amount'];
$CNYAmount = $orderInfo['CNYAmount'];
$GuaranteeType = $orderInfo['GuaranteeType'];
$BalanceType = $orderInfo['BalanceType'];
$Room = $orderInfo['Room'];
$OldRoom = $orderInfo['OldRoom']; //上个预订房型
$RoomPerson = $orderInfo['RoomPerson'];
$RoomName = $orderInfo['RoomName'];
$Quantity = $orderInfo['Quantity']; //预定间数
$CostAmount = $orderInfo['CostAmount']; //订单底价金额(原币种),现付一般不传或者传0
$CNYCostAmount = $orderInfo['CNYCostAmount']; //订单底价金额(人民币),现付一般不传或者传0
foreach ($orderInfo['RoomPrices'] as $item) { //每个RoomPrice对应一天价格
$EffectDate = $item['EffectDate'];
$Price = $item['Price']; //订单卖价金额(原币种),预付一般不传或者传0
$CNYPrice = $item['CNYPrice']; //订单卖价金额(人民币),预付一般不传或者传0
$Cost = $orderInfo['Cost']; //订单底价金额(原币种),现付一般不传或者传0
$CNYCost = $orderInfo['CNYCost']; //-订单底价金额(人民币),现付一般不传或者传0
$BreakFast = $orderInfo['BreakFast']; //早餐数量
$OldPrice = $orderInfo['OldPrice']; //-上个订单卖价金额(原币种),预付一般不传或者传0
}

//检查修改后的房型是否可定
$pdo = conn();
//$sql="CALL HT_CHECKROOM_AVAIL($Arrival,$Departure,$Room,$Quantity,$CostAmount,$BreakFast)";
$sql = "CALL HT_CHECKROOM_AVAIL('2016-08-23','2016-08-23','152248',3,0,0)";
if (is_object($pdo)) {
$result = $pdo->query($sql);
$json = $result->fetchAll(PDO::FETCH_ASSOC); //返回一个包含结果集中所有行的数组
if ($json) {
//TODO:修改订单信息


//返回信息
$orderInfo_arr['RequestResponse']['RequestResult'] = array();
$RequestResult = $orderInfo_arr['RequestResponse']['RequestResult'];
$RequestResult['Message'] = "";
$ResultCode['ResultCode'] = "";
$orderStatus['OrderStatus'] = ''; //订单状态(0:发送中;1:已发送;2:发送失败;3:酒店确认成功;4:酒店 拒绝;5其他)
$orderStatus['InterFaceConfirmNO'] = ""; //接口确认号,酒店确认号
$orderStatus['HotelConfirmNo'] = ""; //供应商确认号
$orderStatus['InterFaceAmount'] = ""; //接口订单金额
$orderStatus['ReturnCode'] = ""; //错误代码
$orderStatus['ReturnDescript'] = ""; //返回描述
$RequestResult['DomesticModifyHotelOrderResponse'] = $orderStatus;
return $RequestResult;
}
}

}

/**
* User:Steven
*
* Desc: DomesticCancelHotelOrder (取消订单)
* 1-1.接口调用方:携程/合作方
* 1-2.接口返回方:合作方/携程
* 1-3.调用频率:频繁
* 1-4.使用说明:通过该接口,提交订单给对方系统
* @return mixed
*/
public function DomesticCancelHotelOrder()
{
$rec_info = file_get_contents("php://input");
$OrderData = $this->obj_utils->data_to_xml($rec_info); //将xml转化成数组
$cancelOrderInfo = $OrderData['DomesticCancelHotelOrderRequest'];
$OrderID = $cancelOrderInfo['OrderID'];
$OldOrderID = $cancelOrderInfo['OldOrderID'];
$Ori_OrderID = $cancelOrderInfo['Ori_OrderID'];
$InterFaceSendID = $cancelOrderInfo['InterFaceSendID'];
$InterFaceConfirmNO = $cancelOrderInfo['InterFaceConfirmNO'];
$Hotel = $cancelOrderInfo['Hotel'];
$HotelName = $cancelOrderInfo['HotelName'];
$Arrival = $cancelOrderInfo['Arrival'];
$Departure = $cancelOrderInfo['Departure'];
$Person = $cancelOrderInfo['Person'];
$ClientName = $cancelOrderInfo['ClientName'];
$Room = $cancelOrderInfo['Room'];
$RoomName = $cancelOrderInfo['RoomName'];
$Quantity = $cancelOrderInfo['Quantity']; //注意确认几个半闭合标签是否存在

//TODO:取消订单逻辑;


//返回结果
$orderInfo_arr['RequestResponse']['RequestResult'] = array();
$RequestResult = $orderInfo_arr['RequestResponse']['RequestResult'];
$RequestResult['Message'] = "";
$RequestResult['ResultCode'] = "";
$orderStatus['OrderStatus'] = ''; //订单状态(0:发送中;1:已发送;2:发送失败;3:酒店确认成功;4:酒店 拒绝;5其他)
$orderStatus['OrderID'] = "";
$orderStatus['InterFaceConfirmNO'] = "";
$orderStatus['ReturnCode'] = "";
$orderStatus['ReturnDescript'] = ""; //错误代码
$RequestResult['DomesticCancelhotelOrderResponse'] = $orderStatus;
return $RequestResult;

}

/**
* User:Steven
*
* Desc: DomesticPushOrderStatus(订单状态推送)
* 1-1.接口调用方:携程/合作方
* 1-2.接口返回方:合作方/携程
* 1-3.调用频率:频繁
* 1-4.使用说明:订单非立即确认时调用该接口,接收方收到订单后,当订单状态变化时, 需及时推送订单状
*/
public function DomesticPushOrderStatus()
{

}


}

+ 202
- 0
Ctrip/Api/HotelPush.php View File

@@ -0,0 +1,202 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/13
* Time: 18:42
* 接口调用方:合作方
* 接口返回方:携程
*/

require_once dirname(__DIR__) . '/Common/Utils.php';

class Api_HotelPush extends PhalApi_Api
{
public $obj_utils = '';
public $Currency = 'RMB';

public function __construct()
{
$this->obj_utils = new roomOrderUtils();
}

public function getRules()
{
return array(/* '*' => array( //通用接口参数
'code' => array('name' => 'code', 'require' => true, 'min' => 4, 'max' => 4),
),
'index' => array( //指定接口参数
'username' => array('name' => 'username', 'default' => 'PHPer',),
),*/
);
}

/**
* 默认接口服务
* @return string title 标题
* @return string content 内容
* @return string version 版本,格式:X.X.X
* @return int time 当前时间戳
*/
public function index()
{
return array(
'title' => 'Hello Worl!',
'content' => T('Hi {name}, welcome to use PhalApi!', array('name' => $this->username)),
'version' => PHALAPI_VERSION,
'time' => $_SERVER['REQUEST_TIME'],
);
}

/**
* User:Steven
*
* Desc:GetCtripRoomTypeInfo(获得房型对照)
* 1-1. 接口调用方:合作方
* 1-2. 接口返回方:携程
* 1-3. 调用频率:不限制,建议每天早晚各一次
* 1-4. 使用说明:合作方通过自己的酒店信息、房型信息、房价套系等获得携程的房型对 照信息
*/
public function GetCtripRoomTypeInfo()
{
$RoomTypeList = array(
'HotelGroupHotelCode' => "",
'HotelGroupRoomTypeCode' => "",
'HotelGroupBrand' => "",
'HotelGroupRatePlanCode' => ''
);
$RoomTypeInfo['HotelGroupInterfaceRoomTypeListRequest'] = $RoomTypeList;
$res = $this->obj_utils->xml_encode($RoomTypeInfo, 'GetCtripRoomTypeInfo');
$result = $this->obj_utils->soapRequest('GetCtripRoomTypeInfo', $res); //发送soap请求
//TODO:得到请求结果,处理
return $result;
}

/**
* User:Steven
*
* Desc:SetRoomPrice(设置房型价格)
* 1.接口调用方:合作方
* 2.接口返回方:携程
* 3.调用频率:不限制,建议不大于50万次/分钟(QPS<1万)
* 4.使用说明:携程建议当价格变化时,立即进行推送。携程方面是异步处理价格。
*/
public function SetRoomPrice()
{
$Prices['Price'] = array(
'AmountBeforeTaxFee' => '', //税前
'AmountAfterTaxFee' => '', //税后
'CostAmountBeforeTaxFee' => '',//税前成本
'CostAmountAfterTaxFee' => '', //税后成本
'Day' => '' //连住天数,暂不用,默认为1
);
//PriceInfo节点代表一天的价格,每天的价格可以不 同
$PriceInfos['PriceInfo'][] = array(
'Prices' => $Prices,
'Stays' => '', //连住,暂不用,默认为1
'BlanceType' => '', //支付类型
'PriceType' => '', //价格类型
'Breakfast' => '', //早餐
'Applicability' => '' //适用人群
);
//根据日期范围生成多天的 SetRoomPriceItem
$SetRoomPriceItem['SetRoomPriceItem'][] = array(
'PriceInfos' => $PriceInfos,
'RoomID' => '',
'StartDate' => '',
'EndDate' => '',
'Currency' => $this->Currency,
);
$RoomTypeList = array(
'SetRoomPriceItems' => $SetRoomPriceItem,
'HotelID' => "", //酒店ID
'Submitor' => "", //提交人,集团名拼音
'Title' => '',
'Priority' => '' //是否优先处理,暂不用,默认为N
);

$RoomPriceRequest['SetAdaperRoomPriceRequest'] = $RoomTypeList; //设置多房型多天房价
$res = $this->obj_utils->xml_encode($RoomPriceRequest, 'SetRoomPrice');
$result = $this->obj_utils->soapRequest('SetRoomPrice', $res); //发送soap请求
return $result;
}

/**
* User:Steven
*
* Desc:SetRoomInfo(设置房态)
* 1.接口调用方:合作方
* 2.接口返回方:携程
* 3.调用频率:不限制,建议不大于50万次/分钟(QPS<1万)
* 4.使用说明:携程建议当房态变化时(开或关),立即进行推送。携程方面是异步处 理房态。
*/
public function SetRoomInfo()
{
//设置房态信息请求,设置一个房型单天或多天房态,不支持多房型同时 设置
$RoomInfoItem['RoomInfoItem'][] = array(
'Stays' => '', //连住,暂不用,默认为1
'ChangeDefault' => '', //是否同时修改房态默认值(F-否,T-是)
'Recommend' => '', //国内推荐级别(5-特推,4-主推,3-可推,2-可订,1-不推,0-不可 订)
'Recommend_Intl' => '', //国外推荐级别(5-特推,4-主推,3-可推,2-可订,1-不推,0-不可 订)
'HoldDeadline' => '', //保留时间(9999-无规定,1000-10:00,...,2330-23:30)
'Roomstatus' => '', //房态(N-满房,G-良好)
'RoomsInv' => '', //临时保留房总数
'UserLimited' => '', //预订限制(2-超时担保,3-一律担保,9999-无限制)
'Note' => '', //备注
'ReserveTime' => '', //保留房用最晚预订时间,计算公式:订单入住日24点向后推 算,如果设置为6,则当天保留房最晚预订时间为24点向后倒推6小时,为18点。 如果设置为36,则保留房最晚预订时间为24点向后倒推36小时,表示入住日前一 天的中午12点。
'Restorable' => '', //保留房可否恢复(T-可,F-不可)
'Guarantee' => '', //担保(此字段暂时不维护)
'CheckType' => '', //住店控制(C-进店统计,S-住店统计)
'GuaranteeLCT' => '', //担保最晚取消时间,计算公式同ReserveTime,不可取消设置 为23988
'PrepayLCT' => '', //预付最晚取消时间,计算公式同ReserveTime, 不可取消设置 为23988
'AllNeedGuarantee' => '', //全额/峰时担保(F-否,T-全额担保,B-峰时担保)-
'RoomGiftID' => '', //房型礼品ID,默认值-2147483648
'LateReserveTime' => '', //订单最晚预订时间,计算公式同ReserveTime
'DeductType' => '', //预付房型扣款类型(C-全部扣款,F-首日扣款)
);

$RoomInfoRequest['SetRoomInfoRequest'] = array(
'RoomInfoItems' => $RoomInfoItem,
'RoomID' => '', //房型ID
'StartDate' => '', //开始日期
'EndDate' => '', //结束日期,设置多天表示多天房态
'Editer' => '', //修改者,集团名拼音
);
$res = $this->obj_utils->xml_encode($RoomInfoRequest, 'SetRoomInfo');
$result = $this->obj_utils->soapRequest('SetRoomInfo', $res); //发送soap请求
return $result;
}

/**
* User:Steven
*
* Desc:UpdateRoomQuantity(更新保留房数量)
* 1-1.接口调用方:合作方
* 1-2.接口返回方:携程
* 1-3.调用频率:限制, 建议10次/分钟,并会视情况调整
* 1-4.使用说明:携程建议当房量变化时,立即进行推送。携程方面是异步处理房量更新操作。
* 一个请求最多只允许更新 10 个酒店下的房型,一个请求只允许 120 天内的房量, 一个请求 只允许发送少于 100 个房型。
*/
public function UpdateRoomQuantity()
{
//多个房型
$RoomQuantityEntityList['RoomQuantityEntity'][] = array(
'RoomTypeID' => '',
'RoomQuantityCount' => '',
'RoomQuantityUpdateType' => '',
'StartDate' => '',
'EndDate' => ''
);
//一个酒店
$UpdateRoomQuantityRequest['UpdateRoomQuantityRequest'] = array(
'SequenceID' => '',
'HotelID' => '',
'RoomQuantityEntityList' => $RoomQuantityEntityList,
'Editer' => '',
);
$res = $this->obj_utils->xml_encode($UpdateRoomQuantityRequest, 'UpdateRoomQuantityRequest ');
$result = $this->obj_utils->soapRequest('UpdateRoomQuantityRequest ', $res); //发送soap请求
return $result;
}
}

+ 93
- 0
Ctrip/Api/Mapping.php View File

@@ -0,0 +1,93 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/14
* Time: 18:46
* Ctrip 自助Mapping
*/
require_once dirname(__DIR__) . '/Common/Utils.php';

class Api_Mapping extends PhalApi_Api
{
public $obj_utils = '';
public $SupplierID = 77; //供应商编码
public $Brand = 1; //品牌编码

public function __construct()
{
$this->obj_utils = new roomOrderUtils();
}

/**
* User:Steven
*
* Desc:、GetHotelInfo(获得Ctrip的酒店信息)
* 1-1. 接口调用方:合作方
* 1-2. 接口返回方:携程
* 1-3. 调用频率:不限制
* 1-4. 使用说明:合作方获取ctrip的酒店对接信息,用于自助Mapping。 SupplierID或Brand会线下提供
*/
public function GetHotelInfo()
{
/*$GetHotelInfoRequest['GetHotelInfoRequest'] = array(
'SupplierID' => $this->SupplierID, //供应商编码
'Brand' => $this->Brand,
'CurrentPage' => ''
);
$res = $this->obj_utils->xml_encode($GetHotelInfoRequest, 'GetHotelInfo');
$GetHotelInfo = $this->obj_utils->soapRequest('GetHotelInfo', $res); //发送soap请求
$result = $this->obj_utils->xml_to_array($GetHotelInfo);*/
//测试
$HotelList[0] = array(
'Hotel' => 12121,
'HotelName' => 'casdas',
'CountryName' => 'sadas',
'CityName' => 'dsadas',
'Address' => 'asdasd',
'Telephone' => 'sadas'
);
$HotelList[1] = array(
'Hotel' => 'weqeqwewq',
'HotelName' => 'casdas',
'CountryName' => 'sadas',
'CityName' => 'dsadas',
'Address' => 'asdasd',
'Telephone' => 'sadas'
);
$GetHotelInfoResponse = array(
'TotalPage' => 10,
'CurrentPage' => 1,
'TotalNum' => 1000,
'HotelList' => $HotelList,
);
$Response = array(
'HeaderInfo' => '',
'GetHotelInfoResponse' => $GetHotelInfoResponse
);

$RequestResponse['RequestResult'] = array(
'Message' => '',
'ResultCode' => '',
'Response' => $Response
);
$result['RequestResponse'] = $RequestResponse;
return $result;
}

/**
* User:Steven
*
* Desc:
*/
public function getZzHotelInfo()
{
$domain = new Domain_hotel();
$res=$domain->getHotelInfo();
return $res;
}
}

?>


+ 128
- 0
Ctrip/Common/SoapDiscovery.class.php View File

@@ -0,0 +1,128 @@
<?php

/**
* Copyright (c) 2005, Braulio Jos?Solano Rojas
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* Neither the name of the Solsoft de Costa Rica S.A. nor the names of its contributors may
* be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* @version $Id$
* @copyright 2005
*/

/**
* SoapDiscovery Class that provides Web Service Definition Language (WSDL).
*
* @package SoapDiscovery
* @author Braulio Jos?Solano Rojas
* @copyright Copyright (c) 2005 Braulio Jos?Solano Rojas
* @version $Id$
* @access public
* */
class SoapDiscovery {

private $class_name = '';
private $service_name = '';

/**
* SoapDiscovery::__construct() SoapDiscovery class Constructor.
*
* @param string $class_name
* @param string $service_name
* */
public function __construct($class_name = '', $service_name = '') {
$this->class_name = $class_name;
$this->service_name = $service_name;
}

/**
* SoapDiscovery::getWSDL() Returns the WSDL of a class if the class is instantiable.
*
* @return string
* */
public function getWSDL() {
if (empty($this->service_name)) {
throw new Exception('No service name.');
}
$headerWSDL = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$headerWSDL.= "<definitions name=\"$this->service_name\" targetNamespace=\"urn:$this->service_name\" xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:tns=\"urn:$this->service_name\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns=\"http://schemas.xmlsoap.org/wsdl/\">\n";
$headerWSDL.= "<types xmlns=\"http://schemas.xmlsoap.org/wsdl/\" />\n";

if (empty($this->class_name)) {
throw new Exception('No class name.');
}

$class = new ReflectionClass($this->class_name);

if (!$class->isInstantiable()) {
throw new Exception('Class is not instantiable.');
}

$methods = $class->getMethods();

$portTypeWSDL = '<portType name="' . $this->service_name . 'Port">';
$bindingWSDL = '<binding name="' . $this->service_name . 'Binding" type="tns:' . $this->service_name . "Port\">\n<soap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\" />\n";
$serviceWSDL = '<service name="' . $this->service_name . "\">\n<documentation />\n<port name=\"" . $this->service_name . 'Port" binding="tns:' . $this->service_name . "Binding\"><soap:address location=\"http://" . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['PHP_SELF'] . "\" />\n</port>\n</service>\n";
$messageWSDL = '';
foreach ($methods as $method) {
if ($method->isPublic() && !$method->isConstructor()) {
$portTypeWSDL.= '<operation name="' . $method->getName() . "\">\n" . '<input message="tns:' . $method->getName() . "Request\" />\n<output message=\"tns:" . $method->getName() . "Response\" />\n</operation>\n";
$bindingWSDL.= '<operation name="' . $method->getName() . "\">\n" . '<soap:operation soapAction="urn:' . $this->service_name . '#' . $this->class_name . '#' . $method->getName() . "\" />\n<input><soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</input>\n<output>\n<soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</output>\n</operation>\n";
$messageWSDL.= '<message name="' . $method->getName() . "Request\">\n";
$parameters = $method->getParameters();
foreach ($parameters as $parameter) {
$messageWSDL.= '<part name="' . $parameter->getName() . "\" type=\"xsd:string\" />\n";
}
$messageWSDL.= "</message>\n";
$messageWSDL.= '<message name="' . $method->getName() . "Response\">\n";
$messageWSDL.= '<part name="' . $method->getName() . "\" type=\"xsd:string\" />\n";
$messageWSDL.= "</message>\n";
}
}
$portTypeWSDL.= "</portType>\n";
$bindingWSDL.= "</binding>\n";
//return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>');
//生成wsdl文件,将上面的return注释
$fso = fopen($this->class_name . ".wsdl", "w");
fwrite($fso, sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'));
fclose($fso);
@chmod($fso,0777);
}

/**
* SoapDiscovery::getDiscovery() Returns discovery of WSDL.
*
* @return string
* */
public function getDiscovery() {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<disco:discovery xmlns:disco=\"http://schemas.xmlsoap.org/disco/\" xmlns:scl=\"http://schemas.xmlsoap.org/disco/scl/\">\n<scl:contractRef ref=\"http://" . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['PHP_SELF'] . "?wsdl\" />\n</disco:discovery>";
}

}

?>

+ 138
- 0
Ctrip/Common/Utils.php View File

@@ -0,0 +1,138 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/13
* Time: 15:17
*/
class roomOrderUtils
{
public $ctrip_url = 'http://127.0.0.1:20083/Ctrip/Service.php?wsdl';
public $UserID = "123456"; //合作方编码
public $RequestorId = "Ctrip.com"; //请求对象的编码,后备字段, 暂不处理,默认值Ctrip.com
public $AsyncRequest = "false"; //是否异步请求
public $UserName = "Zhilianjishuzhuanshu"; //用户名
public $Password = "zhilianzhuanshu11!!"; //密码
public $Version = "1.0"; //API版本号
public $url = ""; //请求URL

/**
* User:Steven
*
* Desc:发生soap请求
* @param $request_fun
* @param $param
* @return Exception|SoapFault
*/
public function soapRequest($request_fun, $param)
{
$soap = new SoapClient($this->ctrip_url, array('soap_version' => SOAP_1_2, 'trace' => TRUE, 'exceptions' => FALSE));
try {
$response = $soap->{$request_fun}($param);
return $response;
} catch (SoapFault $sf) {
return $sf;
/*print ($soap->__getLastRequest());
print ($soap->__getLastResponse());*/
}
}

/**
* User:Steven
*
* Desc:发送post请求(xml)
* @param $url
* @param $xmlData
* @return mixed
*/
public function xml_post_request($url, $xmlData)
{
$header[] = "Content-type: text/xml"; //定义content-type为xml,注意是数组
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlData);
$response = curl_exec($ch);
if (curl_errno($ch)) {
print curl_error($ch);
}
curl_close($ch);
return $response;
}

public function execute($request, $session = null)
{
$this->data = $this->format == 'json' ? json_encode($request) : $this->xml_encode($request);
$this->Url = 'http://' . str_replace(array('http://', 'https://'), '', $this->Url);
$postUrl = $this->Url . "?method={$this->requestMethod}&data=" . urlencode($this->data);
return $this->request_by_curl($postUrl);
}

/**
* User:Steven
*
* Desc:编辑符合携程需要的XML格式
* @param $data 请求体
* @param $RequestTypeName 请求方法名称
* @return string
*/
public function xml_encode($data, $RequestTypeName)
{
$timeStamp = date("Y-m-d H:i:s", time());
$xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$xml .= "<request>";
$xml .= "<HeaderInfo UserID=\"$this->UserID\" RequestorId=\"$this->RequestorId\" AsyncRequest=\"$this->AsyncRequest\" TimeStamp=\"$timeStamp\"><Authentication UserName=\"$this->UserName\" Password=\"$this->Password\"/><RequestType Name=\"$RequestTypeName\" Version=\"$this->Version\"/></HeaderInfo> ";
$xml .= $this->data_to_xml($data);
$xml .= "</request>";
return $xml;
}

/**
* User:Steven
*
* Desc:将xml转换为数组
* @param $xml
* @return mixed
*/
public function xml_to_array($xml)
{
$ob = simplexml_load_string($xml);
$json = json_encode($ob);
$array = json_decode($json, true);
return $array;
}

/**
* User:Steven
*
* Desc:将数组转化成xml
* @param $data
* @return string
*/
public function data_to_xml($data)
{
if (is_object($data)) {
$data = get_object_vars($data);
}
$xml = '';
foreach ($data as $key => $val) {
if (is_null($val)) {
$xml .= "<$key/>\n";
} else {
if (!is_numeric($key)) {
$xml .= "<$key>";
}
$xml .= (is_array($val) || is_object($val)) ? $this->data_to_xml($val) : $val;
if (!is_numeric($key)) {
$xml .= "</$key>";
}
}
}
return $xml;
}
}



+ 19
- 0
Ctrip/Domain/hotel.php View File

@@ -0,0 +1,19 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/15
* Time: 13:43
*
*/
class Domain_hotel
{
public function getHotelInfo()
{
$model = new Model_hotel();
$res = $model->getHotelInfo();
return $res;

}
}

+ 20
- 0
Ctrip/Model/hotel.php View File

@@ -0,0 +1,20 @@
<?php

/**
* Created by PhpStorm.
* User: Steven
* Date: 2017/3/15
* Time: 13:20
*
*/
class Model_hotel extends PhalApi_Model_NotORM
{
public function getHotelInfo()
{
//原生SQL
/* $sql = 'select HOTEL_ID,HOTEL_NAME,HOTEL_ADDRESS fROM opera_hotel where CANCEL_FLAG=0';
$rows = $this->getORM()->queryAll($sql, array());*/
$rs = DI()->notorm->opera_hotel->select('hotel_id,hotel_name,hotel_address')->where('CANCEL_FLAG = ?', 0)->fetchAll();
return $rs;
}
}

+ 9
- 0
Data/phalapi_test.sql View File

@@ -0,0 +1,9 @@
CREATE TABLE `phalapi_test`.`tbl_user` (
`id` INT NOT NULL,
`name` VARCHAR(45) NULL,
`note` VARCHAR(45) NULL,
PRIMARY KEY (`id`));


INSERT INTO `phalapi_test`.`tbl_user` (`id`, `name`, `note`) VALUES ('1', 'dogstar', 'oschina');


+ 2
- 0
Data/user.sql View File

@@ -0,0 +1,2 @@
`name` VARCHAR(45) NULL,
`note` VARCHAR(45) NULL,

+ 39
- 0
Demo/Api/Default.php View File

@@ -0,0 +1,39 @@
<?php
/**
* 默认接口服务类
*
* @author: dogstar <chanzonghuang@gmail.com> 2014-10-04
*/

class Api_Default extends PhalApi_Api {

public function getRules() {
return array(
'*' => array( //通用接口参数
'code' => array('name' => 'code', 'require' => true, 'min' => 4, 'max' => 4),
),
'index' => array( //指定接口参数
'username' => array('name' => 'username', 'default' => 'PHPer', ),
),
);
}
/**
* 默认接口服务
* @return string title 标题
* @return string content 内容
* @return string version 版本,格式:X.X.X
* @return int time 当前时间戳
*/
public function index() {
return array(
'title' => 'Hello World!',
'content' => T('Hi {name}, welcome to use PhalApi!', array('name' => $this->username)),
'version' => PHALAPI_VERSION,
'time' => $_SERVER['REQUEST_TIME'],
);
}



}

+ 70
- 0
Demo/Api/User.php View File

@@ -0,0 +1,70 @@
<?php

/**
* 用户信息类
*/
class Api_User extends PhalApi_Api {

public function getRules() {
return array(
'getBaseInfo' => array(
'userId' => array('name' => 'user_id', 'type' => 'int', 'min' => 1, 'require' => true, 'desc' => '用户ID'),
),
'getMultiBaseInfo' => array(
'userIds' => array('name' => 'user_ids', 'type' => 'array', 'format' => 'explode', 'require' => true, 'desc' => '用户ID,多个以逗号分割'),
),
);
}

/**
* 获取用户基本信息
* @desc 用于获取单个用户基本信息
* @return int code 操作码,0表示成功, 1表示用户不存在
* @return object info 用户信息对象
* @return int info.id 用户ID
* @return string info.name 用户名字
* @return string info.note 用户来源
* @return string msg 提示信息
*/
public function getBaseInfo() {
$rs = array('code' => 0, 'msg' => '', 'info' => array()); //定义返回值

$domain = new Domain_User();
$info = $domain->getBaseInfo($this->userId);

if (empty($info)) {
DI()->logger->debug('user not found', $this->userId);

$rs['code'] = 1;
$rs['msg'] = T('user not exists');
return $rs;
}

$rs['info'] = $info;

return $rs;
}

/**
* 批量获取用户基本信息
* @desc 用于获取多个用户基本信息
* @return int code 操作码,0表示成功
* @return array list 用户列表
* @return int list[].id 用户ID
* @return string list[].name 用户名字
* @return string list[].note 用户来源
* @return string msg 提示信息
* @exception 400 参数传递错误
* @exception 500 服务器内部错误
*/
public function getMultiBaseInfo() {
$rs = array('code' => 0, 'msg' => '', 'list' => array());

$domain = new Domain_User();
foreach ($this->userIds as $userId) {
$rs['list'][] = $domain->getBaseInfo($userId);
}

return $rs;
}
}

+ 33
- 0
Demo/Domain/User.php View File

@@ -0,0 +1,33 @@
<?php
//领域层主要是关注复杂业务的处理,以及缓存的处理、耗时操作后台异步处理等,并调用Model持久层获取需要的数据。因此,是Api与Model层之间的桥梁。
class Domain_User {

public function getBaseInfo($userId) {
$rs = array();

$userId = intval($userId);
if ($userId <= 0) {
return $rs;
}

// 版本1:简单的获取
$model = new Model_User();
$rs = $model->getByUserId($userId);

// 版本2:使用单点缓存/多级缓存 (应该移至Model层中)
/**
$model = new Model_User();
$rs = $model->getByUserIdWithCache($userId);
*/

// 版本3:缓存 + 代理
/**
$query = new PhalApi_ModelQuery();
$query->id = $userId;
$modelProxy = new ModelProxy_UserBaseInfo();
$rs = $modelProxy->getData($query);
*/

return $rs;
}
}

+ 27
- 0
Demo/Model/User.php View File

@@ -0,0 +1,27 @@
<?php

class Model_User extends PhalApi_Model_NotORM {

public function getByUserId($userId) {
return $this->getORM()
->select('*')
->where('id = ?', $userId)
->fetch();
}

public function getByUserIdWithCache($userId) {
$key = 'userbaseinfo_' . $userId;
$rs = DI()->cache->get($key);
if ($rs === NULL) {
$rs = $this->getByUserId($userId);
DI()->cache->set($key, $rs, 600);
}
return $rs;
}

/**
protected function getTableName($id) {
return 'user';
}
*/
}

+ 21
- 0
Demo/ModelProxy/UserBaseInfo.php View File

@@ -0,0 +1,21 @@
<?php
/**
* @author dogstar <chanzonghuang@gmail.com> 2015-02-22
*/

class ModelProxy_UserBaseInfo extends PhalApi_ModelProxy {

protected function doGetData($query) {
$model = new Model_User();

return $model->getByUserId($query->id);
}

protected function getKey($query) {
return 'userbaseinfo_' . $query->id;
}

protected function getExpire($query) {
return 600;
}
}

+ 59
- 0
Demo/Tests/Api/Api_Default_Test.php View File

@@ -0,0 +1,59 @@
<?php
/**
* PhpUnderControl_ApiDefault_Test
*
* 针对 ../../Api/Default.php Api_Default 类的PHPUnit单元测试
*
* @author: dogstar 20150201
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Api_Default')) {
require dirname(__FILE__) . '/../../Api/Default.php';
}

class PhpUnderControl_ApiDefault_Test extends PHPUnit_Framework_TestCase
{
public $apiDefault;

protected function setUp()
{
parent::setUp();

$this->apiDefault = new Api_Default();
}

protected function tearDown()
{
}


/**
* @group testGetRules
*/
public function testGetRules()
{
$rs = $this->apiDefault->getRules();

$this->assertNotEmpty($rs);
}

public function testIndex()
{
//Step 1. 构建请求URL
$url = 'service=Default.Index&username=dogstar';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('title', $rs);
$this->assertArrayHasKey('content', $rs);
$this->assertArrayHasKey('version', $rs);
$this->assertArrayHasKey('time', $rs);

$this->assertEquals('dogstar您好,欢迎使用PhalApi!', $rs['content']);
}
}

+ 84
- 0
Demo/Tests/Api/Api_User_Test.php View File

@@ -0,0 +1,84 @@
<?php
/**
* PhpUnderControl_ApiUser_Test
*
* 针对 ../../Demo/Api/User.php Api_User 类的PHPUnit单元测试
*
* @author: dogstar 20150128
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Api_User')) {
require dirname(__FILE__) . '/../../Demo/Api/User.php';
}

class PhpUnderControl_ApiUser_Test extends PHPUnit_Framework_TestCase
{
public $apiUser;

protected function setUp()
{
parent::setUp();

$this->apiUser = new Api_User();
}

protected function tearDown()
{
}


/**
* @group testGetRules
*/
public function testGetRules()
{
$rs = $this->apiUser->getRules();
}

/**
* @group testGetBaseInfo
*/
public function testGetBaseInfo()
{
//Step 1. 构建请求URL
$url = 'service=User.GetBaseInfo&user_id=1';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('code', $rs);
$this->assertArrayHasKey('msg', $rs);
$this->assertArrayHasKey('info', $rs);

$this->assertEquals(0, $rs['code']);

$this->assertEquals('dogstar', $rs['info']['name']);
$this->assertEquals('oschina', $rs['info']['note']);
}

public function testGetMultiBaseInfo()
{
//Step 1. 构建请求URL
$url = 'service=User.GetMultiBaseInfo&user_ids=1,2,3';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('code', $rs);
$this->assertArrayHasKey('msg', $rs);
$this->assertArrayHasKey('list', $rs);

foreach ($rs['list'] as $item) {
$this->assertArrayHasKey('id', $item);
$this->assertArrayHasKey('name', $item);
$this->assertArrayHasKey('note', $item);
}
}

}

+ 48
- 0
Demo/Tests/Domain/Domain_User_Test.php View File

@@ -0,0 +1,48 @@
<?php
/**
* PhpUnderControl_DomainUser_Test
*
* 针对 ./Demo/Domain/User.php Domain_User 类的PHPUnit单元测试
*
* @author: dogstar 20150208
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Domain_User')) {
require dirname(__FILE__) . '/./Demo/Domain/User.php';
}

class PhpUnderControl_DomainUser_Test extends PHPUnit_Framework_TestCase
{
public $domainUser;

protected function setUp()
{
parent::setUp();

$this->domainUser = new Domain_User();
}

protected function tearDown()
{
}


/**
* @group testGetBaseInfo
*/
public function testGetBaseInfo()
{
$userId = '1';

$rs = $this->domainUser->getBaseInfo($userId);

$this->assertArrayHasKey('id', $rs);
$this->assertArrayHasKey('name', $rs);
$this->assertArrayHasKey('note', $rs);

$this->assertEquals('dogstar', $rs['name']);
}

}

+ 48
- 0
Demo/Tests/Model/Model_User_Test.php View File

@@ -0,0 +1,48 @@
<?php
/**
* PhpUnderControl_ModelUser_Test
*
* 针对 ./Demo/Model/User.php Model_User 类的PHPUnit单元测试
*
* @author: dogstar 20150208
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Model_User')) {
require dirname(__FILE__) . '/./Demo/Model/User.php';
}

class PhpUnderControl_ModelUser_Test extends PHPUnit_Framework_TestCase
{
public $modelUser;

protected function setUp()
{
parent::setUp();

$this->modelUser = new Model_User();
}

protected function tearDown()
{
}


/**
* @group testGetByUserId
*/
public function testGetByUserId()
{
$userId = '1';

$rs = $this->modelUser->getByUserId($userId);

$this->assertArrayHasKey('id', $rs);
$this->assertArrayHasKey('name', $rs);
$this->assertArrayHasKey('note', $rs);

$this->assertEquals('dogstar', $rs['name']);
}

}

+ 34
- 0
Demo/Tests/phpunit.xml View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<php>
<ini name="intl.default_locale" value="en"/>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
</php>

<testsuites>
<testsuite name="common">
<directory suffix="Test.php">./Common</directory>
</testsuite>
<testsuite name="api">
<directory suffix="Test.php">./Api</directory>
</testsuite>
<testsuite name="Domain">
<directory suffix="Test.php">./Domain</directory>
</testsuite>
<testsuite name="Model">
<directory suffix="Test.php">./Model</directory>
</testsuite>
</testsuites>
</phpunit>


+ 25
- 0
Demo/Tests/phpunit_user_getbaseinfo.xml View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<php>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
</php>

<testsuites>
<testsuite name="Test Suite">
<file>./Api/Api_User_Test.php</file>
<file>./Domain/Domain_User_Test.php</file>
<file>./Model/Model_User_Test.php</file>
</testsuite>
</testsuites>
</phpunit>

+ 16
- 0
Demo/Tests/test_env.php View File

@@ -0,0 +1,16 @@
<?php
/**
* demo接口测试入口
* @author dogstar 2015-01-28
*/
/** ---------------- 根目录定义,自动加载 ---------------- **/

require_once dirname(__FILE__) . '/../../Public/init.php';

DI()->loader->addDirs('Demo');

//日记纪录 - Explorer
DI()->logger = new PhalApi_Logger_Explorer(
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);


+ 10
- 0
LICENSE.md View File

@@ -0,0 +1,10 @@
##协议许可的权利 - GPL协议
PhalApi官方网站为 http://www.phalapi.net,依法独立拥有 PhalApi 及官网发布的PhalApi衍生产品著作权。
PhalApi及其衍生产品著作权受到法律和国际公约保护。使用者需仔细阅读本协议,在理解、同意、并遵守本协
议的全部条款后,方可开始使用 PhalApi及其衍生 软件。
本授权协议适用于 http://www.phalapi.net 发布的所有应用程序,PhalApi官方网站拥有对本授权协议的最终
解释权。
PhalApi是一个PHP轻量级开源接口框架,并承诺永久免费!请放心使用!

+ 6
- 0
Language/en/common.php View File

@@ -0,0 +1,6 @@
<?php

return array(
'Hello {name}, Welcome to use PhalApi!' => 'Hello {name}, Welcome to use PhalApi!',
'user not exists' => 'user not exists',
);

+ 14
- 0
Language/zh_cn/common.php View File

@@ -0,0 +1,14 @@
<?php
/**
* 翻译说明:
*
* 1、带大括号的保留原来写法,如:{name},会被系统动态替换
* 2、没在以下出现的,可以自行追加
*
* @author dogstar <chanzonghuang@gmail.com> 2015-02-09
*/

return array(
'Hi {name}, welcome to use PhalApi!' => '{name}您好,欢迎使用PhalApi!',
'user not exists' => '用户不存在',
);

+ 6
- 0
Language/zh_tw/common.php View File

@@ -0,0 +1,6 @@
<?php

return array(
'Hi {name}, welcome to use PhalApi!' => '{name}您好,歡迎使用PhalApi!',
'user not exists' => '用戶不存在',
);

+ 7
- 0
Library/README.md View File

@@ -0,0 +1,7 @@
##扩展类库

请查看:

```
http://git.oschina.net/dogstar/PhalApi-Library
```

+ 33
- 0
Library/Task/Config/app.php View File

@@ -0,0 +1,33 @@
<?php

return array(

//请将以下配置拷贝到 ./Config/app.php 文件中

/**
* 计划任务配置
*/
'Task' => array(
//MQ队列设置,可根据使用需要配置
'mq' => array(
'file' => array(
'path' => API_ROOT . '/Runtime',
'prefix' => 'phalapi_task',
),
'redis' => array(
'host' => '127.0.0.1',
'port' => 6379,
'prefix' => 'phalapi_task',
'auth' => '',
),
),

//Runner设置,如果使用远程调度方式,请加此配置
'runner' => array(
'remote' => array(
'host' => 'http://library.phalapi.net/demo/',
'timeoutMS' => 3000,
),
),
),
);

+ 21
- 0
Library/Task/Config/dbs.php View File

@@ -0,0 +1,21 @@
<?php

return array(

'tables' => array(

//请将以下配置拷贝到 ./Config/dbs.php 文件对应的位置中,未配置的表将使用默认路由

//10张表,可根据需要,自行调整表前缀、主键名和路由
'task_mq' => array(
'prefix' => 'phalapi_',
'key' => 'id',
'map' => array(
array('db' => 'db_demo'),
array('start' => 0, 'end' => 9, 'db' => 'db_demo'),
),
),
)
);



+ 109
- 0
Library/Task/Data/phalapi_task_mq.sql View File

@@ -0,0 +1,109 @@
CREATE TABLE `phalapi_task_mq` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_0` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_2` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_3` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_4` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_5` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_6` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_7` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_8` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_9` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


+ 13
- 0
Library/Task/Data/phalapi_task_progress.sql View File

@@ -0,0 +1,13 @@
CREATE TABLE `phalapi_task_progress` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT '' COMMENT '任务标题',
`trigger_class` varchar(50) DEFAULT '' COMMENT '触发器类名',
`fire_params` varchar(255) DEFAULT '' COMMENT '需要传递的参数,格式自定',
`interval_time` int(11) DEFAULT '0' COMMENT '执行间隔,单位:秒',
`enable` tinyint(1) DEFAULT '1' COMMENT '是否启动,1启动,0禁止',
`result` varchar(255) DEFAULT '' COMMENT '运行的结果,以json格式保存',
`state` tinyint(1) DEFAULT '0' COMMENT '进程状态,0空闲,1运行中,-1异常退出',
`last_fire_time` int(11) DEFAULT '0' COMMENT '上一次运行时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


+ 3
- 0
Library/Task/Data/task_mq.sql View File

@@ -0,0 +1,3 @@
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',

+ 8
- 0
Library/Task/Data/task_progress.sql View File

@@ -0,0 +1,8 @@
`title` varchar(200) DEFAULT '' COMMENT '任务标题',
`trigger_class` varchar(50) DEFAULT '' COMMENT '触发器类名',
`fire_params` varchar(255) DEFAULT '' COMMENT '需要传递的参数,格式自定',
`interval_time` int(11) DEFAULT '0' COMMENT '执行间隔,单位:秒',
`enable` tinyint(1) DEFAULT '1' COMMENT '是否启动,1启动,0禁止',
`result` varchar(255) DEFAULT '' COMMENT '运行的结果,以json格式保存',
`state` tinyint(1) DEFAULT '0' COMMENT '进程状态,0空闲,1运行中,-1异常退出',
`last_fire_time` int(11) DEFAULT '0' COMMENT '上一次运行时间',

+ 44
- 0
Library/Task/Lite.php View File

@@ -0,0 +1,44 @@
<?php
/**
* 计划任务客户端类 Task_Lite
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_Lite {

/**
* Task_MQ $mq MQ队列
*/
protected $mq;

public function __construct(Task_MQ $mq) {
$this->mq = $mq;
DI()->loader->addDirs('./Library/Task/Task');
}

/**
* 添加一个计划任务到MQ队列
* @param string $service 接口服务名称,如:Default.Index
* @param array $params 接口服务参数
*/
public function add($service, $params = array()) {
if (empty($service) || count(explode('.', $service)) < 2) {
return FALSE;
}
if (!is_array($params)) {
return FALSE;
}

$rs = $this->mq->add($service, $params);

if (!$rs) {
DI()->logger->debug('task add a new mq',
array('service' => $service, 'params' => $params));

return FALSE;
}

return TRUE;
}
}

+ 25
- 0
Library/Task/MQ.php View File

@@ -0,0 +1,25 @@
<?php
/**
* MQ队列接口
*
* - 单个添加,批量弹出
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

interface Task_MQ {

/**
* 单个添加
* @param string $service 接口服务名称,如:Default.Index
* @param array $params 接口服务参数
*/
public function add($service, $params = array());

/**
* 批量弹出
* @param string $service 需要获取的接口服务名称
* @param int $num 弹出的个数
*/
public function pop($service, $num = 1);
}

+ 34
- 0
Library/Task/MQ/Array.php View File

@@ -0,0 +1,34 @@
<?php
/**
* 数组MQ
*
* - 用于单元测试,或者临时一次性执行
* - 队列存放于内存的数组中
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_MQ_Array implements Task_MQ {

protected $list = array();

public function add($service, $params = array()) {
if (!isset($this->list[$service])) {
$this->list[$service] = array();
}

$this->list[$service][] = $params;

return TRUE;
}

public function pop($service, $num = 1) {
if (empty($this->list[$service])) {
return array();
}

$rs = array_splice($this->list[$service], 0, $num);

return $rs;
}
}

+ 21
- 0
Library/Task/MQ/DB.php View File

@@ -0,0 +1,21 @@
<?php
/**
* 数据库MQ
*
* - 队列存放于数据库表中,并支持分表
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_MQ_DB implements Task_MQ {

public function add($service, $params = array()) {
$model = new Model_Task_TaskMq();
return $model->add($service, $params);
}

public function pop($service, $num = 1) {
$model = new Model_Task_TaskMq();
return $model->pop($service, $num);
}
}

+ 27
- 0
Library/Task/MQ/File.php View File

@@ -0,0 +1,27 @@
<?php
/**
* 文件MQ
*
* - 队列存放于本地文件 中,不支持分布式MQ
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_MQ_File extends Task_MQ_KeyValue {

public function __construct(PhalApi_Cache_File $fileCache = NULL) {
if ($fileCache === NULL) {
$config = DI()->config->get('app.Task.mq.file');
if (!isset($config['path'])) {
$config['path'] = API_ROOT . '/Runtime';
}
if (!isset($config['prefix'])) {
$config['prefix'] = 'phalapi_task';
}

$fileCache = new PhalApi_Cache_File($config);
}

parent::__construct($fileCache);
}
}

+ 60
- 0
Library/Task/MQ/KeyValue.php View File

@@ -0,0 +1,60 @@
<?php
/**
* 键-值对的 MQ
*
* - 队列存放于Key-Value的缓存中
*
* @author dogstar <chanzonghuang@gmail.com> 20160430
*/

class Task_MQ_KeyValue implements Task_MQ {

/**
* @var PhalApi_Cache_Memcached/PhalApi_Cache_Memcache/PhalApi_Cache_File $kvCache 缓存实例
*/
protected $kvCache;

public function __construct(PhalApi_Cache $kvCache) {
$this->kvCache = $kvCache;
}

public function add($service, $params = array()) {
$list = $this->kvCache->get($service);
if (empty($list)) {
$list = array();
}

$list[] = $params;

$this->kvCache->set($service, $list, $this->getExpireTime());

$list = $this->kvCache->get($service);

return true;
}

public function pop($service, $num = 1) {
$rs = array();
if ($num <= 0) {
return $rs;
}

$list = $this->kvCache->get($service);
if (empty($list)) {
$list = array();
}

$rs = array_splice($list, 0, $num);

$this->kvCache->set($service, $list, $this->getExpireTime());

return $rs;
}

/**
* 最大缓存时间,一年
*/
protected function getExpireTime() {
return 31536000;
}
}

+ 39
- 0
Library/Task/MQ/Memcached.php View File

@@ -0,0 +1,39 @@
<?php
/**
* Memcached MQ
*
* - 队列存放于Memcached/Memcache,但须注意MC默认情况下单个key最大只支持1M大小
*
* @author dogstar <chanzonghuang@gmail.com> 20160430
*/

class Task_MQ_Memcached extends Task_MQ_KeyValue {

public function __construct(PhalApi_Cache $mcCache = NULL) {
if ($mcCache === NULL) {
$config = DI()->config->get('app.Task.mq.mc');
if (!isset($config['host'])) {
$config['host'] = '127.0.0.1';
}
if (!isset($config['port'])) {
$config['port'] = 11211;
}

//优先使用memcached
$mcCache = extension_loaded('memcached')
? new PhalApi_Cache_Memcached($config)
: new PhalApi_Cache_Memcache($config);
}

$mcCache->set('123123', time(), 31536000);

parent::__construct($mcCache);
}

/**
* 最大缓存时间,29天,因为MC的过期时间不能超过30天
*/
protected function getExpireTime() {
return 2505600;
}
}

+ 50
- 0
Library/Task/MQ/Redis.php View File

@@ -0,0 +1,50 @@
<?php

class Task_MQ_Redis implements Task_MQ {

protected $redisCache;

public function __construct(PhalApi_Cache_Redis $redisCache= NULL) {
if ($redisCache === NULL) {
$config = DI()->config->get('app.Task.mq.redis');

if (!isset($config['host'])) {
$config['host'] = '127.0.0.1';
}
if (!isset($config['port'])) {
$config['port'] = 6379;
}
if (!isset($config['prefix'])) {
$config['prefix'] = 'phalapi_task';
}

$redisCache = new PhalApi_Cache_Redis($config);
}

$this->redisCache = $redisCache;
}

public function add($service, $params = array()) {
$num = $this->redisCache->rPush($service, $params);

return $num > 0 ? TRUE : FALSE;
}

public function pop($service, $num = 1) {
$rs = array();

while($num > 0) {
$params = $this->redisCache->lPop($service);

if ($params === NULL) {
break;
}

$rs[] = $params;

$num--;
}

return $rs;
}
}

+ 87
- 0
Library/Task/Progress.php View File

@@ -0,0 +1,87 @@
<?php
/**
* 计划任务进程类
*
* @author dogstar <chanzonghuang@gmail.com> 20150520
*/

class Task_Progress {

/**
* @var int MAX_LAST_FIRE_TIME_INTERVAL 修复的最大时间间隔
*/
const MAX_LAST_FIRE_TIME_INTERVAL = 86400;

/**
* @var Model_Task_TaskProgress 对数据库的操作
*/
protected $model;

public function __construct() {
$this->model = new Model_Task_TaskProgress();
}

/**
* 进行进程调度
*
* - 1、尝试修复异常的任务
* - 2、执行全部空闲的任务
*/
public function run() {
$this->tryToResetWrongItems();

$this->runAllWaittingItems();

return TRUE;
}

protected function tryToResetWrongItems() {
$maxLastFireTime = $_SERVER['REQUEST_TIME'] - self::MAX_LAST_FIRE_TIME_INTERVAL;

$wrongItems = $this->model->getWrongItems($maxLastFireTime);

foreach ($wrongItems as $item) {
$this->model->resetWrongItems($item['id']);

DI()->logger->debug('task try to reset wrong items', $item);
}
}

protected function runAllWaittingItems() {
$waittingItems = $this->model->getAllWaittingItems();

foreach ($waittingItems as $item) {
//
if (!$this->model->isRunnable($item['id'])) {
continue;
}

$class = $item['trigger_class'];
$params = $item['fire_params'];

if (empty($class) || !class_exists($class)) {
DI()->logger->error('Error: task can not run illegal class', $item);
$this->model->updateExceptionItem($item['id'], 'task can not run illegal class');
continue;
}

$trigger = new $class();
if (!is_callable(array($class, 'fire'))) {
DI()->logger->error('Error: task can not call fire()', $item);
$this->model->updateExceptionItem($item['id'], 'task can not call fire()');
continue;
}

$this->model->setRunningState($item['id']);

try {
$result = call_user_func(array($trigger, 'fire'), $params);

$this->model->updateFinishItem($item['id'], $result);
} catch (Exception $ex) {
throw $ex;
$this->model->updateExceptionItem($item['id'], $ex->getMessage());
}
}
}
}

+ 15
- 0
Library/Task/Progress/Trigger.php View File

@@ -0,0 +1,15 @@
<?php
/**
* 触发器接口
*
* @author dogstar <chanzonghuang@gmail.com> 20150520
*/

interface Task_Progress_Trigger {

/**
* 进程的具体操作
* @param string $params 对应数据库表task_progress.fire_params字段
*/
public function fire($params);
}

+ 22
- 0
Library/Task/Progress/Trigger/Common.php View File

@@ -0,0 +1,22 @@
<?php
/**
* 通用 触发器接口
*
* @author dogstar <chanzonghuang@gmail.com> 20150520
*/

class Task_Progress_Trigger_Common implements Task_Progress_Trigger {

public function fire($params) {
$paramsArr = explode('&', $params);

$service = !empty($paramsArr[0]) ? trim($paramsArr[0]) : '';
$mqClass = !empty($paramsArr[1]) ? trim($paramsArr[1]) : 'Task_MQ_Redis';
$runnerClass = !empty($paramsArr[2]) ? trim($paramsArr[2]) : 'Task_Runner_Local';

$mq = new $mqClass();
$runner = new $runnerClass($mq);

return $runner->go($service);
}
}

+ 81
- 0
Library/Task/Runner.php View File

@@ -0,0 +1,81 @@
<?php
/**
* 计划任务调度器
*
* - 异常失败,会轮循重试
* - 彩蛋式的抽象方法名
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

abstract class Task_Runner {

/**
* @var MQ队列实例
*/
protected $mq;

/**
* @var int $step 批次的数据,步长
*/
protected $step;

/**
* @param Task_MQ $mq MQ队列实例
* @param int $step 批次的数据,步长
*/
public function __construct(Task_MQ $mq, $step = 10) {
$this->mq = $mq;

$this->step = max(1, intval($step));
}

/**
* 执行任务
* @param string $service MQ中的接口服务名称,如:Default.Index
* @return array('total' => 总数量, 'fail' => 失败数量)
*/
public function go($service) {
$rs = array('total' => 0, 'fail' => 0);

$todoList = $this->mq->pop($service, $this->step);
$failList = array();

while (!empty($todoList)) {
$rs['total'] += count($todoList);

foreach ($todoList as $params) {
try {
$isFinish = $this->youGo($service, $params);

if (!$isFinish) {
$rs['fail'] ++;
}
} catch (PhalApi_Exception_InternalServerError $ex) {
$rs['fail'] ++;

$failList[] = $params;

DI()->logger->error('task occur exception to go',
array('service' => $service, 'params' => $params, 'error' => $ex->getMessage()));
}
}

$todoList = $this->mq->pop($service, $this->step);
}

foreach ($failList as $params) {
$this->mq->add($service, $params);
}

return $rs;
}

/**
* 具体的执行,这里使用了一个彩蛋的命名
* @param string $service MQ中的接口服务名称,如:Default.Index
* @param array $params 参数
* @return boolean 成功返回TRUE,失败返回FALSE
*/
abstract protected function youGo($service, $params);
}

+ 34
- 0
Library/Task/Runner/Local.php View File

@@ -0,0 +1,34 @@
<?php
/**
* 本地调度器 Task_Runner_Local
*
* - 本地内部调度
* - 不能在Api请求时进行此调度
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_Runner_Local extends Task_Runner {

protected function youGo($service, $params) {
$params['service'] = $service;

DI()->request = new PhalApi_Request($params);
DI()->response = new PhalApi_Response_Json();

$phalapi = new PhalApi();
$rs = $phalapi->response();
$apiRs = $rs->getResult();

if ($apiRs['ret'] != 200) {
DI()->logger->debug('task local go fail',
array('servcie' => $service, 'params' => $params, 'rs' => $apiRs));

return FALSE;
}

return TRUE;
}

}


+ 60
- 0
Library/Task/Runner/Remote.php View File

@@ -0,0 +1,60 @@
<?php
/**
* 远程调度器 Task_Runner_Remote
*
* - 通过远程请求接口实现任务调度
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Task_Runner_Remote extends Task_Runner {

/**
* @var Task_Runner_Remote_Connector 远程接口连接器实例
*/
protected $contector;

/**
* @var int $timeoutMS 接口超时(单位:毫秒)
*/
protected $timeoutMS;

/**
* @var int 默认最大接口超时
*/
const MAX_TIMEOUT_MS = 3000;

public function __construct(Task_MQ $mq, $step = 10, Task_Runner_Remote_Connector $contector = NULL) {
$config = DI()->config->get('app.Task.runner.remote');

if ($contector === NULL) {
if (empty($config['host'])) {
throw new PhalApi_Exception_InternalServerError(T('task miss api host for'));
}
$contector = new Task_Runner_Remote_Connector_Http($config);
}

$this->contector = $contector;
$this->timeoutMS = isset($config['timeoutMS']) ? intval($config['timeoutMS']) : self::MAX_TIMEOUT_MS;

parent::__construct($mq, $step);
}

protected function youGo($service, $params) {
$rs = $this->contector->request($service, $params, $this->timeoutMS);

if ($this->contector->getRet() == 404) {
throw PhalApi_Exception_InternalServerError('task request api time out',
array('url' => $this->contector->getUrl()));
}

$isOk = $this->contector->getRet() == 200 ? TRUE : FALSE;

if (!$isOk) {
DI()->logger->debug('task remote request not ok',
array('url' => $this->contector->getUrl(), 'ret' => $this->contector->getRet(), 'msg' => $this->contector->getMsg()));
}

return $isOk;
}
}

+ 80
- 0
Library/Task/Runner/Remote/Connector.php View File

@@ -0,0 +1,80 @@
<?php
/**
* 远程接口连接器 Task_Runner_Remote_Connector
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

abstract class Task_Runner_Remote_Connector {

protected $host;

protected $params = array();

protected $moreParams = array();

protected $url;
protected $ret;
protected $msg;
protected $data = array();

public function __construct($config) {
$this->host = $config['host'];
$this->moreParams = isset($config['params']) ? $config['params'] : array();
}

/**
* 接口请求,超时时ret为404
* @param string $service MQ中的接口服务名称,如:Default.Index
* @param array $params 参数
* @param int $timeoutMS 接口超时(单位:毫秒)
* @return array
*/
public function request($service, $params = array(), $timeoutMs = 3000) {
$this->url = $this->host . '?service=' . $service;
$params = array_merge($this->moreParams, $params);

$apiRs = $this->doRequest($this->url, $params, $timeoutMs);

if ($apiRs === FALSE) {
$this->ret = 404;
$this->msg = T('time out');

DI()->logger->debug('task request api time out', array('url' => $this->url));

return $this->getData();
}

$rs = json_decode($apiRs, true);

if (empty($rs) || !isset($rs['ret'])) {
$this->ret = 500;
$this->msg = T('nothing return or illegal json: {rs}', array('rs' => $apiRs));
return $this->getData();
}

$this->ret = $rs['ret'];
$this->data = $rs['data'];
$this->msg = $rs['msg'];

return $this->getData();
}

public function getRet() {
return $this->ret;
}

public function getData() {
return $this->data;
}

public function getMsg() {
return $this->msg;
}

public function getUrl() {
return $this->url;
}

abstract protected function doRequest($url, $data, $timeoutMs);
}

+ 10
- 0
Library/Task/Runner/Remote/Connector/Http.php View File

@@ -0,0 +1,10 @@
<?php

class Task_Runner_Remote_Connector_Http extends Task_Runner_Remote_Connector {

protected function doRequest($url, $data, $timeoutMs) {
$curl = DI()->get('curl', 'PhalApi_CUrl');

return $curl->post($url, $data, $timeoutMs);
}
}

+ 60
- 0
Library/Task/Task/Model/Task/TaskMq.php View File

@@ -0,0 +1,60 @@
<?php
/**
* 数据库MQ
*
* - 队列存放于数据库表中,并支持分表
*
* @author dogstar <chanzonghuang@gmail.com> 20150516
*/

class Model_Task_TaskMq extends PhalApi_Model_NotORM {

protected function getTableName($id = NULL) {
$prefix = hexdec(substr(sha1($id), -1)) % 10;
return 'task_mq_' . $prefix;
}

public function add($service, $params = array()) {
$data = array(
'service' => $service,
'params' => json_encode($params),
'create_time' => time(),
);

$id = $this->insert($data, $service);

return $id > 0 ? TRUE : FALSE;
}

public function pop($service, $num = 1) {
$rows = $this->getORM($service)
->select('id, params')
->where('service', $service)
->order('id ASC')
->limit(0, $num)
->fetchAll();

if (empty($rows)) {
return array();
}

$ids = array();
foreach ($rows as $row) {
$ids[] = $row['id'];
}

$this->getORM($service)->where('id', $ids)->delete();

$rs = array();
foreach ($rows as $row) {
$params = json_decode($row['params'], TRUE);
if (!is_array($params)) {
$params = array();
}

$rs[] = $params;
}

return $rs;
}
}

+ 76
- 0
Library/Task/Task/Model/Task/TaskProgress.php View File

@@ -0,0 +1,76 @@
<?php

class Model_Task_TaskProgress extends PhalApi_Model_NotORM {

const STATE_WAITTING = 0;
const STATE_RUNNING = 1;
const STATE_EXCEPTION = -1;

const ENABLE_ON = 1;
const ENABLE_OFF = 0;

protected function getTableName($id = NULL) {
return 'task_progress';
}

public function getWrongItems($maxLastFireTime) {
$rows = $this->getORM()
->select('id, title')
->where('state != ?', self::STATE_WAITTING)
->where('last_fire_time < ?', $maxLastFireTime)
->where('enable = ?', self::ENABLE_ON)
->order('last_fire_time ASC')
->fetchAll();

return !empty($rows) ? $rows : array();
}

public function resetWrongItems($id) {
return $this->update($id, array('state' => self::STATE_WAITTING));
}

public function getAllWaittingItems() {
$rows = $this->getORM()
->select('id, title, trigger_class, fire_params')
->where('state', self::STATE_WAITTING)
->where('interval_time + last_fire_time < ?', $_SERVER['REQUEST_TIME'])
->where('enable = ?', self::ENABLE_ON)
->fetchAll();

return !empty($rows) ? $rows : array();
}

public function isRunnable($id) {
$row = $this->get($id, 'enable, state');

if (empty($row)) {
return FALSE;
}

return ($row['state'] == self::STATE_WAITTING && $row['enable'] == self::ENABLE_ON) ? TRUE : FALSE;
}

public function setRunningState($id) {
return $this->update($id, array('state' => self::STATE_RUNNING));
}

public function updateFinishItem($id, $result) {
$data = array(
'result' => json_encode($result),
'state' => self::STATE_WAITTING,
'last_fire_time' => $_SERVER['REQUEST_TIME'],
);

return $this->update($id, $data);
}

public function updateExceptionItem($id, $errorMsg) {
$data = array(
'result' => $errorMsg,
'state' => self::STATE_EXCEPTION,
'last_fire_time' => $_SERVER['REQUEST_TIME'],
);

return $this->update($id, $data);
}
}

+ 68
- 0
Library/Task/Tests/MQ/Task_MQ_Array_Test.php View File

@@ -0,0 +1,68 @@
<?php
/**
* PhpUnderControl_TaskMQArray_Test
*
* 针对 ../../MQ/Array.php Task_MQ_Array 类的PHPUnit单元测试
*
* @author: dogstar 20150516
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_MQ_Array')) {
require dirname(__FILE__) . '/../../MQ/Array.php';
}

class PhpUnderControl_TaskMQArray_Test extends PHPUnit_Framework_TestCase
{
public $taskMQArray;

protected function setUp()
{
parent::setUp();

$this->taskMQArray = new Task_MQ_Array();
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'Demo.Test';
$params = array (
'id' => 1,
);

$rs = $this->taskMQArray->add($service, $params);

$this->assertTrue($rs);
}

/**
* @group testPop
*/
public function testPop()
{
$service = 'Demo.Update';
$num = '1';

$rs = $this->taskMQArray->pop($service, $num);

$this->assertEmpty($rs);

$rs = $this->taskMQArray->add($service, array('name' => 'phalapi'));
$rs = $this->taskMQArray->add($service, array('name' => 'net'));

$rs = $this->taskMQArray->pop($service, 1);
$this->assertEquals(array(array('name' => 'phalapi')), $rs);
$rs = $this->taskMQArray->pop($service, 1);
$this->assertEquals(array(array('name' => 'net')), $rs);
}

}

+ 70
- 0
Library/Task/Tests/MQ/Task_MQ_DB_Test.php View File

@@ -0,0 +1,70 @@
<?php
/**
* PhpUnderControl_TaskMQDB_Test
*
* 针对 ../../MQ/DB.php Task_MQ_DB 类的PHPUnit单元测试
*
* @author: dogstar 20150516
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_MQ_DB')) {
require dirname(__FILE__) . '/../../MQ/DB.php';
}

class PhpUnderControl_TaskMQDB_Test extends PHPUnit_Framework_TestCase
{
public $taskMQDB;

protected function setUp()
{
parent::setUp();

$this->taskMQDB = new Task_MQ_DB();
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'Demo.Test';
$params = array (
'id' => 1,
);

$rs = $this->taskMQDB->add($service, $params);

$this->assertTrue($rs);
}

/**
* @group testPop
*/
public function testPop()
{
$this->assertEmpty($this->taskMQDB->pop('NoThisServcie.Index'));

$service = 'Demo.Update';
$num = '1';
$rs = $this->taskMQDB->add($service, array('name' => 'phalapi'));
$rs = $this->taskMQDB->add($service, array('name' => 'net'));
$rs = $this->taskMQDB->add($service, array('name' => 'net'));
$rs = $this->taskMQDB->add($service, array('name' => 'net'));

$rs = $this->taskMQDB->pop($service, 1);
$this->assertEquals(array(array('name' => 'phalapi')), $rs);
$rs = $this->taskMQDB->pop($service, 2);
$this->assertEquals(array(array('name' => 'net'), array('name' => 'net')), $rs);

$rs = $this->taskMQDB->pop($service, 10);
$this->assertCount(1, $rs);
}

}

+ 59
- 0
Library/Task/Tests/MQ/Task_MQ_File_Test.php View File

@@ -0,0 +1,59 @@
<?php
/**
* PhpUnderControl_TaskMQFile_Test
*
* 针对 ../../MQ/File.php Task_MQ_File 类的PHPUnit单元测试
*
* @author: dogstar 20160430
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_MQ_File')) {
require dirname(__FILE__) . '/../../MQ/File.php';
}

class PhpUnderControl_TaskMQFile_Test extends PHPUnit_Framework_TestCase
{
public $taskMQFile;

protected function setUp()
{
parent::setUp();

$this->taskMQFile = new Task_MQ_File();
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'Task_MQ_File_Default.Index';
$params = array (
'username' => 'dogstar',
);

$rs = $this->taskMQFile->add($service, $params);
$rs = $this->taskMQFile->add($service, $params);
$rs = $this->taskMQFile->add($service, $params);
}

/**
* @group testPop
*/
public function testPop()
{
$service = 'Task_MQ_File_Default.Index';
$num = 2;

$rs = $this->taskMQFile->pop($service, $num);
$this->assertCount($num, $rs);
}

}

+ 59
- 0
Library/Task/Tests/MQ/Task_MQ_Memcached_Test.php View File

@@ -0,0 +1,59 @@
<?php
/**
* PhpUnderControl_TaskMQMemcached_Test
*
* 针对 ../../MQ/Memcached.php Task_MQ_Memcached 类的PHPUnit单元测试
*
* @author: dogstar 20160430
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_MQ_Memcached')) {
require dirname(__FILE__) . '/../../MQ/Memcached.php';
}

class PhpUnderControl_TaskMQMemcached_Test extends PHPUnit_Framework_TestCase
{
public $taskMQMemcached;

protected function setUp()
{
parent::setUp();

$this->taskMQMemcached = new Task_MQ_Memcached();
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'Task_MQ_Memcached_Default.Index';
$params = array (
'username' => 'dogstar',
);

$rs = $this->taskMQMemcached->add($service, $params);
$rs = $this->taskMQMemcached->add($service, $params);
$rs = $this->taskMQMemcached->add($service, $params);
}

/**
* @group testPop
*/
public function testPop()
{
$service = 'Task_MQ_Memcached_Default.Index';
$num = 2;

$rs = $this->taskMQMemcached->pop($service, $num);
$this->assertCount($num, $rs);
}

}

+ 60
- 0
Library/Task/Tests/MQ/Task_MQ_Redis_Test.php View File

@@ -0,0 +1,60 @@
<?php
/**
* PhpUnderControl_TaskMQRedis_Test
*
* 针对 ../../MQ/Redis.php Task_MQ_Redis 类的PHPUnit单元测试
*
* @author: Task_MQ_Redis 20150516
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_MQ_Redis')) {
require dirname(__FILE__) . '/../../MQ/Redis.php';
}

class PhpUnderControl_TaskMQRedis_Test extends PHPUnit_Framework_TestCase
{
public $taskMQRedis;

protected function setUp()
{
parent::setUp();

$this->taskMQRedis = new Task_MQ_Redis();
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'TaskRedis.Test';
$params = array (
'id' => 1,
);

$rs = $this->taskMQRedis->add($service, $params);

$this->taskMQRedis->add($service, array('id' => 2));
}

/**
* @group testPop
*/
public function testPop()
{
$service = 'TaskRedis.Test';
$num = 2;

$rs = $this->taskMQRedis->pop($service, $num);

$this->assertEquals(array(array('id' => 1), array('id' => 2)), $rs);
}

}

+ 68
- 0
Library/Task/Tests/Runner/Task_Runner_Local_Test.php View File

@@ -0,0 +1,68 @@
<?php
/**
* PhpUnderControl_TaskRunnerLocal_Test
*
* 针对 ../../Runner/Local.php Task_Runner_Local 类的PHPUnit单元测试
*
* @author: dogstar 20150516
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_Runner_Local')) {
require dirname(__FILE__) . '/../../Runner/Local.php';
}

class PhpUnderControl_TaskRunnerLocal_Test extends PHPUnit_Framework_TestCase
{
public $taskRunnerLocal;

public $mq;

protected function setUp()
{
parent::setUp();

$this->mq = new Task_MQ_Array();

$this->taskRunnerLocal = new Task_Runner_Local($this->mq);
}

protected function tearDown()
{
}

public function testHere()
{
$service1 = 'TestTaskDemo.Update1';
$this->mq->add($service1, array('name' => 'phalapi'));
$this->mq->add($service1, array('name' => 'net'));

$service2 = 'TestTaskDemo.Update2';
$this->mq->add($service2, array('id' => 1));

$rs = $this->taskRunnerLocal->go($service1);
$this->assertEquals(2, $rs['total']);
$this->assertEquals(0, $rs['fail']);

$rs = $this->taskRunnerLocal->go($service2);
$this->assertEquals(1, $rs['total']);
$this->assertEquals(1, $rs['fail']);

$rs = $this->taskRunnerLocal->go('TestTaskDemo.Update3');
$this->assertEquals(0, $rs['total']);
$this->assertEquals(0, $rs['fail']);
}

}

class Api_TestTaskDemo extends PhalApi_Api {

public function update1() {
return array('code' => 0);
}

public function update2() {
throw new PhalApi_Exception_InternalServerError('just for test');
}
}

+ 57
- 0
Library/Task/Tests/Runner/Task_Runner_Remote_Test.php View File

@@ -0,0 +1,57 @@
<?php
/**
* PhpUnderControl_TaskRunnerRemote_Test
*
* 针对 ../../Runner/Remote.php Task_Runner_Remote 类的PHPUnit单元测试
*
* @author: dogstar 20150516
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Task_Runner_Remote')) {
require dirname(__FILE__) . '/../../Runner/Remote.php';
}

class PhpUnderControl_TaskRunnerRemote_Test extends PHPUnit_Framework_TestCase
{
public $taskRunnerRemote;

protected $mq;

protected function setUp()
{
parent::setUp();

$this->mq = new Task_MQ_Array();

$this->taskRunnerRemote = new Task_Runner_Remote($this->mq);
}

protected function tearDown()
{
}

public function testHere()
{
$service1 = 'Default.Index';
$this->mq->add($service1, array('username' => 'phalapi'));
$this->mq->add($service1, array('username' => 'net'));

$service2 = 'WrongUser.GetBaseInfo';
$this->mq->add($service2, array('userId' => 1));

$rs = $this->taskRunnerRemote->go($service1);
$this->assertEquals(2, $rs['total']);
$this->assertEquals(0, $rs['fail']);

$rs = $this->taskRunnerRemote->go($service2);
$this->assertEquals(1, $rs['total']);
$this->assertEquals(1, $rs['fail']);

$rs = $this->taskRunnerRemote->go('TestTaskDemo.Update');
$this->assertEquals(0, $rs['total']);
$this->assertEquals(0, $rs['fail']);
}

}

+ 54
- 0
Library/Task/Tests/Task_Lite_Test.php View File

@@ -0,0 +1,54 @@
<?php
/**
* PhpUnderControl_TaskLite_Test
*
* 针对 ../Lite.php Task_Lite 类的PHPUnit单元测试
*
* @author: dogstar 20150514
*/

require_once dirname(__FILE__) . '/test_env.php';

if (!class_exists('Task_Lite')) {
require dirname(__FILE__) . '/../Lite.php';
}

class PhpUnderControl_TaskLite_Test extends PHPUnit_Framework_TestCase
{
public $taskLite;

protected function setUp()
{
parent::setUp();

$this->taskLite = new Task_Lite(new Task_MQ_File());
}

protected function tearDown()
{
}


/**
* @group testAdd
*/
public function testAdd()
{
$service = 'Demo.Update';
$params = array (
'id' => 888
);

$rs = $this->taskLite->add($service, $params);
$this->assertTrue($rs);
}

public function testAddWrong()
{
$service = 'Demo';

$rs = $this->taskLite->add($service);

$this->assertFalse($rs);
}
}

+ 40
- 0
Library/Task/Tests/Task_Progress_Test.php View File

@@ -0,0 +1,40 @@
<?php
/**
* PhpUnderControl_TaskProgress_Test
*
* 针对 ../Progress.php Task_Progress 类的PHPUnit单元测试
*
* @author: dogstar 20150519
*/

require_once dirname(__FILE__) . '/test_env.php';

if (!class_exists('Task_Progress')) {
require dirname(__FILE__) . '/../Progress.php';
}

class PhpUnderControl_TaskProgress_Test extends PHPUnit_Framework_TestCase
{
public $taskProgress;

protected function setUp()
{
parent::setUp();

$this->taskProgress = new Task_Progress();
}

protected function tearDown()
{
}


/**
* @group testRun
*/
public function testRun()
{
$rs = $this->taskProgress->run();
}

}

+ 65
- 0
Library/Task/Tests/Task_Runner_Test.php View File

@@ -0,0 +1,65 @@
<?php
/**
* PhpUnderControl_TaskRunner_Test
*
* 针对 ../Runner.php Task_Runner 类的PHPUnit单元测试
*
* @author: dogstar 20150515
*/

require_once dirname(__FILE__) . '/test_env.php';

if (!class_exists('Task_Runner')) {
require dirname(__FILE__) . '/../Runner.php';
}

class PhpUnderControl_TaskRunner_Test extends PHPUnit_Framework_TestCase
{
protected $fileMq;

public $taskRunner;

protected function setUp()
{
parent::setUp();

$this->fileMq = new Task_MQ_File();
$this->taskRunner = new Task_Runner_Mock($this->fileMq);
}

protected function tearDown()
{
}


/**
* @group testGo
*/
public function testGo()
{
$service = 'Demo.TestGo';

$this->fileMq->add($service, array());
$this->fileMq->add($service, array('id' => 123));
$this->fileMq->add($service, array('id' => 888, 'name' => 'phalapi'));

$rs = $this->taskRunner->go($service);
//var_dump($rs);

$this->assertNotEmpty($rs);
$this->assertArrayHasKey('total', $rs);
$this->assertArrayHasKey('fail', $rs);

$this->assertEquals(3, $rs['total']);
$this->assertEquals(0, $rs['fail']);
}

}

class Task_Runner_Mock extends Task_Runner {

protected function youGo($service, $params) {
echo "Task_Runner_Mock::youGo(", $service , ", ", json_encode($params), ") ... \n";
return true;
}
}

+ 14
- 0
Library/Task/Tests/test_env.php View File

@@ -0,0 +1,14 @@
<?php
$_GET['debug'] = $_GET['__sql__'] = 1;

require_once dirname(__FILE__) . '/../../../Public/init.php';
//require_once '/home/dogstar/projects/library.phalapi.net/Public/init.php';

DI()->loader->addDirs('Demo');
DI()->loader->addDirs('Library');
DI()->loader->addDirs('./Library/Task/Task');

DI()->logger = new PhalApi_Logger_Explorer(
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);

SL('en');

+ 32
- 0
Library/Task/check.php View File

@@ -0,0 +1,32 @@
#!/usr/bin/env php
<?php
require_once dirname(__FILE__) . '/../../../../Public/init.php';
//require_once '/home/dogstar/projects/library.phalapi.net/Public/init.php';

DI()->loader->addDirs('Demo');

if ($argc < 2) {
echo "Usage: $argv[0] <service> \n\n";
exit(1);
}

$service = trim($argv[1]);

echo "Input params(json):\n";
$params = trim(fgets(STDIN));

$params = json_decode($params, true);
if (is_array($params)) {
$params = array();
}

$mq = new Task_MQ_Array();
$taskLite = new Task_Lite($mq);

$taskLite->add($service, $params);

$runner = new Task_Runner_Local($mq);
$rs = $runnter->go($service);

echo "\nDone:\n", json_encode($rs), "\n\n";


+ 15
- 0
Library/Task/crontab.php View File

@@ -0,0 +1,15 @@
<?php
require_once dirname(__FILE__) . '/../../Public/init.php';
//require_once '/home/dogstar/projects/library.phalapi.net/Public/init.php';

DI()->loader->addDirs(array('Demo', 'Library', 'Library/Task/Task'));

try {
$progress = new Task_Progress();
$progress->run();
} catch (Exception $ex) {
echo $ex->getMessage();
echo "\n\n";
echo $ex->getTraceAsString();
// notify ...
}

+ 23
- 0
PhalApi/.gitignore View File

@@ -0,0 +1,23 @@

.settings
.settings/*
.buildpath
.project

*.log

./Demo/Api/DogstarTest.php
Demo/Api/DogstarTest.php

*.bak

*.dat
*.zip
*.tar

*.swp

.DS_Store
*.DS_Store

.idea

+ 15
- 0
PhalApi/Config/app.php View File

@@ -0,0 +1,15 @@
<?php
/**
* 请在下面放置任何您需要的应用配置
*/

return array(

/**
* 应用接口层的统一参数
*/
'apiCommonRules' => array(
//'sign' => array('name' => 'sign', 'require' => true),
),

);

+ 45
- 0
PhalApi/Config/dbs.php View File

@@ -0,0 +1,45 @@
<?php
/**
* 分库分表的自定义数据库路由配置
*/

return array(
/**
* DB数据库服务器集群
*/
'servers' => array(
'db_ctrip' => array( //服务器标记
'host' => 'localhost', //数据库域名
'name' => 'phalapi_Ctrip', //数据库名字
'user' => 'root', //数据库用户名
'password' => '123456', //数据库密码
'port' => '3306', //数据库端口
'charset' => 'UTF8', //数据库字符集
),
),

/**
* 自定义路由表
*/
'tables' => array(
//通用路由
'__default__' => array(
'prefix' => 'Ctr_',
'key' => 'id',
'map' => array(
array('db' => 'db_ctrip'),
),
),

/**
'demo' => array( //表名
'prefix' => 'Ctr_', //表名前缀
'key' => 'id', //表主键名
'map' => array( //表路由配置
array('db' => 'db_ctrip'), //单表配置:array('db' => 服务器标记)
array('start' => 0, 'end' => 2, 'db' => 'db_ctrip'), //分表配置:array('start' => 开始下标, 'end' => 结束下标, 'db' => 服务器标记)
),
),
*/
),
);

+ 26
- 0
PhalApi/Config/sys.php View File

@@ -0,0 +1,26 @@
<?php
/**
* 以下配置为系统级的配置,通常放置不同环境下的不同配置
*/

return array(
/**
* 默认环境配置
*/
'debug' => false,

/**
* MC缓存服务器参考配置
*/
'mc' => array(
'host' => '127.0.0.1',
'port' => 11211,
),

/**
* 加密
*/
'crypt' => array(
'mcrypt_iv' => '12345678', //8位
),
);

+ 33
- 0
PhalApi/Ctrip/Api/Default.php View File

@@ -0,0 +1,33 @@
<?php
/**
* 默认接口服务类
*
* @author: dogstar <chanzonghuang@gmail.com> 2014-10-04
*/

class Api_Default extends PhalApi_Api {

public function getRules() {
return array(
'index' => array(
'username' => array('name' => 'username', 'default' => 'PHPer', ),
),
);
}
/**
* 默认接口服务
* @return string title 标题
* @return string content 内容
* @return string version 版本,格式:X.X.X
* @return int time 当前时间戳
*/
public function index() {
return array(
'title' => 'Hello World!',
'content' => T('Hi {name}, welcome to use PhalApi!', array('name' => $this->username)),
'version' => PHALAPI_VERSION,
'time' => $_SERVER['REQUEST_TIME'],
);
}
}

+ 59
- 0
PhalApi/Ctrip/Tests/Api/Api_Default_Test.php View File

@@ -0,0 +1,59 @@
<?php
/**
* PhpUnderControl_ApiDefault_Test
*
* 针对 ../../Api/Default.php Api_Default 类的PHPUnit单元测试
*
* @author: dogstar 20150201
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Api_Default')) {
require dirname(__FILE__) . '/../../Api/Default.php';
}

class PhpUnderControl_ApiDefault_Test extends PHPUnit_Framework_TestCase
{
public $apiDefault;

protected function setUp()
{
parent::setUp();

$this->apiDefault = new Api_Default();
}

protected function tearDown()
{
}


/**
* @group testGetRules
*/
public function testGetRules()
{
$rs = $this->apiDefault->getRules();

$this->assertNotEmpty($rs);
}

public function testIndex()
{
//Step 1. 构建请求URL
$url = 'service=Default.Index&username=dogstar';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('title', $rs);
$this->assertArrayHasKey('content', $rs);
$this->assertArrayHasKey('version', $rs);
$this->assertArrayHasKey('time', $rs);

$this->assertEquals('dogstar您好,欢迎使用PhalApi!', $rs['content']);
}
}

+ 34
- 0
PhalApi/Ctrip/Tests/phpunit.xml View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<php>
<ini name="intl.default_locale" value="en"/>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
</php>

<testsuites>
<testsuite name="common">
<directory suffix="Test.php">./Common</directory>
</testsuite>
<testsuite name="api">
<directory suffix="Test.php">./Api</directory>
</testsuite>
<testsuite name="Domain">
<directory suffix="Test.php">./Domain</directory>
</testsuite>
<testsuite name="Model">
<directory suffix="Test.php">./Model</directory>
</testsuite>
</testsuites>
</phpunit>


+ 16
- 0
PhalApi/Ctrip/Tests/test_env.php View File

@@ -0,0 +1,16 @@
<?php
/**
* demo接口测试入口
* @author dogstar 2015-01-28
*/
/** ---------------- 根目录定义,自动加载 ---------------- **/

require_once dirname(__FILE__) . '/../../Public/init.php';

DI()->loader->addDirs('Ctrip');

//日记纪录 - Explorer
DI()->logger = new PhalApi_Logger_Explorer(
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);


+ 9
- 0
PhalApi/Data/phalapi_test.sql View File

@@ -0,0 +1,9 @@
CREATE TABLE `phalapi_test`.`tbl_user` (
`id` INT NOT NULL,
`name` VARCHAR(45) NULL,
`note` VARCHAR(45) NULL,
PRIMARY KEY (`id`));


INSERT INTO `phalapi_test`.`tbl_user` (`id`, `name`, `note`) VALUES ('1', 'dogstar', 'oschina');


+ 2
- 0
PhalApi/Data/user.sql View File

@@ -0,0 +1,2 @@
`name` VARCHAR(45) NULL,
`note` VARCHAR(45) NULL,

+ 33
- 0
PhalApi/Demo/Api/Default.php View File

@@ -0,0 +1,33 @@
<?php
/**
* 默认接口服务类
*
* @author: dogstar <chanzonghuang@gmail.com> 2014-10-04
*/

class Api_Default extends PhalApi_Api {

public function getRules() {
return array(
'index' => array(
'username' => array('name' => 'username', 'default' => 'PHPer', ),
),
);
}
/**
* 默认接口服务
* @return string title 标题
* @return string content 内容
* @return string version 版本,格式:X.X.X
* @return int time 当前时间戳
*/
public function index() {
return array(
'title' => 'Hello World!',
'content' => T('Hi {name}, welcome to use PhalApi!', array('name' => $this->username)),
'version' => PHALAPI_VERSION,
'time' => $_SERVER['REQUEST_TIME'],
);
}
}

+ 70
- 0
PhalApi/Demo/Api/User.php View File

@@ -0,0 +1,70 @@
<?php

/**
* 用户信息类
*/
class Api_User extends PhalApi_Api {

public function getRules() {
return array(
'getBaseInfo' => array(
'userId' => array('name' => 'user_id', 'type' => 'int', 'min' => 1, 'require' => true, 'desc' => '用户ID'),
),
'getMultiBaseInfo' => array(
'userIds' => array('name' => 'user_ids', 'type' => 'array', 'format' => 'explode', 'require' => true, 'desc' => '用户ID,多个以逗号分割'),
),
);
}

/**
* 获取用户基本信息
* @desc 用于获取单个用户基本信息
* @return int code 操作码,0表示成功, 1表示用户不存在
* @return object info 用户信息对象
* @return int info.id 用户ID
* @return string info.name 用户名字
* @return string info.note 用户来源
* @return string msg 提示信息
*/
public function getBaseInfo() {
$rs = array('code' => 0, 'msg' => '', 'info' => array());

$domain = new Domain_User();
$info = $domain->getBaseInfo($this->userId);

if (empty($info)) {
DI()->logger->debug('user not found', $this->userId);

$rs['code'] = 1;
$rs['msg'] = T('user not exists');
return $rs;
}

$rs['info'] = $info;

return $rs;
}

/**
* 批量获取用户基本信息
* @desc 用于获取多个用户基本信息
* @return int code 操作码,0表示成功
* @return array list 用户列表
* @return int list[].id 用户ID
* @return string list[].name 用户名字
* @return string list[].note 用户来源
* @return string msg 提示信息
* @exception 400 参数传递错误
* @exception 500 服务器内部错误
*/
public function getMultiBaseInfo() {
$rs = array('code' => 0, 'msg' => '', 'list' => array());

$domain = new Domain_User();
foreach ($this->userIds as $userId) {
$rs['list'][] = $domain->getBaseInfo($userId);
}

return $rs;
}
}

+ 33
- 0
PhalApi/Demo/Domain/User.php View File

@@ -0,0 +1,33 @@
<?php

class Domain_User {

public function getBaseInfo($userId) {
$rs = array();

$userId = intval($userId);
if ($userId <= 0) {
return $rs;
}

// 版本1:简单的获取
$model = new Model_User();
$rs = $model->getByUserId($userId);

// 版本2:使用单点缓存/多级缓存 (应该移至Model层中)
/**
$model = new Model_User();
$rs = $model->getByUserIdWithCache($userId);
*/

// 版本3:缓存 + 代理
/**
$query = new PhalApi_ModelQuery();
$query->id = $userId;
$modelProxy = new ModelProxy_UserBaseInfo();
$rs = $modelProxy->getData($query);
*/

return $rs;
}
}

+ 27
- 0
PhalApi/Demo/Model/User.php View File

@@ -0,0 +1,27 @@
<?php

class Model_User extends PhalApi_Model_NotORM {

public function getByUserId($userId) {
return $this->getORM()
->select('*')
->where('id = ?', $userId)
->fetch();
}

public function getByUserIdWithCache($userId) {
$key = 'userbaseinfo_' . $userId;
$rs = DI()->cache->get($key);
if ($rs === NULL) {
$rs = $this->getByUserId($userId);
DI()->cache->set($key, $rs, 600);
}
return $rs;
}

/**
protected function getTableName($id) {
return 'user';
}
*/
}

+ 21
- 0
PhalApi/Demo/ModelProxy/UserBaseInfo.php View File

@@ -0,0 +1,21 @@
<?php
/**
* @author dogstar <chanzonghuang@gmail.com> 2015-02-22
*/

class ModelProxy_UserBaseInfo extends PhalApi_ModelProxy {

protected function doGetData($query) {
$model = new Model_User();

return $model->getByUserId($query->id);
}

protected function getKey($query) {
return 'userbaseinfo_' . $query->id;
}

protected function getExpire($query) {
return 600;
}
}

+ 59
- 0
PhalApi/Demo/Tests/Api/Api_Default_Test.php View File

@@ -0,0 +1,59 @@
<?php
/**
* PhpUnderControl_ApiDefault_Test
*
* 针对 ../../Api/Default.php Api_Default 类的PHPUnit单元测试
*
* @author: dogstar 20150201
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Api_Default')) {
require dirname(__FILE__) . '/../../Api/Default.php';
}

class PhpUnderControl_ApiDefault_Test extends PHPUnit_Framework_TestCase
{
public $apiDefault;

protected function setUp()
{
parent::setUp();

$this->apiDefault = new Api_Default();
}

protected function tearDown()
{
}


/**
* @group testGetRules
*/
public function testGetRules()
{
$rs = $this->apiDefault->getRules();

$this->assertNotEmpty($rs);
}

public function testIndex()
{
//Step 1. 构建请求URL
$url = 'service=Default.Index&username=dogstar';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('title', $rs);
$this->assertArrayHasKey('content', $rs);
$this->assertArrayHasKey('version', $rs);
$this->assertArrayHasKey('time', $rs);

$this->assertEquals('dogstar您好,欢迎使用PhalApi!', $rs['content']);
}
}

+ 84
- 0
PhalApi/Demo/Tests/Api/Api_User_Test.php View File

@@ -0,0 +1,84 @@
<?php
/**
* PhpUnderControl_ApiUser_Test
*
* 针对 ../../Demo/Api/User.php Api_User 类的PHPUnit单元测试
*
* @author: dogstar 20150128
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Api_User')) {
require dirname(__FILE__) . '/../../Demo/Api/User.php';
}

class PhpUnderControl_ApiUser_Test extends PHPUnit_Framework_TestCase
{
public $apiUser;

protected function setUp()
{
parent::setUp();

$this->apiUser = new Api_User();
}

protected function tearDown()
{
}


/**
* @group testGetRules
*/
public function testGetRules()
{
$rs = $this->apiUser->getRules();
}

/**
* @group testGetBaseInfo
*/
public function testGetBaseInfo()
{
//Step 1. 构建请求URL
$url = 'service=User.GetBaseInfo&user_id=1';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('code', $rs);
$this->assertArrayHasKey('msg', $rs);
$this->assertArrayHasKey('info', $rs);

$this->assertEquals(0, $rs['code']);

$this->assertEquals('dogstar', $rs['info']['name']);
$this->assertEquals('oschina', $rs['info']['note']);
}

public function testGetMultiBaseInfo()
{
//Step 1. 构建请求URL
$url = 'service=User.GetMultiBaseInfo&user_ids=1,2,3';

//Step 2. 执行请求
$rs = PhalApi_Helper_TestRunner::go($url);

//Step 3. 验证
$this->assertNotEmpty($rs);
$this->assertArrayHasKey('code', $rs);
$this->assertArrayHasKey('msg', $rs);
$this->assertArrayHasKey('list', $rs);

foreach ($rs['list'] as $item) {
$this->assertArrayHasKey('id', $item);
$this->assertArrayHasKey('name', $item);
$this->assertArrayHasKey('note', $item);
}
}

}

+ 48
- 0
PhalApi/Demo/Tests/Domain/Domain_User_Test.php View File

@@ -0,0 +1,48 @@
<?php
/**
* PhpUnderControl_DomainUser_Test
*
* 针对 ./Demo/Domain/User.php Domain_User 类的PHPUnit单元测试
*
* @author: dogstar 20150208
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Domain_User')) {
require dirname(__FILE__) . '/./Demo/Domain/User.php';
}

class PhpUnderControl_DomainUser_Test extends PHPUnit_Framework_TestCase
{
public $domainUser;

protected function setUp()
{
parent::setUp();

$this->domainUser = new Domain_User();
}

protected function tearDown()
{
}


/**
* @group testGetBaseInfo
*/
public function testGetBaseInfo()
{
$userId = '1';

$rs = $this->domainUser->getBaseInfo($userId);

$this->assertArrayHasKey('id', $rs);
$this->assertArrayHasKey('name', $rs);
$this->assertArrayHasKey('note', $rs);

$this->assertEquals('dogstar', $rs['name']);
}

}

+ 48
- 0
PhalApi/Demo/Tests/Model/Model_User_Test.php View File

@@ -0,0 +1,48 @@
<?php
/**
* PhpUnderControl_ModelUser_Test
*
* 针对 ./Demo/Model/User.php Model_User 类的PHPUnit单元测试
*
* @author: dogstar 20150208
*/

require_once dirname(__FILE__) . '/../test_env.php';

if (!class_exists('Model_User')) {
require dirname(__FILE__) . '/./Demo/Model/User.php';
}

class PhpUnderControl_ModelUser_Test extends PHPUnit_Framework_TestCase
{
public $modelUser;

protected function setUp()
{
parent::setUp();

$this->modelUser = new Model_User();
}

protected function tearDown()
{
}


/**
* @group testGetByUserId
*/
public function testGetByUserId()
{
$userId = '1';

$rs = $this->modelUser->getByUserId($userId);

$this->assertArrayHasKey('id', $rs);
$this->assertArrayHasKey('name', $rs);
$this->assertArrayHasKey('note', $rs);

$this->assertEquals('dogstar', $rs['name']);
}

}

+ 34
- 0
PhalApi/Demo/Tests/phpunit.xml View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<php>
<ini name="intl.default_locale" value="en"/>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
</php>

<testsuites>
<testsuite name="common">
<directory suffix="Test.php">./Common</directory>
</testsuite>
<testsuite name="api">
<directory suffix="Test.php">./Api</directory>
</testsuite>
<testsuite name="Domain">
<directory suffix="Test.php">./Domain</directory>
</testsuite>
<testsuite name="Model">
<directory suffix="Test.php">./Model</directory>
</testsuite>
</testsuites>
</phpunit>


+ 25
- 0
PhalApi/Demo/Tests/phpunit_user_getbaseinfo.xml View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<php>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
</php>

<testsuites>
<testsuite name="Test Suite">
<file>./Api/Api_User_Test.php</file>
<file>./Domain/Domain_User_Test.php</file>
<file>./Model/Model_User_Test.php</file>
</testsuite>
</testsuites>
</phpunit>

+ 16
- 0
PhalApi/Demo/Tests/test_env.php View File

@@ -0,0 +1,16 @@
<?php
/**
* demo接口测试入口
* @author dogstar 2015-01-28
*/
/** ---------------- 根目录定义,自动加载 ---------------- **/

require_once dirname(__FILE__) . '/../../Public/init.php';

DI()->loader->addDirs('Demo');

//日记纪录 - Explorer
DI()->logger = new PhalApi_Logger_Explorer(
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);


+ 10
- 0
PhalApi/LICENSE.md View File

@@ -0,0 +1,10 @@
##协议许可的权利 - GPL协议
PhalApi官方网站为 http://www.phalapi.net,依法独立拥有 PhalApi 及官网发布的PhalApi衍生产品著作权。
PhalApi及其衍生产品著作权受到法律和国际公约保护。使用者需仔细阅读本协议,在理解、同意、并遵守本协
议的全部条款后,方可开始使用 PhalApi及其衍生 软件。
本授权协议适用于 http://www.phalapi.net 发布的所有应用程序,PhalApi官方网站拥有对本授权协议的最终
解释权。
PhalApi是一个PHP轻量级开源接口框架,并承诺永久免费!请放心使用!

+ 6
- 0
PhalApi/Language/en/common.php View File

@@ -0,0 +1,6 @@
<?php

return array(
'Hello {name}, Welcome to use PhalApi!' => 'Hello {name}, Welcome to use PhalApi!',
'user not exists' => 'user not exists',
);

+ 14
- 0
PhalApi/Language/zh_cn/common.php View File

@@ -0,0 +1,14 @@
<?php
/**
* 翻译说明:
*
* 1、带大括号的保留原来写法,如:{name},会被系统动态替换
* 2、没在以下出现的,可以自行追加
*
* @author dogstar <chanzonghuang@gmail.com> 2015-02-09
*/

return array(
'Hi {name}, welcome to use PhalApi!' => '{name}您好,欢迎使用PhalApi!',
'user not exists' => '用户不存在',
);

+ 6
- 0
PhalApi/Language/zh_tw/common.php View File

@@ -0,0 +1,6 @@
<?php

return array(
'Hi {name}, welcome to use PhalApi!' => '{name}您好,歡迎使用PhalApi!',
'user not exists' => '用戶不存在',
);

+ 7
- 0
PhalApi/Library/README.md View File

@@ -0,0 +1,7 @@
##扩展类库

请查看:

```
http://git.oschina.net/dogstar/PhalApi-Library
```

+ 33
- 0
PhalApi/Library/Task/Config/app.php View File

@@ -0,0 +1,33 @@
<?php

return array(

//请将以下配置拷贝到 ./Config/app.php 文件中

/**
* 计划任务配置
*/
'Task' => array(
//MQ队列设置,可根据使用需要配置
'mq' => array(
'file' => array(
'path' => API_ROOT . '/Runtime',
'prefix' => 'phalapi_task',
),
'redis' => array(
'host' => '127.0.0.1',
'port' => 6379,
'prefix' => 'phalapi_task',
'auth' => '',
),
),

//Runner设置,如果使用远程调度方式,请加此配置
'runner' => array(
'remote' => array(
'host' => 'http://library.phalapi.net/demo/',
'timeoutMS' => 3000,
),
),
),
);

+ 21
- 0
PhalApi/Library/Task/Config/dbs.php View File

@@ -0,0 +1,21 @@
<?php

return array(

'tables' => array(

//请将以下配置拷贝到 ./Config/dbs.php 文件对应的位置中,未配置的表将使用默认路由

//10张表,可根据需要,自行调整表前缀、主键名和路由
'task_mq' => array(
'prefix' => 'phalapi_',
'key' => 'id',
'map' => array(
array('db' => 'db_demo'),
array('start' => 0, 'end' => 9, 'db' => 'db_demo'),
),
),
)
);



+ 109
- 0
PhalApi/Library/Task/Data/phalapi_task_mq.sql View File

@@ -0,0 +1,109 @@
CREATE TABLE `phalapi_task_mq` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_0` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_2` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_3` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_4` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_5` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_6` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_7` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_8` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `phalapi_task_mq_9` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',
`ext_data` text COMMENT 'json data here',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


+ 13
- 0
PhalApi/Library/Task/Data/phalapi_task_progress.sql View File

@@ -0,0 +1,13 @@
CREATE TABLE `phalapi_task_progress` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT '' COMMENT '任务标题',
`trigger_class` varchar(50) DEFAULT '' COMMENT '触发器类名',
`fire_params` varchar(255) DEFAULT '' COMMENT '需要传递的参数,格式自定',
`interval_time` int(11) DEFAULT '0' COMMENT '执行间隔,单位:秒',
`enable` tinyint(1) DEFAULT '1' COMMENT '是否启动,1启动,0禁止',
`result` varchar(255) DEFAULT '' COMMENT '运行的结果,以json格式保存',
`state` tinyint(1) DEFAULT '0' COMMENT '进程状态,0空闲,1运行中,-1异常退出',
`last_fire_time` int(11) DEFAULT '0' COMMENT '上一次运行时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


+ 3
- 0
PhalApi/Library/Task/Data/task_mq.sql View File

@@ -0,0 +1,3 @@
`service` varchar(200) DEFAULT '' COMMENT '接口服务名称',
`params` text COMMENT 'json格式的参数',
`create_time` int(11) DEFAULT '0',

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save