3.8.1
This commit is contained in:
11
bin/admin/run_app_daily_stat.php
Normal file
11
bin/admin/run_app_daily_stat.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
require_once dirname(__FILE__) . '/../../public/init.php';
|
||||
|
||||
// 先统计全部的
|
||||
|
||||
$domain = new \Admin\Domain\StatReport();
|
||||
|
||||
$statDay = date('Y-m-d', strtotime('1 day ago'));
|
||||
$domain->calWholeAppDailyStat($statDay);
|
||||
$domain->calAllEachAppDailyStat($statDay);
|
||||
|
||||
171
bin/build_sqls.php
Normal file
171
bin/build_sqls.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* 根据配置自动生成SQL建表语句
|
||||
*
|
||||
* @author dogstar <chanzonghuang@gmail.com> 2015-02-04
|
||||
*/
|
||||
|
||||
define('CUR_PATH', dirname(__FILE__));
|
||||
|
||||
if ($argc < 3) {
|
||||
echo "\n";
|
||||
echo colorfulString("Usage:\n", 'WARNING');
|
||||
echo " $argv[0] <dbs_config> <table> [engine] [sqls_folder]\n";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Options:\n", 'WARNING');
|
||||
echo colorfulString(' dbs_config', 'NOTE'), " Require. Path to ./Config/dbs.php\n";
|
||||
echo colorfulString(' table', 'NOTE'), " Require. Table name\n";
|
||||
echo colorfulString(' engine', 'NOTE'), " NOT require. Database engine, default is Innodb\n";
|
||||
echo colorfulString(' sqls_folder', 'NOTE'), " NOT require. Data foler, default is API_ROOT/data";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Demo:\n", 'WARNING');
|
||||
echo " $argv[0] ../Config/dbs.php User\n";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Tips:\n", 'WARNING');
|
||||
echo " This will output the sql directly, enjoy yourself!\n";
|
||||
echo "\n";
|
||||
|
||||
//echo "\n", implode("\n", array_keys($dbsConfig['tables'])), "\n\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$dbsConfigFile = trim($argv[1]);
|
||||
$tableName = trim($argv[2]);
|
||||
$engine = isset($argv[3]) ? $argv[3] : 'InnoDB';
|
||||
$dataFoler = isset($argv[4]) ? $argv[4] : CUR_PATH . '/../data';
|
||||
|
||||
if (!file_exists($dbsConfigFile)) {
|
||||
echo colorfulString("Error: file $dbsConfigFile not exists!\n\n", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$dbsConfig = include($dbsConfigFile);
|
||||
|
||||
if (empty($dbsConfig) || empty($dbsConfig['servers']) || empty($dbsConfig['tables'])
|
||||
|| !is_array($dbsConfig['servers']) || !is_array($dbsConfig['tables'])) {
|
||||
echo colorfulString("Error: db config is incorrect, it should be format as:
|
||||
|
||||
<?php
|
||||
|
||||
return array(
|
||||
/**
|
||||
* avaiable db servers
|
||||
*/
|
||||
|
||||
'servers' => array(
|
||||
'db_X' => array(
|
||||
'host' => 'localhost', //数据库域名
|
||||
'name' => 'phalapi', //数据库名字
|
||||
'user' => 'root', //数据库用户名
|
||||
'password' => '', //数据库密码
|
||||
'port' => '3306', //数据库端口
|
||||
'charset' => 'UTF8', //数据库字符集
|
||||
),
|
||||
),
|
||||
/**
|
||||
* custom table map
|
||||
*/
|
||||
'tables' => array(
|
||||
'demo' => array(
|
||||
'prefix' => 'weili_',
|
||||
'key' => 'id',
|
||||
'map' => array(
|
||||
array('start' => 0, 'end' => 2, 'db' => 'db_X'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$tableMap = isset($dbsConfig['tables'][$tableName]) ? $dbsConfig['tables'][$tableName] : $dbsConfig['tables']['__default__'];
|
||||
if (empty($tableMap)) {
|
||||
echo colorfulString("Error: no table map for $tableName !\n\n", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$tableMap['prefix'] = isset($tableMap['prefix']) ? trim($tableMap['prefix']) : '';
|
||||
$tableMap['key'] = isset($tableMap['key']) ? trim($tableMap['key']) : 'id';
|
||||
$tableMap['map'] = isset($tableMap['map']) ? $tableMap['map'] : array();
|
||||
|
||||
if (empty($tableMap['map'])) {
|
||||
echo colorfulString("Error: miss map for table $tableName !\n\n", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$sqlFilePath = $dataFoler . '/' . $tableName . '.sql';
|
||||
if (!file_exists($sqlFilePath)) {
|
||||
echo colorfulString("Error: sql file $sqlFilePath not exists!\n\n", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$sqlContent = file_get_contents($sqlFilePath);
|
||||
$sqlContent = trim($sqlContent);
|
||||
|
||||
$outputSql = '';
|
||||
|
||||
foreach ($tableMap['map'] as $mapItem) {
|
||||
$dbName = isset($mapItem['db']) ? $mapItem['db'] : 'db';
|
||||
if (!isset($dbsConfig['servers'][$dbName])) {
|
||||
echo colorfulString("Error: no such db server as db = $dbName !\n\n", 'FAILURE');
|
||||
exit();
|
||||
}
|
||||
|
||||
$outputSql .= "
|
||||
/**
|
||||
* DB: {$dbsConfig['servers'][$dbName]['host']} {$dbsConfig['servers'][$dbName]['name']}
|
||||
*/
|
||||
";
|
||||
|
||||
$charset = isset($dbsConfig['servers'][$dbName]['charset'])
|
||||
? $dbsConfig['servers'][$dbName]['charset'] : 'utf8';
|
||||
|
||||
if (isset($mapItem['start']) && isset($mapItem['end'])) {
|
||||
for ($i = $mapItem['start']; $i <= $mapItem['end']; $i ++) {
|
||||
$outputSql .= genSql(
|
||||
$tableMap['prefix'] . $tableName . '_' . $i,
|
||||
$tableMap['key'],
|
||||
$sqlContent,
|
||||
$engine,
|
||||
$charset
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$outputSql .= genSql($tableMap['prefix'] . $tableName, $tableMap['key'], $sqlContent, $engine, $charset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echo $outputSql;
|
||||
|
||||
function colorfulString($text, $type = NULL) {
|
||||
$colors = array(
|
||||
'WARNING' => '1;33',
|
||||
'NOTE' => '1;36',
|
||||
'SUCCESS' => '1;32',
|
||||
'FAILURE' => '1;35',
|
||||
);
|
||||
|
||||
if (empty($type) || !isset($colors[$type])){
|
||||
return $text;
|
||||
}
|
||||
|
||||
return "\033[" . $colors[$type] . "m" . $text . "\033[0m";
|
||||
}
|
||||
|
||||
function genSql($tableName, $tableKey, $sqlContent, $engine, $charset) {
|
||||
return sprintf("
|
||||
CREATE TABLE `%s` (
|
||||
`%s` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
%s
|
||||
`ext_data` text COMMENT 'json data here',
|
||||
PRIMARY KEY (`%s`)
|
||||
) ENGINE=%s DEFAULT CHARSET=%s;
|
||||
|
||||
", $tableName, $tableKey, $sqlContent, $tableKey, $engine, $charset);
|
||||
}
|
||||
301
bin/build_test.php
Normal file
301
bin/build_test.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* 单元测试骨架代码自动生成脚本
|
||||
* 主要是针对当前项目系列生成相应的单元测试代码,提高开发效率
|
||||
*
|
||||
* 用法:
|
||||
* Usage: php ./build_test.php <file_path> <class_name> [bootstrap] [author = dogstar]
|
||||
*
|
||||
* 1、针对全部public的函数进行单元测试
|
||||
* 2、可根据@testcase注释自动生成测试用例
|
||||
*
|
||||
* 备注:亦可使用phpunit-skelgen进行骨架代码生成
|
||||
*
|
||||
* @author: dogstar 20181206
|
||||
* @version: 6.1.1
|
||||
*/
|
||||
|
||||
if ($argc < 3) {
|
||||
echo "\n";
|
||||
echo colorfulString("Usage:\n", 'WARNING');
|
||||
echo " php $argv[0] <file_path> <class_name> [bootstrap] [author]\n";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Options:\n", 'WARNING');
|
||||
echo colorfulString(' file_path', 'NOTE'), " Require. Path to the PHP source code file\n";
|
||||
echo colorfulString(' class_name', 'NOTE'), " Require. The class name need to be tested\n";
|
||||
echo colorfulString(' bootstrap', 'NOTE'), " NOT require. Path to the bootsrap file, usually is test_env.php\n";
|
||||
echo colorfulString(' author', 'NOTE'), " NOT require. Your great name here, default is dogstar\n";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Demo:\n", 'WARNING');
|
||||
echo " $argv[0] ./Demo.php Demo > Demo_Test.php\n";
|
||||
echo " $argv[0] ./Demo.php Demo > Demo_Test.php\n";
|
||||
echo " $argv[0] ./src/Request.php PhalApi\\\\Reqeust > Request_Test.php\n";
|
||||
echo "\n";
|
||||
|
||||
echo colorfulString("Tips:\n", 'WARNING');
|
||||
echo " This will output the code directly, you can save them to test file like with _Test.php suffix.\n";
|
||||
echo "\n";
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
$filePath = $argv[1];
|
||||
$className = $argv[2];
|
||||
$bootstrap = isset($argv[3]) ? $argv[3] : null;
|
||||
$author = isset($argv[4]) ? $argv[4] : 'dogstar';
|
||||
|
||||
// 尝试加载composer autoload
|
||||
$autoloadFiles = array(
|
||||
dirname(__FILE__) . '/../vendor/autoload.php',
|
||||
dirname(__FILE__) . '/../../../vendor/autoload.php',
|
||||
);
|
||||
foreach ($autoloadFiles as $file) {
|
||||
if (file_exists($file)) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
|
||||
// 引入启动文件
|
||||
if (!empty($bootstrap)) {
|
||||
require_once $bootstrap;
|
||||
}
|
||||
|
||||
// 引入源代码
|
||||
require_once $filePath;
|
||||
|
||||
if (!class_exists($className)) {
|
||||
echo colorfulString("Error: cannot find class($className). \n\n", 'FAILURE');
|
||||
die();
|
||||
}
|
||||
|
||||
$reflector = new ReflectionClass($className);
|
||||
|
||||
$methods = $reflector->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$objName = lcfirst(str_replace(array('_', '\\'), array('', ''), $className));
|
||||
|
||||
/** ------------------- 生成通用的单元测试代码 ------------------ **/
|
||||
|
||||
$code = "<?php";
|
||||
|
||||
// 已经将启动文件配置在phpunit.xml,不需要再手动引入
|
||||
// if (file_exists(dirname(__FILE__) . '/test_env.php')) {
|
||||
// $code .= "require_once dirname(__FILE__) . '/bootstrap.php';
|
||||
// ";
|
||||
// } else {
|
||||
// $code .= "//require_once dirname(__FILE__) . '/bootstrap.php';
|
||||
// ";
|
||||
// }
|
||||
|
||||
$initWay = "new \\$className()";
|
||||
if (method_exists($className, '__construct')) {
|
||||
$constructMethod = new ReflectionMethod($className, '__construct');
|
||||
if (!$constructMethod->isPublic()) {
|
||||
if (is_callable(array($className, 'getInstance'))) {
|
||||
$initWay = "\\$className::getInstance()";
|
||||
} else if(is_callable(array($className, 'newInstance'))) {
|
||||
$initWay = "\\$className::newInstance()";
|
||||
} else {
|
||||
$initWay = 'NULL';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 不同版本下的PHPUnit
|
||||
$phpunitBaseClass = class_exists('PHPUnit_Framework_TestCase') ? '\PHPUnit_Framework_TestCase' : '\PHPUnit\Framework\TestCase';
|
||||
|
||||
$code .= "
|
||||
/**
|
||||
* PhalApi_" . str_replace('_', '', $className) . "_Test
|
||||
*
|
||||
* 针对 $filePath $className 类的PHPUnit单元测试
|
||||
*
|
||||
* @author: $author " . date('Ymd') . "
|
||||
*/
|
||||
|
||||
";
|
||||
|
||||
$code .= "namespace tests\\" . substr($className, 0, strrpos($className, '\\')) . ";";
|
||||
$code .= "
|
||||
use $className;
|
||||
";
|
||||
|
||||
$code .="
|
||||
class PhpUnderControl_" . str_replace(array('_', '\\'), array('', ''), $className) . "_Test extends $phpunitBaseClass
|
||||
{
|
||||
public \$$objName;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\$this->$objName = $initWay;
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
// 输出本次单元测试所执行的SQL语句
|
||||
// var_dump(\PhalApi\DI()->tracer->getSqls());
|
||||
|
||||
// 输出本次单元测试所涉及的追踪埋点
|
||||
// var_dump(\PhalApi\DI()->tracer->getStack());
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
foreach ($methods as $method) {
|
||||
if($method->class != $className) continue;
|
||||
|
||||
$fun = $method->name;
|
||||
$Fun = ucfirst($fun);
|
||||
|
||||
if (strlen($Fun) > 2 && substr($Fun, 0, 2) == '__') continue;
|
||||
|
||||
$rMethod = new ReflectionMethod($className, $method->name);
|
||||
$params = $rMethod->getParameters();
|
||||
$isStatic = $rMethod->isStatic();
|
||||
$isConstructor = $rMethod->isConstructor();
|
||||
|
||||
if($isConstructor) continue;
|
||||
|
||||
$initParamStr = '';
|
||||
$callParamStr = '';
|
||||
foreach ($params as $param) {
|
||||
$default = '';
|
||||
|
||||
$rp = new ReflectionParameter(array($className, $fun), $param->name);
|
||||
if ($rp->isOptional()) {
|
||||
$default = $rp->getDefaultValue();
|
||||
}
|
||||
if (is_string($default)) {
|
||||
$default = "'$default'";
|
||||
} else if (is_array($default)) {
|
||||
$default = var_export($default, true);
|
||||
} else if (is_bool($default)) {
|
||||
$default = $default ? 'true' : 'false';
|
||||
} else if ($default === null) {
|
||||
$default = 'null';
|
||||
} else {
|
||||
$default = "''";
|
||||
}
|
||||
|
||||
$initParamStr .= "
|
||||
\$" . $param->name . " = $default;";
|
||||
$callParamStr .= '$' . $param->name . ', ';
|
||||
}
|
||||
$callParamStr = empty($callParamStr) ? $callParamStr : substr($callParamStr, 0, -2);
|
||||
|
||||
/** ------------------- 根据@return对结果类型的简单断言 ------------------ **/
|
||||
$returnAssert = '';
|
||||
|
||||
$docComment = $rMethod->getDocComment();
|
||||
$docCommentArr = explode("\n", $docComment);
|
||||
foreach ($docCommentArr as $comment) {
|
||||
if (strpos($comment, '@return') == false) {
|
||||
continue;
|
||||
}
|
||||
$returnCommentArr = explode(' ', strrchr($comment, '@return'));
|
||||
if (count($returnCommentArr) >= 2) {
|
||||
switch (strtolower($returnCommentArr[1])) {
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
$returnAssert = '$this->assertTrue(is_bool($rs));';
|
||||
break;
|
||||
case 'int':
|
||||
$returnAssert = '$this->assertTrue(is_int($rs));';
|
||||
break;
|
||||
case 'integer':
|
||||
$returnAssert = '$this->assertTrue(is_integer($rs));';
|
||||
break;
|
||||
case 'string':
|
||||
$returnAssert = '$this->assertTrue(is_string($rs));';
|
||||
break;
|
||||
case 'object':
|
||||
$returnAssert = '$this->assertTrue(is_object($rs));';
|
||||
break;
|
||||
case 'array':
|
||||
$returnAssert = '$this->assertTrue(is_array($rs));';
|
||||
break;
|
||||
case 'float':
|
||||
$returnAssert = '$this->assertTrue(is_float($rs));';
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** ------------------- 基本的单元测试代码生成 ------------------ **/
|
||||
$code .= "
|
||||
/**
|
||||
* @group test$Fun
|
||||
*/
|
||||
public function test$Fun()
|
||||
{"
|
||||
. (empty($initParamStr) ? '' : "$initParamStr\n")
|
||||
. "\n "
|
||||
. ($isStatic ? "\$rs = \\$className::$fun($callParamStr);" : "\$rs = \$this->$objName->$fun($callParamStr);")
|
||||
. (empty($returnAssert) ? '' : "\n\n " . $returnAssert . "\n")
|
||||
. "
|
||||
}
|
||||
";
|
||||
|
||||
/** ------------------- 根据@testcase 生成测试代码 ------------------ **/
|
||||
$caseNum = 0;
|
||||
foreach ($docCommentArr as $comment) {
|
||||
if (strpos($comment, '@testcase') == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$returnCommentArr = explode(' ', strrchr($comment, '@testcase'));
|
||||
if (count($returnCommentArr) > 1) {
|
||||
$expRs = $returnCommentArr[1];
|
||||
|
||||
//去掉@testcase和期望的结果
|
||||
array_shift($returnCommentArr);
|
||||
array_shift($returnCommentArr);
|
||||
|
||||
$callParamStrInCase = !empty($returnCommentArr) ? implode(' ', $returnCommentArr) : '';
|
||||
|
||||
$code .= "
|
||||
/**
|
||||
* @group test$Fun
|
||||
*/
|
||||
public function test{$Fun}Case{$caseNum}()
|
||||
{"
|
||||
. "\n "
|
||||
. ($isStatic ? "\$rs = $className::$fun($callParamStrInCase);" : "\$rs = \$this->$objName->$fun($callParamStrInCase);")
|
||||
. "\n\n \$this->assertEquals({$expRs}, \$rs);"
|
||||
. "
|
||||
}
|
||||
";
|
||||
$caseNum ++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$code .= "
|
||||
}";
|
||||
|
||||
echo $code;
|
||||
echo "\n";
|
||||
|
||||
function colorfulString($text, $type = NULL) {
|
||||
$colors = array(
|
||||
'WARNING' => '1;33',
|
||||
'NOTE' => '1;36',
|
||||
'SUCCESS' => '1;32',
|
||||
'FAILURE' => '1;35',
|
||||
);
|
||||
|
||||
if (empty($type) || !isset($colors[$type])){
|
||||
return $text;
|
||||
}
|
||||
|
||||
return "\033[" . $colors[$type] . "m" . $text . "\033[0m";
|
||||
}
|
||||
|
||||
6
bin/es/EsPublishExamples.php
Normal file
6
bin/es/EsPublishExamples.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
// 将数据库中的数据同步到ES
|
||||
require_once dirname(__FILE__) . '/../../public/init.php';
|
||||
$model = new \Base\Model\Search();
|
||||
$model->release(true);
|
||||
4
bin/get_pro_version.php
Normal file
4
bin/get_pro_version.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
echo PHALAPI_PRO_VERSION;
|
||||
16
bin/install_check.sh
Normal file
16
bin/install_check.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
# 安装助手,进行安装前可执行一下
|
||||
|
||||
cur_dir=$(cd $(dirname $0); pwd)
|
||||
|
||||
echo "start to check ..."
|
||||
|
||||
chmod 777 $cur_dir/../config
|
||||
chmod 777 $cur_dir/../config/app.php
|
||||
chmod 777 $cur_dir/../runtime
|
||||
chmod 777 $cur_dir/../public/uploads
|
||||
|
||||
echo "check ok!"
|
||||
|
||||
|
||||
|
||||
8
bin/phalapi-buildsqls
Normal file
8
bin/phalapi-buildsqls
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* chmod +x ./phalapi-buildsqls
|
||||
* ln -s /path/to/phalapi-buildsqls /usr/bin/phalapi-buildsqls
|
||||
*/
|
||||
require_once dirname(__FILE__) . '/build_sqls.php';
|
||||
|
||||
9
bin/phalapi-buildtest
Normal file
9
bin/phalapi-buildtest
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* chmod +x ./phalapi-buildtest
|
||||
* ln -s /path/to/phalapi-buildtest /usr/bin/phalapi-buildtest
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/build_test.php';
|
||||
|
||||
6
bin/phalapi-cli
Normal file
6
bin/phalapi-cli
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
$cli = new PhalApi\CLI\Lite();
|
||||
$cli->response();
|
||||
20
bin/phalapi-create-portal-admin.php
Normal file
20
bin/phalapi-create-portal-admin.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
if ($argc < 3) {
|
||||
echo "Usage: {$argv[0]} <username> <password> [role=admin|super]\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$username = $argv[1];
|
||||
$password = $argv[2];
|
||||
$role = isset($argv[3]) ? $argv[3] : '';
|
||||
|
||||
$domain = new Portal\Domain\Admin();
|
||||
if ($domain->createAdmin($username, $password, $role)) {
|
||||
echo "运营平台管理员账号创建成功!\n";
|
||||
} else {
|
||||
echo "运营平台管理员账号已存在,不能重复创建!\n";
|
||||
}
|
||||
|
||||
87
bin/phalapi-plugin-build.php
Normal file
87
bin/phalapi-plugin-build.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* 打包发布插件
|
||||
* @author dogstar 20200311
|
||||
*/
|
||||
|
||||
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
if ($argc < 2) {
|
||||
echo "Usage: {$argv[0]} <plugin_key>\n";
|
||||
echo "请输入你的插件编号,字母数字和下划线组合。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKey = trim($argv[1]);
|
||||
if (!preg_match('/^[0-9A-Za-z_]{1,}$/', $pluginKey)) {
|
||||
echo "插件编号格式不对,应该使用字母数字和下划线组合。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKeyClass = ucfirst(str_replace('_', '', $pluginKey));
|
||||
|
||||
$jsonFile = dirname(__FILE__) . '/../plugins/' . $pluginKey . '.json';
|
||||
|
||||
if (!file_exists($jsonFile)) {
|
||||
echo "插件json配置文件不存在,", $jsonFile, " \n";
|
||||
echo "可以先使用 php ./bin/phalapi-plugin-create.php 脚本命令创建一个新的插件。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$config = json_decode(file_get_contents($jsonFile), true);
|
||||
|
||||
// 压缩多个文件
|
||||
$fileList = $config['plugin_files'];
|
||||
$fileList[] = 'plugins/' . $pluginKey . '.json';
|
||||
|
||||
$filename = API_ROOT . "/plugins/{$pluginKey}.zip"; // 压缩包所在的位置路径
|
||||
@unlink($filename);
|
||||
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($filename,ZipArchive::CREATE); //打开压缩包
|
||||
foreach($fileList as $file){
|
||||
if (is_string($file)) {
|
||||
if (strpos($file, '.')) {
|
||||
$zip->addFile(API_ROOT . '/' . $file, $file); //向压缩包中添加文件
|
||||
} else {
|
||||
addFileToZip(API_ROOT . '/' . $file, $file, $zip);
|
||||
}
|
||||
} else if (is_array($file)) {
|
||||
foreach ($file as $it) {
|
||||
if (strpos($it, '.')) {
|
||||
$zip->addFile(API_ROOT . '/' . $it, $it); //向压缩包中添加文件
|
||||
} else {
|
||||
addFileToZip(API_ROOT . '/' . $it, $it, $zip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$zip->close(); //关闭压缩包
|
||||
|
||||
echo "插件已打包发布完毕!\n";
|
||||
echo realpath($filename), "\n\n";
|
||||
|
||||
|
||||
/**
|
||||
* @param $path 文件夹路径
|
||||
* @param $zip zip 对象
|
||||
*/
|
||||
function addFileToZip($path, $zipPath, $zip) {
|
||||
$handler = opendir($path); //打开当前文件夹由$path指定。
|
||||
|
||||
while (($filename = readdir($handler)) !== false) {
|
||||
if ($filename != "." && $filename != "..") {//文件夹文件名字为'.'和‘..’,不要对他们进行操作
|
||||
if (is_dir($path . "/" . $filename)) {// 如果读取的某个对象是文件夹,则递归
|
||||
|
||||
addFileToZip($path . "/" . $filename, $zipPath . '/' . $filename, $zip);
|
||||
} else { //将文件加入zip对象
|
||||
$zip->addFile($path . "/" . $filename, $zipPath . '/' . $filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@closedir($path);
|
||||
}
|
||||
199
bin/phalapi-plugin-create.php
Normal file
199
bin/phalapi-plugin-create.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* 创建一个新的应用插件
|
||||
* @author dogstar 20200311
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
if ($argc < 2) {
|
||||
echo "Usage: {$argv[0]} <plugin_key>\n";
|
||||
echo "请输入你的插件编号,字母数字和下划线组合。\n";
|
||||
echo "例如:{$argv[0]} plugin_demo\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKey = trim($argv[1]);
|
||||
if (!preg_match('/^[0-9A-Za-z_]{1,}$/', $pluginKey)) {
|
||||
echo "插件编号格式不对,应该使用字母数字和下划线组合。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKeyClass = ucfirst(str_replace('_', '', $pluginKey));
|
||||
|
||||
// 生成插件json配置文件
|
||||
echo "开始生成插件json配置文件……\n";
|
||||
$jsonFile = dirname(__FILE__) . '/../plugins/' . $pluginKey . '.json';
|
||||
$jsonConfig = array(
|
||||
'plugin_key' => $pluginKey,
|
||||
'plugin_name' => $pluginKey . '插件',
|
||||
'plugin_author' => '作者名称',
|
||||
'plugin_desc' => '插件描述',
|
||||
'plugin_version' => '1.0',
|
||||
'plugin_encrypt' => 0, // 加密模式,0无加密,1有加密,2半加密
|
||||
'plugin_depends' => array(
|
||||
'PHP' => '5.6',
|
||||
'MySQL' => '5.3',
|
||||
'PhalApi' => PHALAPI_VERSION,
|
||||
// composer 依赖的包,无则不写
|
||||
'composer' => array(
|
||||
// 参考示例,格式是包名 => 版本号
|
||||
'phalapi/kernal' => '>=2.12.2',
|
||||
),
|
||||
'extension' => array(
|
||||
// PHP扩展名
|
||||
// 'pdo_mysql',
|
||||
),
|
||||
),
|
||||
// 插件的文件
|
||||
'plugin_files' => array(
|
||||
// 配置文件
|
||||
'config' => 'config/' . $pluginKey . '.php',
|
||||
// 插件启动文件
|
||||
'plugins' => 'plugins/' . $pluginKey . '.php',
|
||||
// 数据库变更文件
|
||||
'data' => 'data/' . $pluginKey . '.sql',
|
||||
// portal后台及对外访问的文件
|
||||
'public' => array(
|
||||
'public/portal/page/' . $pluginKey,
|
||||
'public/portal/page/' . $pluginKey,
|
||||
),
|
||||
// PHP源代码
|
||||
'src' => array(
|
||||
'src/app/Api/' . $pluginKeyClass,
|
||||
'src/app/Domain/' . $pluginKeyClass,
|
||||
'src/app/Model/' . $pluginKeyClass,
|
||||
'src/app/Common/' . $pluginKeyClass,
|
||||
'src/portal/Api/' . $pluginKeyClass,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (file_exists($jsonFile)) {
|
||||
echo "插件已存在!" . $jsonFile . "\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
file_put_contents($jsonFile, json_encode($jsonConfig, version_compare(PHP_VERSION, '5.4.0', '>=') ? JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT : JSON_PRETTY_PRINT));
|
||||
|
||||
echo realpath($jsonFile), " json配置文件生成 ok \n\n";
|
||||
|
||||
// 开始创建插件文件和目录
|
||||
echo "开始创建插件文件和目录……\n";
|
||||
|
||||
// config配置
|
||||
$file = API_ROOT . '/' . $jsonConfig['plugin_files']['config'];
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
// $pluginKey 插件配置
|
||||
return array(
|
||||
);
|
||||
");
|
||||
|
||||
// json配置
|
||||
$file = API_ROOT . '/' . $jsonConfig['plugin_files']['plugins'];
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
// $pluginKey 插件初始化
|
||||
|
||||
");
|
||||
|
||||
// 添加菜单
|
||||
$menuId = rand(100001, 999999999);
|
||||
$menuSql = array();
|
||||
$menuSql[] = "delete from `phalapi_portal_menu` where id = {$menuId};";
|
||||
$menuSql[] = "insert into `phalapi_portal_menu` ( `target`, `id`, `title`, `href`, `sort_num`, `parent_id`, `icon`) values ( '_self', '{$menuId}', '{$pluginKey}插件', 'page/{$pluginKey}/index.html', '9999', '1', 'fa fa-list-alt');";
|
||||
|
||||
$file = API_ROOT . '/' . $jsonConfig['plugin_files']['data'];
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, implode("\n", $menuSql) . "\n");
|
||||
|
||||
// 运营平台
|
||||
$file = API_ROOT . '/public/portal/' . $pluginKey;
|
||||
echo $file, "... \n";
|
||||
mkdir(API_ROOT . '/public/portal/page/' . $pluginKey, 0755, TRUE);
|
||||
$file = API_ROOT . '/public/portal/page/' . $pluginKey . '/index.html';
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, file_get_contents(API_ROOT . '/public/portal/page/phalapi-plugins/_index_tpl.html'));
|
||||
|
||||
// src源代码
|
||||
mkdir(API_ROOT . '/src/app/Api/' . $pluginKeyClass, 0755, TRUE);
|
||||
$file = API_ROOT . '/src/app/Api/' . $pluginKeyClass . '/Main.php';
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
namespace App\\Api\\{$pluginKeyClass};
|
||||
use PhalApi\\Api;
|
||||
|
||||
/**
|
||||
* {$pluginKey} 插件
|
||||
*/
|
||||
class Main extends Api {
|
||||
|
||||
/**
|
||||
* 插件接口
|
||||
* @desc 待开发的插件新接口
|
||||
*/
|
||||
public function todo() {
|
||||
}
|
||||
}
|
||||
|
||||
");
|
||||
|
||||
mkdir(API_ROOT . '/src/app/Domain/' . $pluginKeyClass, 0755, TRUE);
|
||||
$file = API_ROOT . '/src/app/Domain/' . $pluginKeyClass . '/Main.php';
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
namespace App\\Domain\\{$pluginKeyClass};
|
||||
|
||||
class Main {
|
||||
}
|
||||
");
|
||||
|
||||
mkdir(API_ROOT . '/src/app/Model/' . $pluginKeyClass, 0755, TRUE);
|
||||
$file = API_ROOT . '/src/app/Model/' . $pluginKeyClass . '/Main.php';
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
namespace App\\Model\\{$pluginKeyClass};
|
||||
use PhalApi\\Model\\DataModel;
|
||||
|
||||
class Main extends DataModel {
|
||||
}
|
||||
");
|
||||
|
||||
mkdir(API_ROOT . '/src/app/Common/' . $pluginKeyClass, 0755, TRUE);
|
||||
|
||||
// portal
|
||||
mkdir(API_ROOT . '/src/portal/Api/' . $pluginKeyClass, 0755, TRUE);
|
||||
|
||||
$file = API_ROOT . '/src/portal/Api/' . $pluginKeyClass . '/Main.php';
|
||||
echo $file, "... \n";
|
||||
file_put_contents($file, "<?php
|
||||
namespace Portal\\Api\\{$pluginKeyClass};
|
||||
use Portal\\Common\\DataApi as Api;
|
||||
|
||||
/**
|
||||
* {$pluginKey} 插件
|
||||
*/
|
||||
class Main extends Api {
|
||||
|
||||
protected function getDataModel() {
|
||||
return new \\App\\Model\\{$pluginKeyClass}\\Main();
|
||||
}
|
||||
}
|
||||
");
|
||||
|
||||
echo "插件文件和目录生成 ok \n\n";
|
||||
|
||||
echo "开始添加运营平台菜单……\n";
|
||||
|
||||
foreach ($menuSql as $sql) {
|
||||
\PhalApi\DI()->notorm->demo->executeSql($sql);
|
||||
}
|
||||
|
||||
echo "{$pluginKey}插件菜单添加 ok \n\n";
|
||||
|
||||
echo "恭喜,插件创建成功,可以开始开发啦!\n";
|
||||
|
||||
|
||||
32
bin/phalapi-plugin-install.php
Normal file
32
bin/phalapi-plugin-install.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* 安装插件
|
||||
* @author dogstar 20200311
|
||||
*/
|
||||
|
||||
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
if ($argc < 2) {
|
||||
echo "Usage: {$argv[0]} <plugin_key>\n";
|
||||
echo "请输入待安装的插件编号。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKey = trim($argv[1]);
|
||||
if (!preg_match('/^[0-9A-Za-z_]{1,}$/', $pluginKey)) {
|
||||
echo "插件编号格式不对,应该使用字母数字和下划线组合。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$plugin = new Portal\Domain\Plugin();
|
||||
$detail = [];
|
||||
|
||||
$plugin->install($pluginKey, $detail);
|
||||
|
||||
echo implode("\n", $detail);
|
||||
|
||||
echo "\n";
|
||||
|
||||
27
bin/phalapi-plugin-prepare.php
Normal file
27
bin/phalapi-plugin-prepare.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* 插件环境预热
|
||||
* @author dogstar 20200312
|
||||
*/
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
$folder = array(
|
||||
'config',
|
||||
'plugins',
|
||||
'data',
|
||||
'public/portal/page',
|
||||
'public/portal',
|
||||
'src/app/Api',
|
||||
'src/app/Domain',
|
||||
'src/app/Model',
|
||||
'src/app/Common',
|
||||
'src/portal/Api',
|
||||
);
|
||||
|
||||
foreach ($folder as $it) {
|
||||
chmod(API_ROOT . '/' . $it, 0777);
|
||||
}
|
||||
|
||||
|
||||
echo "插件安装环境已预热完毕!\n";
|
||||
|
||||
32
bin/phalapi-plugin-uninstall.php
Normal file
32
bin/phalapi-plugin-uninstall.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* 卸载插件
|
||||
* @author dogstar 20200326
|
||||
*/
|
||||
|
||||
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
if ($argc < 2) {
|
||||
echo "Usage: {$argv[0]} <plugin_key>\n";
|
||||
echo "请输入待卸载的插件编号。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$pluginKey = trim($argv[1]);
|
||||
if (!preg_match('/^[0-9A-Za-z_]{1,}$/', $pluginKey)) {
|
||||
echo "插件编号格式不对,应该使用字母数字和下划线组合。\n";
|
||||
echo "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$plugin = new Portal\Domain\Plugin();
|
||||
$detail = [];
|
||||
|
||||
$plugin->uninstall($pluginKey, $detail);
|
||||
|
||||
echo implode("\n", $detail);
|
||||
|
||||
echo "\n";
|
||||
|
||||
83
bin/run_task.php
Normal file
83
bin/run_task.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
// ---------------------------------------------------------------------------------
|
||||
// _____ _ _ _ _____
|
||||
// | __ \ | | | | /\ (_) | __ \
|
||||
// | |__) || |__ __ _ | | / \ _ __ _ | |__) |_ __ ___
|
||||
// | ___/ | '_ \ / _` || | / /\ \ | '_ \ | | | ___/| '__|/ _ \
|
||||
// | | | | | || (_| || | / ____ \ | |_) || | | | | | | (_) |
|
||||
// |_| |_| |_| \__,_||_|/_/ \_\| .__/ |_| |_| |_| \___/
|
||||
// | |
|
||||
// |_|
|
||||
// PhalApi Pro 专业版
|
||||
// 广州果创网络科技有限公司
|
||||
//
|
||||
// ---------------------------------------------------------------------------------
|
||||
//
|
||||
// 一、协议的许可和权利
|
||||
// 1. 您可以在完全遵守本协议的基础上,将本软件应用于商业用途;
|
||||
// 2. 您可以在协议规定的约束和限制范围内修改本产品源代码或界面风格以适应您的要求;
|
||||
// 3. 您拥有使用本产品中的全部内容资料、商品信息及其他信息的所有权,并独立承担与其内容相关的
|
||||
// 法律义务;
|
||||
// 4. 获得商业授权之后,您可以将本软件应用于商业用途,自授权时刻起,在技术支持期限内拥有通过
|
||||
// 指定的方式获得指定范围内的技术支持服务;
|
||||
//
|
||||
// 二、协议的约束和限制
|
||||
// 1. 未获商业授权之前,禁止将本软件用于商业用途(包括但不限于企业法人经营的产品、经营性产品
|
||||
// 以及以盈利为目的或实现盈利产品);
|
||||
// 2. 未获商业授权之前,禁止在本产品的整体或在任何部分基础上发展任何派生版本、修改版本或第三
|
||||
// 方版本用于重新开发;
|
||||
// 3. 如果您未能遵守本协议的条款,您的授权将被终止,所被许可的权利将被收回并承担相应法律责任;
|
||||
//
|
||||
// 三、有限担保和免责声明
|
||||
// 1. 本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的;
|
||||
// 2. 用户出于自愿而使用本软件,您必须了解使用本软件的风险,在尚未获得商业授权之前,我们不承
|
||||
// 诺提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任;
|
||||
// 3. 广州果创网络科技有限公司不对使用本产品构建的商城中的内容信息承担责任,但在不侵犯用户隐
|
||||
// 私信息的前提下,保留以任何方式获取用户信息及商品信息的权利;
|
||||
//
|
||||
// 有关本产品最终用户授权协议、商业授权与技术服务的详细内容,均由广州果创网络科技有限公司独家
|
||||
// 提供。广州果创网络科技有限公司拥有在不事先通知的情况下,修改授权协议的权力,修改后的协议对
|
||||
// 改变之日起的新授权用户生效。电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和
|
||||
// 等同的法律效力。您一旦开始修改、安装或使用本产品,即被视为完全理解并接受本协议的各项条款,
|
||||
// 在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本
|
||||
// 授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。
|
||||
//
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
use PhalApi\Logger;
|
||||
use PhalApi\Logger\FileLogger;
|
||||
|
||||
/**
|
||||
* 计划任务入口示例
|
||||
*/
|
||||
require_once dirname(__FILE__) . '/../public/init.php';
|
||||
|
||||
|
||||
$di = \PhalApi\DI();
|
||||
// $di->debug = true;
|
||||
|
||||
// 关闭签名
|
||||
$di->filter = null;
|
||||
|
||||
// 日记纪录(调整目录)
|
||||
$di->logger = new FileLogger(API_ROOT . '/runtime/task', Logger::LOG_LEVEL_DEBUG | Logger::LOG_LEVEL_INFO | Logger::LOG_LEVEL_ERROR);
|
||||
|
||||
// 缓存(调整目录)
|
||||
$di->cache = new \PhalApi\Cache\FileCache(array('path' => API_ROOT . '/runtime/task'));
|
||||
|
||||
|
||||
try {
|
||||
// 执行MQ任务
|
||||
$progress = new \PhalApi\Task\Progress();
|
||||
$progress->run();
|
||||
|
||||
// 执行计划任务
|
||||
$taskDomain = new \Base\Domain\Task();
|
||||
$taskDomain->runCrontabTask();
|
||||
} catch (Exception $ex) {
|
||||
echo '[Exception] ', date('Y-m-d H:i:s'), PHP_EOL;
|
||||
echo $ex->getMessage();
|
||||
echo PHP_EOL;
|
||||
echo $ex->getTraceAsString();
|
||||
// notify ...
|
||||
}
|
||||
4
bin/test/run_test_sample.php
Normal file
4
bin/test/run_test_sample.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
require_once dirname(__FILE__) . '/../../public/init.php';
|
||||
$model = new \Base\Domain\TestSample();
|
||||
$model->beginTestAllSamples();
|
||||
1
bin/test/test_detail.txt
Normal file
1
bin/test/test_detail.txt
Normal file
@@ -0,0 +1 @@
|
||||
未开始测试
|
||||
Reference in New Issue
Block a user