[更新]ComposerUpdate

This commit is contained in:
Anyon 2018-05-11 16:53:26 +08:00
parent b00cae0d02
commit a8b6cfba94
44 changed files with 1346 additions and 182 deletions

View File

@ -21,7 +21,7 @@
],
"require": {
"php": ">=5.6.0",
"topthink/think-installer": "~1.0"
"topthink/think-installer": "2.*"
},
"require-dev": {
"phpunit/phpunit": "^5.0|^6.0",

View File

@ -70,7 +70,7 @@ if (!function_exists('app')) {
* @param string $name 类名或标识 默认获取当前应用实例
* @param array $args 参数
* @param bool $newInstance 是否每次创建新的实例
* @return object
* @return mixed|\think\App
*/
function app($name = 'think\App', $args = [], $newInstance = false)
{

View File

@ -51,6 +51,7 @@ return [
'where express error' => '查询表达式错误',
'no data to update' => '没有任何数据需要更新',
'miss data to insert' => '缺少需要写入的数据',
'not support data' => '不支持的数据表达式',
'miss complex primary data' => '缺少复合主键数据',
'miss update condition' => '缺少更新条件',
'model data Not Found' => '模型数据不存在',

View File

@ -20,7 +20,7 @@ use think\route\Dispatch;
*/
class App implements \ArrayAccess
{
const VERSION = '5.1.12';
const VERSION = '5.1.13';
/**
* 当前模块路径
@ -128,6 +128,12 @@ class App implements \ArrayAccess
{
$this->appPath = $appPath ? realpath($appPath) . DIRECTORY_SEPARATOR : $this->getAppPath();
$this->container = Container::getInstance();
$this->thinkPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
$this->rootPath = dirname($this->appPath) . DIRECTORY_SEPARATOR;
$this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
$this->routePath = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
$this->configPath = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
}
/**
@ -163,11 +169,6 @@ class App implements \ArrayAccess
{
$this->beginTime = microtime(true);
$this->beginMem = memory_get_usage();
$this->thinkPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
$this->rootPath = dirname($this->appPath) . DIRECTORY_SEPARATOR;
$this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
$this->routePath = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
$this->configPath = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
// 设置路径环境变量
$this->env->set([
@ -304,6 +305,8 @@ class App implements \ArrayAccess
}
}
$this->setModulePath($path);
$this->request->filter($this->config('app.default_filter'));
}

View File

@ -13,6 +13,14 @@ namespace think;
use think\cache\Driver;
/**
* Class Cache
*
* @package think
*
* @mixin Driver
* @mixin \think\cache\driver\File
*/
class Cache
{
/**

View File

@ -131,16 +131,20 @@ class Container
* 绑定一个类实例当容器
* @access public
* @param string $abstract 类名或者标识
* @param object $instance 类的实例
* @param object|\Closure $instance 类的实例
* @return $this
*/
public function instance($abstract, $instance)
{
if ($instance instanceof \Closure) {
$this->bind[$abstract] = $instance;
} else {
if (isset($this->bind[$abstract])) {
$abstract = $this->bind[$abstract];
}
$this->instances[$abstract] = $instance;
}
return $this;
}
@ -252,7 +256,7 @@ class Container
$args = $this->bindParams($reflect, $vars);
return $reflect->invokeArgs($args);
return call_user_func_array($function, $args);
} catch (ReflectionException $e) {
throw new Exception('function not exists: ' . $function . '()');
}
@ -280,6 +284,10 @@ class Container
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
} catch (ReflectionException $e) {
if (is_array($method) && is_object($method[0])) {
$method[0] = get_class($method[0]);
}
throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()');
}
}
@ -327,11 +335,21 @@ class Container
try {
$reflect = new ReflectionClass($class);
if ($reflect->hasMethod('__make')) {
$method = new ReflectionMethod($class, '__make');
if ($method->isPublic() && $method->isStatic()) {
$args = $this->bindParams($method, $vars);
return $method->invokeArgs(null, $args);
}
}
$constructor = $reflect->getConstructor();
$args = $constructor ? $this->bindParams($constructor, $vars) : [];
return $reflect->newInstanceArgs($args);
} catch (ReflectionException $e) {
throw new ClassNotFoundException('class not exists: ' . $class, $class);
}

View File

@ -16,6 +16,7 @@ namespace think;
* @package think
* @method \think\db\Query connect(array $config =[], mixed $name = false) static 连接/切换数据库连接
* @method \think\db\Query master() static 从主服务器读取数据
* @method \think\db\Query readMaster(bool $all = false) static 后续从主服务器读取数据
* @method \think\db\Query table(string $table) static 指定数据表(含前缀)
* @method \think\db\Query name(string $name) static 指定数据表(不含前缀)
* @method \think\db\Expression raw(string $value) static 使用表达式设置数据

View File

@ -58,6 +58,7 @@ class Facade
protected static function createFacade($class = '', $args = [], $newInstance = false)
{
$class = $class ?: static::class;
$facadeClass = static::getFacadeClass();
if ($facadeClass) {

View File

@ -177,6 +177,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
$this->connection = array_merge($config->pull('database'), $this->connection);
}
if ($this->observerClass) {
// 注册模型观察者
static::observe($this->observerClass);
}
// 执行初始化操作
$this->initialize();
}
@ -595,12 +600,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
// 读取更新条件
$where = $this->getWhere();
// 事件回调
if (false === $this->trigger('before_update')) {
return false;
}
$result = $this->db(false)->where($where)->setInc($field, $step, $lazyTime);
if (true !== $result) {
$this->data[$field] += $step;
}
// 更新回调
$this->trigger('after_update');
return $result;
}
@ -618,12 +631,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
// 读取更新条件
$where = $this->getWhere();
// 事件回调
if (false === $this->trigger('before_update')) {
return false;
}
$result = $this->db(false)->where($where)->setDec($field, $step, $lazyTime);
if (true !== $result) {
$this->data[$field] -= $step;
}
// 更新回调
$this->trigger('after_update');
return $result;
}

View File

@ -404,21 +404,26 @@ class Request
/**
* 设置或获取当前包含协议的域名
* @access public
* @param string $domain 域名
* @param string|bool $domain 域名
* @return string|$this
*/
public function domain($domain = null)
{
if (!is_null($domain)) {
$this->domain = $domain;
return $this;
} elseif (!$this->domain) {
if (is_null($domain)) {
if (!$this->domain) {
$this->domain = $this->scheme() . '://' . $this->host();
}
return $this->domain;
}
if (true === $domain) {
return $this->scheme() . '://' . $this->host(true);
}
$this->domain = $domain;
return $this;
}
/**
* 获取当前根域名
* @access public
@ -429,7 +434,7 @@ class Request
$root = $this->config->get('app.url_domain_root');
if (!$root) {
$item = explode('.', $this->host());
$item = explode('.', $this->host(true));
$count = count($item);
$root = $count > 1 ? $item[$count - 2] . '.' . $item[$count - 1] : $item[0];
}
@ -450,9 +455,9 @@ class Request
if ($rootDomain) {
// 配置域名根 例如 thinkphp.cn 163.com.cn 如果是国家级域名 com.cn net.cn 之类的域名需要配置
$domain = explode('.', rtrim(stristr($this->host(), $rootDomain, true), '.'));
$domain = explode('.', rtrim(stristr($this->host(true), $rootDomain, true), '.'));
} else {
$domain = explode('.', $this->host(), -2);
$domain = explode('.', $this->host(true), -2);
}
$this->subDomain = implode('.', $domain);
@ -1647,15 +1652,18 @@ class Request
/**
* 当前请求的host
* @access public
* @param bool $strict true 仅仅获取HOST
* @return string
*/
public function host()
public function host($strict = false)
{
if (isset($_SERVER['HTTP_X_REAL_HOST'])) {
return $_SERVER['HTTP_X_REAL_HOST'];
$host = $_SERVER['HTTP_X_REAL_HOST'];
} else {
$host = $this->server('HTTP_HOST');
}
return $this->server('HTTP_HOST');
return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host;
}
/**

View File

@ -122,7 +122,7 @@ class Route
public function __construct(Request $request)
{
$this->request = $request;
$this->host = $this->request->host();
$this->host = $this->request->host(true);
$this->setDefaultDomain();
}

View File

@ -105,7 +105,7 @@ class Url
$url = $match[0];
if (!empty($match[1])) {
$host = $this->app['config']->get('app_host') ?: $this->app['request']->host();
$host = $this->app['config']->get('app_host') ?: $this->app['request']->host(true);
if ($domain || $match[1] != $host) {
$domain = $match[1];
}
@ -134,6 +134,11 @@ class Url
}
}
if (!$matchAlias) {
// 路由标识不存在 直接解析
$url = $this->parseUrl($url);
}
// 检测URL绑定
if (!$this->bindCheck) {
$bind = $this->app['route']->getBind($domain && is_string($domain) ? $domain : null);
@ -153,11 +158,6 @@ class Url
}
}
if (!$matchAlias) {
// 路由标识不存在 直接解析
$url = $this->parseUrl($url);
}
if (isset($info['query'])) {
// 解析地址里面参数 合并到vars
parse_str($info['query'], $params);
@ -264,9 +264,8 @@ class Url
$rootDomain = $this->app['request']->rootDomain();
if (true === $domain) {
// 自动判断域名
$domain = $this->app['config']->get('app_host') ?: $this->app['request']->host();
$domain = $this->app['config']->get('app_host') ?: $this->app['request']->host(true);
$domains = $this->app['route']->getDomains();

View File

@ -41,14 +41,11 @@ class Redis extends Driver
*/
public function __construct($options = [])
{
if (!extension_loaded('redis')) {
throw new \BadFunctionCallException('not support: redis');
}
if (!empty($options)) {
$this->options = array_merge($this->options, $options);
}
if (extension_loaded('redis')) {
$this->handler = new \Redis;
if ($this->options['persistent']) {
@ -64,6 +61,18 @@ class Redis extends Driver
if (0 != $this->options['select']) {
$this->handler->select($this->options['select']);
}
} elseif (class_exists('\Predis\Client')) {
$params = [];
foreach ($this->options as $key => $val) {
if (in_array($key, ['aggregate', 'cluster', 'connections', 'exceptions', 'prefix', 'profile', 'replication'])) {
$params[$key] = $val;
unset($this->options[$key]);
}
}
$this->handler = new \Predis\Client($this->options, $params);
} else {
throw new \BadFunctionCallException('not support: redis');
}
}
/**

View File

@ -144,6 +144,8 @@ abstract class Builder
case 'DEC':
$result[$item] = $item . ' - ' . floatval($val[1]);
break;
case 'EXP':
throw new Exception('not support data:[' . $val[0] . ']');
}
} elseif (is_scalar($val)) {
// 过滤非标量数据
@ -815,8 +817,11 @@ abstract class Builder
$condition = [];
foreach ((array) $on as $val) {
if (strpos($val, '=')) {
if ($val instanceof Expression) {
$condition[] = $val->getValue();
} elseif (strpos($val, '=')) {
list($val1, $val2) = explode('=', $val, 2);
$condition[] = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2);
} else {
$condition[] = $val;
@ -1067,7 +1072,7 @@ abstract class Builder
// 分析并处理数据
$data = $this->parseData($query, $options['data']);
if (empty($data)) {
return 0;
return '';
}
$fields = array_keys($data);

View File

@ -814,11 +814,8 @@ abstract class Connection
$options = $query->getOptions();
$pk = $query->getPk($options);
if (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
}
$data = $options['data'];
$query->setOption('limit', 1);
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
// 判断查询缓存
@ -826,7 +823,7 @@ abstract class Connection
if (is_string($cache['key'])) {
$key = $cache['key'];
} elseif (!isset($key)) {
} else {
$key = $this->getCacheKey($query, $data);
}
@ -848,7 +845,6 @@ abstract class Connection
}
$query->setOption('data', $data);
$query->setOption('limit', 1);
// 生成查询SQL
$sql = $this->builder->select($query);
@ -983,7 +979,7 @@ abstract class Connection
}
// 执行操作
$result = $this->execute($sql, $bind, $query);
$result = '' == $sql ? 0 : $this->execute($sql, $bind, $query);
if ($result) {
$sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null);
@ -1145,8 +1141,12 @@ abstract class Connection
$options['where']['AND'] = $where;
$query->setOption('where', ['AND' => $where]);
}
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'])) {
foreach ($options['where']['AND'] as $val) {
if (is_array($val) && $val[0] == $pk) {
$key = $this->getCacheKey($query, $val);
}
}
}
// 更新数据
@ -1208,8 +1208,12 @@ abstract class Connection
$key = $options['cache']['key'];
} elseif (!is_null($data) && true !== $data && !is_array($data)) {
$key = $this->getCacheKey($query, $data);
} elseif (is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
} elseif (is_string($pk) && isset($options['where']['AND'])) {
foreach ($options['where']['AND'] as $val) {
if (is_array($val) && $val[0] == $pk) {
$key = $this->getCacheKey($query, $val);
}
}
}
if (true !== $data && empty($options['where'])) {
@ -1269,7 +1273,7 @@ abstract class Connection
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
$cache = $options['cache'];
$result = $this->getCacheData($query, $cache, $field, $key);
$result = $this->getCacheData($query, $cache, null, $key);
if (false !== $result) {
return $result;
@ -1622,6 +1626,42 @@ abstract class Connection
}
}
/**
* 启动XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function startTransXa($xid)
{}
/**
* 预编译XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function prepareXa($xid)
{}
/**
* 提交XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function commitXa($xid)
{}
/**
* 回滚XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function rollbackXa($xid)
{}
/**
* 启动事务
* @access public

View File

@ -397,6 +397,62 @@ class Query
return $this->connection->getLastSql();
}
/**
* 执行数据库Xa事务
* @access public
* @param callable $callback 数据操作方法回调
* @param array $dbs 多个查询对象或者连接对象
* @return mixed
* @throws PDOException
* @throws \Exception
* @throws \Throwable
*/
public function transactionXa($callback, array $dbs = [])
{
$xid = uniqid('xa');
if (empty($dbs)) {
$dbs[] = $this->getConnection();
}
foreach ($dbs as $key => $db) {
if ($db instanceof Query) {
$db = $db->getConnection();
$dbs[$key] = $db;
}
$db->startTransXa($xid);
}
try {
$result = null;
if (is_callable($callback)) {
$result = call_user_func_array($callback, [$this]);
}
foreach ($dbs as $db) {
$db->prepareXa($xid);
}
foreach ($dbs as $db) {
$db->commitXa($xid);
}
return $result;
} catch (\Exception $e) {
foreach ($dbs as $db) {
$db->rollbackXa($xid);
}
throw $e;
} catch (\Throwable $e) {
foreach ($dbs as $db) {
$db->rollbackXa($xid);
}
throw $e;
}
}
/**
* 执行数据库事务
* @access public
@ -563,13 +619,7 @@ class Query
{
$this->parseOptions();
$result = $this->connection->value($this, $field, $default);
if (!empty($this->options['fetch_sql'])) {
return $result;
}
return $result;
return $this->connection->value($this, $field, $default);
}
/**
@ -1107,7 +1157,7 @@ class Query
* @access public
* @param string|array $table 数据表
* @param string|array $field 查询字段
* @param string|array $on JOIN条件
* @param mixed $on JOIN条件
* @param string $type JOIN类型
* @return $this
*/
@ -1550,7 +1600,13 @@ class Query
if (key($field) !== 0) {
$where = [];
foreach ($field as $key => $val) {
$where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, '=', $val];
if ($val instanceof Expression) {
$where[] = [$key, 'exp', $val];
} elseif (is_null($val)) {
$where[] = [$key, 'NULL', ''];
} else {
$where[] = [$key, is_array($val) ? 'IN' : '=', $val];
}
}
} else {
// 数组批量查询
@ -3079,7 +3135,6 @@ class Query
public function parsePkWhere($data)
{
$pk = $this->getPk($this->options);
// 获取当前数据表
$table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table'];
@ -3091,16 +3146,16 @@ class Query
$key = isset($alias) ? $alias . '.' . $pk : $pk;
// 根据主键查询
if (is_array($data)) {
$where[] = isset($data[$pk]) ? [$key, '=', $data[$pk]] : [$key, 'in', $data];
$where[$pk] = isset($data[$pk]) ? [$key, '=', $data[$pk]] : [$key, 'in', $data];
} else {
$where[] = strpos($data, ',') ? [$key, 'IN', $data] : [$key, '=', $data];
$where[$pk] = strpos($data, ',') ? [$key, 'IN', $data] : [$key, '=', $data];
}
} elseif (is_array($pk) && is_array($data) && !empty($data)) {
// 根据复合主键查询
foreach ($pk as $key) {
if (isset($data[$key])) {
$attr = isset($alias) ? $alias . '.' . $key : $key;
$where[] = [$attr, '=', $data[$key]];
$where[$key] = [$attr, '=', $data[$key]];
} else {
throw new Exception('miss complex primary data');
}

View File

@ -112,7 +112,7 @@ class Mysql extends Builder
*/
public function parseKey(Query $query, $key, $strict = false)
{
if (is_int($key)) {
if (is_numeric($key)) {
return $key;
} elseif ($key instanceof Expression) {
return $key->getValue();

View File

@ -56,7 +56,7 @@ class Pgsql extends Builder
*/
public function parseKey(Query $query, $key, $strict = false)
{
if (is_int($key)) {
if (is_numeric($key)) {
return $key;
} elseif ($key instanceof Expression) {
return $key->getValue();

View File

@ -64,7 +64,7 @@ class Sqlite extends Builder
*/
public function parseKey(Query $query, $key, $strict = false)
{
if (is_int($key)) {
if (is_numeric($key)) {
return $key;
} elseif ($key instanceof Expression) {
return $key->getValue();

View File

@ -83,7 +83,7 @@ class Sqlsrv extends Builder
*/
public function parseKey(Query $query, $key, $strict = false)
{
if (is_int($key)) {
if (is_numeric($key)) {
return $key;
} elseif ($key instanceof Expression) {
return $key->getValue();

View File

@ -154,4 +154,56 @@ class Mysql extends Connection
return true;
}
/**
* 启动XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function startTransXa($xid)
{
$this->initConnect(true);
if (!$this->linkID) {
return false;
}
$this->execute("XA START '$xid'");
}
/**
* 预编译XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function prepareXa($xid)
{
$this->initConnect(true);
$this->execute("XA END '$xid'");
$this->execute("XA PREPARE '$xid'");
}
/**
* 提交XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function commitXa($xid)
{
$this->initConnect(true);
$this->execute("XA COMMIT '$xid'");
}
/**
* 回滚XA事务
* @access public
* @param string $xid XA事务id
* @return void
*/
public function rollbackXa($xid)
{
$this->initConnect(true);
$this->execute("XA ROLLBACK '$xid'");
}
}

View File

@ -66,7 +66,7 @@ use think\Facade;
* @method bool isMobile() static 检测是否使用手机访问
* @method string scheme() static 当前URL地址中的scheme参数
* @method string query() static 当前请求URL地址中的query参数
* @method string host() static 当前请求的host
* @method string host(bool $stric = false) static 当前请求的host
* @method string port() static 当前请求URL地址中的port参数
* @method string protocol() static 当前请求 SERVER_PROTOCOL
* @method string remotePort() static 当前请求 REMOTE_PORT

View File

@ -12,6 +12,7 @@
namespace think\model\concern;
use think\Container;
use think\Loader;
/**
* 模型事件处理
@ -24,6 +25,24 @@ trait ModelEvent
*/
private static $event = [];
/**
* 模型事件观察
* @var array
*/
protected static $observe = ['before_write', 'after_write', 'before_insert', 'after_insert', 'before_update', 'after_update', 'before_delete', 'after_delete', 'before_restore', 'after_restore'];
/**
* 绑定模型事件观察者类
* @var array
*/
protected $observerClass;
/**
* 是否需要事件响应
* @var bool
*/
private $withEvent = true;
/**
* 注册回调方法
* @access public
@ -43,6 +62,45 @@ trait ModelEvent
self::$event[$class][$event][] = $callback;
}
/**
* 清除回调方法
* @access public
* @return void
*/
public static function flushEvent()
{
self::$event[static::class] = [];
}
/**
* 注册一个模型观察者
*
* @param object|string $class
* @return void
*/
public static function observe($class)
{
foreach (static::$observe as $event) {
$eventFuncName = Loader::parseName($event, 1, false);
if (method_exists($class, $eventFuncName)) {
static::event($event, [$class, $eventFuncName]);
}
}
}
/**
* 当前操作的事件响应
* @access protected
* @param bool $event 是否需要事件响应
* @return $this
*/
public function withEvent($event)
{
$this->withEvent = $event;
return $this;
}
/**
* 触发事件
* @access protected
@ -53,7 +111,7 @@ trait ModelEvent
{
$class = static::class;
if (isset(self::$event[$class][$event])) {
if ($this->withEvent && isset(self::$event[$class][$event])) {
foreach (self::$event[$class][$event] as $callback) {
$result = Container::getInstance()->invoke($callback, [$this]);
@ -154,4 +212,25 @@ trait ModelEvent
self::event('after_delete', $callback, $override);
}
/**
* 模型before_restore事件快捷方法
* @access protected
* @param callable $callback
* @param bool $override
*/
protected static function beforeRestore($callback, $override = false)
{
self::event('before_restore', $callback, $override);
}
/**
* 模型after_restore事件快捷方法
* @access protected
* @param callable $callback
* @param bool $override
*/
protected static function afterRestore($callback, $override = false)
{
self::event('after_restore', $callback, $override);
}
}

View File

@ -161,11 +161,20 @@ trait SoftDelete
}
if ($name) {
if (false === $this->trigger('before_restore')) {
return false;
}
// 恢复删除
return $this->db(false)
$result = $this->db(false)
->where($where)
->useSoftDelete($name, $this->getWithTrashedExp())
->update([$name => $this->defaultSoftDelete]);
$this->trigger('after_restore');
return $result;
}
return 0;

View File

@ -67,22 +67,37 @@ class BelongsToMany extends Relation
return $this;
}
/**
* 获取中间表更新条件
* @param $data
* @return array
*/
protected function getUpdateWhere($data)
{
return [
$this->localKey => $data[$this->localKey],
$this->foreignKey => $data[$this->foreignKey],
];
}
/**
* 实例化中间表模型
* @access public
* @param $data
* @param array $data
* @param bool $isUpdate
* @return Pivot
* @throws Exception
*/
protected function newPivot($data = [])
protected function newPivot($data = [], $isUpdate = false)
{
$class = $this->pivotName ?: '\\think\\model\\Pivot';
$pivot = new $class($data, $this->parent, $this->middle);
if ($pivot instanceof Pivot) {
return $pivot;
} else {
throw new Exception('pivot model must extends: \think\model\Pivot');
return $isUpdate ? $pivot->isUpdate(true, $this->getUpdateWhere($data)) : $pivot;
}
throw new Exception('pivot model must extends: \think\model\Pivot');
}
/**
@ -106,7 +121,7 @@ class BelongsToMany extends Relation
}
}
$model->setRelation('pivot', $this->newPivot($pivot));
$model->setRelation('pivot', $this->newPivot($pivot, true));
}
}
@ -398,7 +413,7 @@ class BelongsToMany extends Relation
}
}
$set->setRelation('pivot', $this->newPivot($pivot));
$set->setRelation('pivot', $this->newPivot($pivot, true));
$data[$pivot[$this->localKey]][] = $set;
}
@ -509,7 +524,7 @@ class BelongsToMany extends Relation
foreach ($ids as $id) {
$pivot[$this->foreignKey] = $id;
$this->pivot->insert($pivot, true);
$result[] = $this->newPivot($pivot);
$result[] = $this->newPivot($pivot, true);
}
if (count($result) == 1) {

View File

@ -387,6 +387,17 @@ abstract class Rule
return $this->option('pjax', $pjax);
}
/**
* 检查是否为手机访问
* @access public
* @param bool $mobile
* @return $this
*/
public function mobile($mobile = true)
{
return $this->option('mobile', $mobile);
}
/**
* 当前路由到一个模板地址 当使用数组的时候可以传入模板变量
* @access public
@ -884,7 +895,7 @@ abstract class Rule
}
// AJAX PJAX 请求检查
foreach (['ajax', 'pjax'] as $item) {
foreach (['ajax', 'pjax', 'mobile'] as $item) {
if (isset($option[$item])) {
$call = 'is' . $item;
if ($option[$item] && !$request->$call() || !$option[$item] && $request->$call()) {
@ -900,7 +911,7 @@ abstract class Rule
}
// 域名检查
if ((isset($option['domain']) && !in_array($option['domain'], [$_SERVER['HTTP_HOST'], $request->subDomain()]))) {
if ((isset($option['domain']) && !in_array($option['domain'], [$request->host(true), $request->subDomain()]))) {
return false;
}

View File

@ -78,15 +78,8 @@ class Module extends Dispatch
} else {
throw new HttpException(404, 'module not exists:' . $module);
}
} else {
// 单一模块部署
$module = '';
$this->app['request']->module($module);
}
// 当前模块路径
$this->app->setModulePath($this->app->getAppPath() . ($module ? $module . DIRECTORY_SEPARATOR : ''));
// 是否自动转换控制器和操作名
$convert = is_bool($this->convert) ? $this->convert : $this->app->config('app.url_convert');
// 获取控制器名

View File

@ -44,11 +44,7 @@ class Redis implements SessionHandlerInterface
*/
public function open($savePath, $sessName)
{
// 检测php环境
if (!extension_loaded('redis')) {
throw new Exception('not support:redis');
}
if (extension_loaded('redis')) {
$this->handler = new \Redis;
// 建立连接
@ -62,6 +58,18 @@ class Redis implements SessionHandlerInterface
if (0 != $this->config['select']) {
$this->handler->select($this->config['select']);
}
} elseif (class_exists('\Predis\Client')) {
$params = [];
foreach ($this->config as $key => $val) {
if (in_array($key, ['aggregate', 'cluster', 'connections', 'exceptions', 'prefix', 'profile', 'replication'])) {
$params[$key] = $val;
unset($this->config[$key]);
}
}
$this->handler = new \Predis\Client($this->config, $params);
} else {
throw new \BadFunctionCallException('not support: redis');
}
return true;
}

2
vendor/autoload.php vendored
View File

@ -4,4 +4,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903::getLoader();
return ComposerAutoloaderInite29f1d41f74bbc25b33cf82965146bdc::getLoader();

View File

@ -140,12 +140,19 @@ return array(
'WeChat\\Template' => $vendorDir . '/zoujingli/wechat-developer/WeChat/Template.php',
'WeChat\\User' => $vendorDir . '/zoujingli/wechat-developer/WeChat/User.php',
'WeChat\\Wifi' => $vendorDir . '/zoujingli/wechat-developer/WeChat/Wifi.php',
'WeMini\\Basic' => $vendorDir . '/zoujingli/weopen-developer/WeMini/Basic.php',
'WeMini\\Code' => $vendorDir . '/zoujingli/weopen-developer/WeMini/Code.php',
'WeMini\\Crypt' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Crypt.php',
'WeMini\\Domain' => $vendorDir . '/zoujingli/weopen-developer/WeMini/Domain.php',
'WeMini\\Plugs' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Plugs.php',
'WeMini\\Poi' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Poi.php',
'WeMini\\Qrcode' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Qrcode.php',
'WeMini\\Template' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Template.php',
'WeMini\\Tester' => $vendorDir . '/zoujingli/weopen-developer/WeMini/Tester.php',
'WeMini\\Total' => $vendorDir . '/zoujingli/wechat-developer/WeMini/Total.php',
'WeMini\\User' => $vendorDir . '/zoujingli/weopen-developer/WeMini/User.php',
'WeOpen\\Login' => $vendorDir . '/zoujingli/weopen-developer/WeOpen/Login.php',
'WeOpen\\MiniApp' => $vendorDir . '/zoujingli/weopen-developer/WeOpen/MiniApp.php',
'WeOpen\\Service' => $vendorDir . '/zoujingli/weopen-developer/WeOpen/Service.php',
'app\\admin\\controller\\Auth' => $baseDir . '/application/admin/controller/Auth.php',
'app\\admin\\controller\\Config' => $baseDir . '/application/admin/controller/Config.php',

View File

@ -10,7 +10,7 @@ return array(
'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
'app\\' => array($baseDir . '/application'),
'WeOpen\\' => array($vendorDir . '/zoujingli/weopen-developer/WeOpen'),
'WeMini\\' => array($vendorDir . '/zoujingli/wechat-developer/WeMini'),
'WeMini\\' => array($vendorDir . '/zoujingli/wechat-developer/WeMini', $vendorDir . '/zoujingli/weopen-developer/WeMini'),
'WeChat\\' => array($vendorDir . '/zoujingli/wechat-developer/WeChat'),
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
'Qiniu\\' => array($vendorDir . '/qiniu/php-sdk/src/Qiniu'),

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903
class ComposerAutoloaderInite29f1d41f74bbc25b33cf82965146bdc
{
private static $loader;
@ -19,15 +19,15 @@ class ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInite29f1d41f74bbc25b33cf82965146bdc', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInite29f1d41f74bbc25b33cf82965146bdc', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita33eeddf73f94e102eeb54914d7e1903::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
@ -48,19 +48,19 @@ class ComposerAutoloaderInita33eeddf73f94e102eeb54914d7e1903
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInita33eeddf73f94e102eeb54914d7e1903::$files;
$includeFiles = Composer\Autoload\ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequirea33eeddf73f94e102eeb54914d7e1903($fileIdentifier, $file);
composerRequiree29f1d41f74bbc25b33cf82965146bdc($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequirea33eeddf73f94e102eeb54914d7e1903($fileIdentifier, $file)
function composerRequiree29f1d41f74bbc25b33cf82965146bdc($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInita33eeddf73f94e102eeb54914d7e1903
class ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc
{
public static $files = array (
'1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
@ -65,6 +65,7 @@ class ComposerStaticInita33eeddf73f94e102eeb54914d7e1903
'WeMini\\' =>
array (
0 => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini',
1 => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini',
),
'WeChat\\' =>
array (
@ -223,12 +224,19 @@ class ComposerStaticInita33eeddf73f94e102eeb54914d7e1903
'WeChat\\Template' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeChat/Template.php',
'WeChat\\User' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeChat/User.php',
'WeChat\\Wifi' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeChat/Wifi.php',
'WeMini\\Basic' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini/Basic.php',
'WeMini\\Code' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini/Code.php',
'WeMini\\Crypt' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Crypt.php',
'WeMini\\Domain' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini/Domain.php',
'WeMini\\Plugs' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Plugs.php',
'WeMini\\Poi' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Poi.php',
'WeMini\\Qrcode' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Qrcode.php',
'WeMini\\Template' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Template.php',
'WeMini\\Tester' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini/Tester.php',
'WeMini\\Total' => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeMini/Total.php',
'WeMini\\User' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeMini/User.php',
'WeOpen\\Login' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeOpen/Login.php',
'WeOpen\\MiniApp' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeOpen/MiniApp.php',
'WeOpen\\Service' => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeOpen/Service.php',
'app\\admin\\controller\\Auth' => __DIR__ . '/../..' . '/application/admin/controller/Auth.php',
'app\\admin\\controller\\Config' => __DIR__ . '/../..' . '/application/admin/controller/Config.php',
@ -276,9 +284,9 @@ class ComposerStaticInita33eeddf73f94e102eeb54914d7e1903
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInita33eeddf73f94e102eeb54914d7e1903::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInita33eeddf73f94e102eeb54914d7e1903::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInita33eeddf73f94e102eeb54914d7e1903::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInite29f1d41f74bbc25b33cf82965146bdc::$classMap;
}, null, ClassLoader::class);
}

View File

@ -1,17 +1,17 @@
[
{
"name": "topthink/think-installer",
"version": "v1.0.12",
"version_normalized": "1.0.12.0",
"version": "v2.0.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-installer.git",
"reference": "1be326e68f63de4e95977ed50f46ae75f017556d"
"reference": "f5400a12c60e513911aef41fe443fa6920952675"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/top-think/think-installer/1be326e68f63de4e95977ed50f46ae75f017556d.zip",
"reference": "1be326e68f63de4e95977ed50f46ae75f017556d",
"url": "https://files.phpcomposer.com/files/top-think/think-installer/f5400a12c60e513911aef41fe443fa6920952675.zip",
"reference": "f5400a12c60e513911aef41fe443fa6920952675",
"shasum": ""
},
"require": {
@ -20,7 +20,7 @@
"require-dev": {
"composer/composer": "1.0.*@dev"
},
"time": "2017-05-27T06:58:09+00:00",
"time": "2018-05-11T06:45:42+00:00",
"type": "composer-plugin",
"extra": {
"class": "think\\composer\\Plugin"
@ -133,26 +133,27 @@
"source": {
"type": "git",
"url": "https://github.com/zoujingli/WeOpenDeveloper.git",
"reference": "8bb75bc08488a43964c00f027b21b93ed58e8d5a"
"reference": "602ef0a4742744dd19f52e610e3aa873942a188f"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/zoujingli/WeOpenDeveloper/8bb75bc08488a43964c00f027b21b93ed58e8d5a.zip",
"reference": "8bb75bc08488a43964c00f027b21b93ed58e8d5a",
"url": "https://files.phpcomposer.com/files/zoujingli/WeOpenDeveloper/602ef0a4742744dd19f52e610e3aa873942a188f.zip",
"reference": "602ef0a4742744dd19f52e610e3aa873942a188f",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=5.4",
"zoujingli/wechat-developer": "^1.0.0"
"zoujingli/wechat-developer": "^1.0"
},
"time": "2018-03-21T05:06:35+00:00",
"time": "2018-05-11T03:49:36+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"WeOpen\\": "WeOpen"
"WeOpen\\": "WeOpen",
"WeMini\\": "WeMini"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -176,22 +177,22 @@
},
{
"name": "topthink/framework",
"version": "v5.1.12",
"version_normalized": "5.1.12.0",
"version": "v5.1.13",
"version_normalized": "5.1.13.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/framework.git",
"reference": "f879603ee321af8fde56d8855445cf98bc81b042"
"reference": "1cc81707dab128e360405aa4811a27b7a5403a78"
},
"dist": {
"type": "zip",
"url": "https://files.phpcomposer.com/files/top-think/framework/f879603ee321af8fde56d8855445cf98bc81b042.zip",
"reference": "f879603ee321af8fde56d8855445cf98bc81b042",
"url": "https://files.phpcomposer.com/files/top-think/framework/1cc81707dab128e360405aa4811a27b7a5403a78.zip",
"reference": "1cc81707dab128e360405aa4811a27b7a5403a78",
"shasum": ""
},
"require": {
"php": ">=5.6.0",
"topthink/think-installer": "~1.0"
"topthink/think-installer": "2.*"
},
"require-dev": {
"johnkary/phpunit-speedtrap": "^1.0",
@ -202,7 +203,7 @@
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "2.*"
},
"time": "2018-04-26T03:46:41+00:00",
"time": "2018-05-11T07:50:00+00:00",
"type": "think-framework",
"installation-source": "dist",
"notification-url": "https://packagist.org/downloads/",

View File

@ -39,18 +39,13 @@ class ThinkExtend extends LibraryInstaller
if (!empty($extra['think-config'])) {
$composerExtra = $this->composer->getPackage()->getExtra();
$configDir = 'config';
$appDir = !empty($composerExtra['app-path']) ? $composerExtra['app-path'] : 'application';
if (is_dir($appDir)) {
$extraDir = $appDir . DIRECTORY_SEPARATOR . 'extra';
$this->filesystem->ensureDirectoryExists($extraDir);
$this->filesystem->ensureDirectoryExists($configDir);
//配置文件
foreach ((array) $extra['think-config'] as $name => $config) {
$target = $extraDir . DIRECTORY_SEPARATOR . $name . '.php';
$target = $configDir . DIRECTORY_SEPARATOR . $name . '.php';
$source = $this->getInstallPath($package) . DIRECTORY_SEPARATOR . $config;
if (is_file($target)) {
@ -65,7 +60,7 @@ class ThinkExtend extends LibraryInstaller
copy($source, $target);
}
}
}
}
}

View File

@ -0,0 +1,54 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeMini;
use WeChat\Contracts\BasicWeChat;
/**
* 基础信息设置
* Class Basic
* @package WeOpen\MiniApp
*/
class Basic extends BasicWeChat
{
/**
* 1. 设置小程序隐私设置(是否可被搜索)
* @param integer $status 1表示不可搜索0表示可搜索
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function changeWxaSearchStatus($status)
{
$url = 'https://api.weixin.qq.com/wxa/changewxasearchstatus?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['status' => $status], true);
}
/**
* 2. 查询小程序当前隐私设置(是否可被搜索)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getWxaSearchStatus()
{
$url = 'https://api.weixin.qq.com/wxa/getwxasearchstatus?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
}

View File

@ -0,0 +1,397 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeMini;
use WeChat\Contracts\BasicWeChat;
use WeChat\Contracts\Tools;
/**
* 代码管理
* Class Tester
* @package WeOpen\MiniApp
*/
class Code extends BasicWeChat
{
/**
* 1. 为授权的小程序帐号上传小程序代码
* @param string $templateId 代码库中的代码模版ID
* @param string $extJson 第三方自定义的配置
* @param string $userVersion 代码版本号,开发者可自定义
* @param string $userDesc 代码描述,开发者可自定义
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function commit($templateId, $extJson, $userVersion, $userDesc)
{
$url = 'https://api.weixin.qq.com/wxa/commit?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
$data = [
'template_id' => $templateId,
'ext_json' => $extJson,
'user_version' => $userVersion,
'user_desc' => $userDesc,
];
return $this->httpPostForJson($url, $data, true);
}
/**
* 2. 获取体验小程序的体验二维码
* @param null|string $path 指定体验版二维码跳转到某个具体页面
* @param null|string $outType 指定输出类型
* @return array|bool|string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getQrcode($path = null, $outType = null)
{
$pathStr = is_null($path) ? '' : ("&path=" . urlencode($path));
$url = "https://api.weixin.qq.com/wxa/get_qrcode?access_token=ACCESS_TOKEN{$pathStr}";
$this->registerApi($url, __FUNCTION__, func_get_args());
$result = Tools::get($url);
if (json_decode($result)) {
return Tools::json2arr($result);
}
return is_null($outType) ? $result : $outType($result);
}
/**
* 3. 获取授权小程序帐号的可选类目
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getCategory()
{
$url = 'https://api.weixin.qq.com/wxa/get_category?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 4. 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getPage()
{
$url = 'https://api.weixin.qq.com/wxa/get_page?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 5. 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用)
* @param array $itemList 提交审核项的一个列表
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function submitAudit(array $itemList)
{
$url = 'https://api.weixin.qq.com/wxa/submit_audit?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['item_list' => $itemList], true);
}
/**
* 6. 获取审核结果
* @return array
*/
public function getNotify()
{
return Tools::xml2arr(file_get_contents('php://input'));
}
/**
* 7. 查询某个指定版本的审核状态(仅供第三方代小程序调用)
* @param string $auditid 提交审核时获得的审核id
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getAuditstatus($auditid)
{
$url = 'https://api.weixin.qq.com/wxa/get_auditstatus?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['auditid' => $auditid], true);
}
/**
* 8、查询最新一次提交的审核状态(仅供第三方代小程序调用)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getLatestAuditatus()
{
$url = 'https://api.weixin.qq.com/wxa/get_latest_auditstatus?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 9、发布已通过审核的小程序(仅供第三方代小程序调用)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function publishRelease()
{
$url = 'https://api.weixin.qq.com/wxa/release?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, [], true);
}
/**
* 10、修改小程序线上代码的可见状态(仅供第三方代小程序调用)
* @param string $action 设置可访问状态发布后默认可访问close为不可见open为可见
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function changeVisitStatus($action)
{
$url = 'https://api.weixin.qq.com/wxa/change_visitstatus?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['action' => $action], true);
}
/**
* 11. 小程序版本回退(仅供第三方代小程序调用)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function revertCodeRelease()
{
$url = 'https://api.weixin.qq.com/wxa/revertcoderelease?access_token=TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 12. 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getWeappSupportVersion()
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, []);
}
/**
* 13. 设置最低基础库版本(仅供第三方代小程序调用)
* @param string $version 版本
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function setWeappSupportVersion($version)
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['version' => $version]);
}
/**
* 14. 设置小程序“扫普通链接二维码打开小程序”能力
* (1) 增加或修改二维码规则
* @param array $data
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function addQrcodeJump(array $data)
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpadd?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, $data);
}
/**
* 14. 设置小程序“扫普通链接二维码打开小程序”能力
* (2) 获取已设置的二维码规则
* @param array $data
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getQrcodeJump(array $data)
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpget?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, $data);
}
/**
* 14. 设置小程序“扫普通链接二维码打开小程序”能力
* (3)获取校验文件名称及内容
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function downloadQrcodeJump()
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpdownload?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, []);
}
/**
* 14. 设置小程序“扫普通链接二维码打开小程序”能力
* (4)删除已设置的二维码规则
* @param string $prefix 二维码规则
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function deleteQrcodeJump($prefix)
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpdelete?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['prefix' => $prefix]);
}
/**
* 14. 设置小程序“扫普通链接二维码打开小程序”能力
* (5)发布已设置的二维码规则
* @param string $prefix 二维码规则
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function publishQrcodeJump($prefix)
{
$url = 'https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumppublish?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['prefix' => $prefix]);
}
/**
* 16. 小程序审核撤回
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function undoCodeAudit()
{
$url = 'https://api.weixin.qq.com/wxa/undocodeaudit?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 17.小程序分阶段发布
* (1)分阶段发布接口
* @param integer $gray_percentage 灰度的百分比1到100的整数
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function grayRelease($gray_percentage)
{
$url = 'https://api.weixin.qq.com/wxa/grayrelease?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['gray_percentage' => $gray_percentage]);
}
/**
* 17.小程序分阶段发布
* (2)取消分阶段发布
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function revertGrayRelease()
{
$url = 'https://api.weixin.qq.com/wxa/revertgrayrelease?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 17.小程序分阶段发布
* (3)查询当前分阶段发布详情
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getGrayreLeasePlan()
{
$url = 'https://api.weixin.qq.com/wxa/getgrayreleaseplan?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 1、获取草稿箱内的所有临时代码草稿
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getTemplateDraftList()
{
$url = 'https://api.weixin.qq.com/wxa/gettemplatedraftlist?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 2、获取代码模版库中的所有小程序代码模版
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getTemplateList()
{
$url = 'https://api.weixin.qq.com/wxa/gettemplatelist?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
/**
* 3、将草稿箱的草稿选为小程序代码模版
* @param integer $draft_id 草稿ID本字段可通过“ 获取草稿箱内的所有临时代码草稿 ”接口获得
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function addToTemplate($draft_id)
{
$url = 'https://api.weixin.qq.com/wxa/grayrelease?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['draft_id' => $draft_id]);
}
/**
* 4、删除指定小程序代码模版
* @param integer $template_id 要删除的模版ID
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function deleteTemplate($template_id)
{
$url = 'https://api.weixin.qq.com/wxa/deletetemplate?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['template_id' => $template_id]);
}
}

View File

@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeMini;
use WeChat\Contracts\BasicWeChat;
/**
* 修改服务器地址
* Class Domain
* @package WeOpen\MiniApp
*/
class Domain extends BasicWeChat
{
/**
* 1、设置小程序服务器域名
* @param string $action add添加,delete删除,set覆盖,get获取。当参数是get时不需要填四个域名字段
* @param array $data 需要的参数的数据
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function modifyDomain($action, $data = [])
{
$data['action'] = $action;
$url = 'https://api.weixin.qq.com/wxa/modify_domain?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, $data, true);
}
/**
* 2、设置小程序业务域名(仅供第三方代小程序调用)
* @param string $action add添加, delete删除, set覆盖, get获取。
* 当参数是get时不需要填webviewdomain字段。
* 如果没有action字段参数则默认见开放平台第三方登记的小程序业务域名全部添加到授权的小程序中
* @param string $webviewdomain 小程序业务域名当action参数是get时不需要此字段
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function setWebViewDomain($action, $webviewdomain)
{
$url = 'https://api.weixin.qq.com/wxa/setwebviewdomain?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['action' => $action, 'webviewdomain' => $webviewdomain], true);
}
}

View File

@ -0,0 +1,68 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeMini;
use WeChat\Contracts\BasicWeChat;
/**
* 成员管理
* Class Tester
* @package WeOpen\MiniApp
*/
class Tester extends BasicWeChat
{
/**
* 1、绑定微信用户为小程序体验者
* @param string $testid 微信号
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function bindTester($testid)
{
$url = 'https://api.weixin.qq.com/wxa/bind_tester?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['wechatid' => $testid], true);
}
/**
* 2、解除绑定小程序的体验者
* @param string $testid 微信号
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function unbindTester($testid)
{
$url = 'https://api.weixin.qq.com/wxa/unbind_tester?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['wechatid' => $testid], true);
}
/**
* 3. 获取体验者列表
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getTesterList()
{
$url = 'https://api.weixin.qq.com/wxa/memberauth?access_token=ACCESS_TOKEN';
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['action' => 'get_experiencer'], true);
}
}

View File

@ -0,0 +1,83 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeMini;
use WeChat\Contracts\BasicWeChat;
/**
* 微信开放平台帐号管理
* Class Template
* @package WeOpen\MiniApp
*/
class User extends BasicWeChat
{
/**
* 1. 创建开放平台帐号并绑定公众号/小程序
* @param string $appid 授权公众号或小程序的 appid
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function create($appid)
{
$url = "https://api.weixin.qq.com/cgi-bin/open/create?access_token=ACCESS_TOKEN";
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['appid' => $appid], true);
}
/**
* 2. 将公众号/小程序绑定到开放平台帐号下
* @param string $appid 授权公众号或小程序的appid
* @param string $openAppid 开放平台帐号appid
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function bind($appid, $openAppid)
{
$url = "https://api.weixin.qq.com/cgi-bin/open/bind?access_token=ACCESS_TOKEN";
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['appid' => $appid, 'open_appid' => $openAppid]);
}
/**
* 3. 将公众号/小程序从开放平台帐号下解绑
* @param string $appid 授权公众号或小程序的appid
* @param string $openAppid 开放平台帐号appid
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function unbind($appid, $openAppid)
{
$url = "https://api.weixin.qq.com/cgi-bin/open/unbind?access_token=ACCESS_TOKEN";
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['appid' => $appid, 'open_appid' => $openAppid]);
}
/**
* 3. 获取公众号/小程序所绑定的开放平台帐号
* @param string $appid 授权公众号或小程序的appid
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function get($appid)
{
$url = "https://api.weixin.qq.com/cgi-bin/open/unbind?access_token=ACCESS_TOKEN";
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, ['appid' => $appid]);
}
}

View File

@ -0,0 +1,110 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeOpen;
use WeChat\Contracts\DataArray;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
/**
* 网站应用微信登录
* Class Login
* @package WeOpen
*/
class Login
{
/**
* 当前配置对象
* @var DataArray
*/
protected $config;
/**
* Login constructor.
* @param array $options
*/
public function __construct(array $options)
{
$this->config = new DataArray($options);
if (empty($options['appid'])) {
throw new InvalidArgumentException("Missing Config -- [appid]");
}
if (empty($options['appsecret'])) {
throw new InvalidArgumentException("Missing Config -- [appsecret]");
}
}
/**
* 第一步请求CODE
* @param string $redirectUri 请使用urlEncode对链接进行处理
* @return string
*/
public function auth($redirectUri)
{
$appid = $this->config->get('appid');
$redirectUri = urlencode($redirectUri);
return "https://open.weixin.qq.com/connect/qrconnect?appid={$appid}&redirect_uri=${$redirectUri}&response_type=code&scope=snsapi_login&state={$appid}#wechat_redirect";
}
/**
* 第二步通过code获取access_token
* @return mixed
*/
public function getAccessToken()
{
$appid = $this->config->get('appid');
$secret = $this->config->get('appsecret');
$code = isset($_GET['code']) ? $_GET['code'] : '';
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
return json_decode(Tools::get($url));
}
/**
* 刷新AccessToken有效期
* @param string $refreshToken
* @return array
*/
public function refreshToken($refreshToken)
{
$appid = $this->config->get('appid');
$url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={$appid}&grant_type=refresh_token&refresh_token={$refreshToken}";
return json_decode(Tools::get($url));
}
/**
* 检验授权凭证access_token是否有效
* @param string $accessToken 调用凭证
* @param string $openid 普通用户的标识,对当前开发者帐号唯一
* @return array
*/
public function checkAccessToken($accessToken, $openid)
{
$url = "https://api.weixin.qq.com/sns/auth?access_token={$accessToken}&openid={$openid}";
return json_decode(Tools::get($url));
}
/**
* 获取用户个人信息UnionID机制
* @param string $accessToken 调用凭证
* @param string $openid 普通用户的标识,对当前开发者帐号唯一
* @return array
*/
public function getUserinfo($accessToken, $openid)
{
$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$accessToken}&openid={$openid}";
return json_decode(Tools::get($url));
}
}

View File

@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeOpen;
use WeChat\Contracts\Tools;
/**
* 公众号小程序授权支持
* Class MiniApp
* @package WeOpen
*/
class MiniApp extends Service
{
/**
* code换取session_key
* @param string $appid 小程序的AppID
* @param string $code 登录时获取的code
* @return mixed
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function session($appid, $code)
{
$component_appid = $this->config->get('component_appid');
$component_access_token = $this->getComponentAccessToken();
$url = "https://api.weixin.qq.com/sns/component/jscode2session?appid={$appid}&js_code={$code}&grant_type=authorization_code&component_appid={$component_appid}&component_access_token={$component_access_token}";
return json_decode(Tools::get($url), true);
}
}

View File

@ -275,13 +275,14 @@ class Service
/**
* 创建指定授权公众号接口实例
* @param string $type 需要加载的接口实例名称
* @param string $name 需要加载的接口实例名称
* @param string $authorizer_appid 授权公众号的appid
* @param string $type 加载SDK类型 WeChat|WeMini
* @return \WeChat\Card|\WeChat\Custom|\WeChat\Media|\WeChat\Menu|\WeChat\Oauth|\WeChat\Pay|\WeChat\Product|\WeChat\Qrcode|\WeChat\Receive|\WeChat\Scan|\WeChat\Script|\WeChat\Shake|\WeChat\Tags|\WeChat\Template|\WeChat\User|\WeChat\Wifi
*/
public function instance($type, $authorizer_appid)
public function instance($name, $authorizer_appid, $type = 'WeChat')
{
$className = 'WeChat\\' . ucfirst(strtolower($type));
$className = "{$type}\\" . ucfirst(strtolower($name));
return new $className($this->getConfig($authorizer_appid));
}

View File

@ -20,11 +20,12 @@
"php": ">=5.4",
"ext-curl": "*",
"ext-openssl": "*",
"zoujingli/wechat-developer": "^1.0.0"
"zoujingli/wechat-developer": "^1.0"
},
"autoload": {
"psr-4": {
"WeOpen\\": "WeOpen"
"WeOpen\\": "WeOpen",
"WeMini\\": "WeMini"
}
}
}