From 83ca563d1c45da13aef6d32918bfb64b5cc2a935 Mon Sep 17 00:00:00 2001 From: tao Date: Fri, 7 Jan 2022 14:43:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E6=A0=B8=E5=BF=83=E6=A1=86?= =?UTF-8?q?=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/model/Article.php | 21 +- app/common/model/Comment.php | 4 +- app/common/model/Slider.php | 2 +- app/index/controller/Article.php | 54 ++- app/index/route/route.php | 6 +- app/install/controller/Index.php | 82 +++-- app/install/view/index/test.html | 7 +- composer.lock | 100 ++++- config/cookie.php | 2 + config/database.php | 77 ++-- vendor/composer/autoload_files.php | 2 +- vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_static.php | 7 +- vendor/composer/installed.json | 109 ++++-- vendor/composer/installed.php | 31 +- vendor/psr/http-message/CHANGELOG.md | 36 ++ vendor/psr/http-message/LICENSE | 19 + vendor/psr/http-message/README.md | 13 + vendor/psr/http-message/composer.json | 26 ++ .../psr/http-message/src/MessageInterface.php | 187 ++++++++++ .../psr/http-message/src/RequestInterface.php | 129 +++++++ .../http-message/src/ResponseInterface.php | 68 ++++ .../src/ServerRequestInterface.php | 261 +++++++++++++ .../psr/http-message/src/StreamInterface.php | 158 ++++++++ .../src/UploadedFileInterface.php | 123 +++++++ vendor/psr/http-message/src/UriInterface.php | 323 +++++++++++++++++ vendor/services.php | 2 +- vendor/topthink/framework/README.md | 2 +- vendor/topthink/framework/composer.json | 4 +- vendor/topthink/framework/src/helper.php | 2 +- vendor/topthink/framework/src/think/App.php | 31 +- .../framework/src/think/Container.php | 11 +- .../topthink/framework/src/think/Cookie.php | 6 +- vendor/topthink/framework/src/think/Env.php | 26 +- vendor/topthink/framework/src/think/File.php | 2 +- vendor/topthink/framework/src/think/Lang.php | 54 ++- .../topthink/framework/src/think/Request.php | 7 +- .../topthink/framework/src/think/Response.php | 21 +- .../src/think/console/command/Make.php | 2 +- .../src/think/console/command/RouteList.php | 7 +- .../framework/src/think/filesystem/Driver.php | 11 + .../src/think/filesystem/driver/Local.php | 8 + .../framework/src/think/log/driver/File.php | 2 + .../src/think/middleware/LoadLangPack.php | 79 +++- .../framework/src/think/route/Dispatch.php | 7 + .../framework/src/think/route/Url.php | 6 +- .../src/think/route/dispatch/Controller.php | 47 ++- .../topthink/framework/tests/DispatchTest.php | 32 ++ vendor/topthink/framework/tests/EnvTest.php | 2 - vendor/topthink/framework/tests/RouteTest.php | 7 +- .../think-helper/.github/workflows/ci.yml | 36 ++ .../think-helper/.github/workflows/php.yml | 36 ++ vendor/topthink/think-helper/.gitignore | 3 +- vendor/topthink/think-helper/README.md | 2 + vendor/topthink/think-helper/composer.json | 16 +- vendor/topthink/think-helper/phpunit.xml.dist | 17 + .../topthink/think-helper/src/Collection.php | 17 +- .../topthink/think-helper/src/helper/Str.php | 2 +- .../topthink/think-helper/tests/ArrTest.php | 342 ++++++++++++++++++ .../think-helper/tests/CollectionTest.php | 70 ++++ .../topthink/think-helper/tests/StrTest.php | 59 +++ .../topthink/think-helper/tests/TestCase.php | 13 + vendor/topthink/think-orm/src/Model.php | 43 ++- vendor/topthink/think-orm/src/Paginator.php | 10 +- .../topthink/think-orm/src/db/BaseQuery.php | 17 +- .../think-orm/src/db/PDOConnection.php | 10 +- .../think-orm/src/db/builder/Sqlite.php | 12 + .../src/db/concern/ModelRelationQuery.php | 162 +++------ .../src/db/concern/ResultOperation.php | 73 ++-- .../think-orm/src/db/concern/WhereQuery.php | 4 +- .../think-orm/src/model/Collection.php | 2 +- .../think-orm/src/model/concern/Attribute.php | 28 +- .../src/model/concern/Conversion.php | 1 + .../src/model/concern/SoftDelete.php | 31 +- .../src/model/relation/BelongsToMany.php | 98 +---- view/taoler/index/article/ask/cate.html | 10 +- view/taoler/index/article/ask/detail.html | 28 +- view/taoler/index/article/cate.html | 17 +- view/taoler/index/article/posts/cate.html | 10 +- view/taoler/index/article/posts/detail.html | 10 +- view/taoler/index/index/index.html | 2 +- 81 files changed, 2848 insertions(+), 559 deletions(-) create mode 100644 vendor/psr/http-message/CHANGELOG.md create mode 100644 vendor/psr/http-message/LICENSE create mode 100644 vendor/psr/http-message/README.md create mode 100644 vendor/psr/http-message/composer.json create mode 100644 vendor/psr/http-message/src/MessageInterface.php create mode 100644 vendor/psr/http-message/src/RequestInterface.php create mode 100644 vendor/psr/http-message/src/ResponseInterface.php create mode 100644 vendor/psr/http-message/src/ServerRequestInterface.php create mode 100644 vendor/psr/http-message/src/StreamInterface.php create mode 100644 vendor/psr/http-message/src/UploadedFileInterface.php create mode 100644 vendor/psr/http-message/src/UriInterface.php create mode 100644 vendor/topthink/framework/tests/DispatchTest.php create mode 100644 vendor/topthink/think-helper/.github/workflows/ci.yml create mode 100644 vendor/topthink/think-helper/.github/workflows/php.yml create mode 100644 vendor/topthink/think-helper/phpunit.xml.dist create mode 100644 vendor/topthink/think-helper/tests/ArrTest.php create mode 100644 vendor/topthink/think-helper/tests/CollectionTest.php create mode 100644 vendor/topthink/think-helper/tests/StrTest.php create mode 100644 vendor/topthink/think-helper/tests/TestCase.php diff --git a/app/common/model/Article.php b/app/common/model/Article.php index a956b33..b394ce8 100644 --- a/app/common/model/Article.php +++ b/app/common/model/Article.php @@ -107,7 +107,8 @@ class Article extends Model 'user' => function ($query) { $query->field('id,name,nickname,user_img,area_id,vip'); } - ])->withCount(['comments'])->order('create_time', 'desc')->limit($num)->select(); + ])->withCount(['comments'])->order('create_time', 'desc')->limit($num)->select()->toArray(); + Cache::tag('tagArtDetail')->set('arttop', $artTop, 60); } return $artTop; @@ -133,7 +134,7 @@ class Article extends Model 'user' => function($query){ $query->field('id,name,nickname,user_img,area_id,vip'); } ]) - ->withCount(['comments'])->where(['status'=>1,'is_top'=>0])->order('create_time','desc')->limit($num)->select(); + ->withCount(['comments'])->where(['status'=>1,'is_top'=>0])->order('create_time','desc')->limit($num)->select()->toArray(); Cache::tag('tagArt')->set('artlist',$artList,60); } return $artList; @@ -167,7 +168,7 @@ class Article extends Model * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ - public function getArtDetail(int $id) + public function getArtDetail(int $id, int $page) { $article = Cache::get('article_'.$id); if(!$article){ @@ -179,8 +180,8 @@ class Article extends Model 'user' => function($query){ $query->field('id,name,nickname,user_img,area_id,vip'); } - ])->find($id); - Cache::tag('tagArtDetail')->set('article_'.$id,$article,3600); + ])->withCount(['comments'])->find($id)->toArray(); + Cache::tag('tagArtDetail')->set('article_'.$id, $article, 3600); } return $article; } @@ -225,7 +226,7 @@ class Article extends Model 'list_rows' => 15, 'page' => $page, 'path' =>$url.'[PAGE]'.$suffix - ]); + ])->toArray(); break; case 'hot': @@ -241,7 +242,7 @@ class Article extends Model 'list_rows' => 15, 'page' => $page, 'path' =>$url.'[PAGE]'.$suffix - ]); + ])->toArray(); break; case 'top': @@ -257,7 +258,7 @@ class Article extends Model 'list_rows' => 15, 'page' => $page, 'path' =>$url.'[PAGE]'.$suffix - ]); + ])->toArray(); break; case 'wait': @@ -273,7 +274,7 @@ class Article extends Model 'list_rows' => 15, 'page' => $page, 'path' =>$url.'[PAGE]'.$suffix - ]); + ])->toArray(); break; default: @@ -289,7 +290,7 @@ class Article extends Model 'list_rows' => 15, 'page' => $page, 'path' =>$url.'[PAGE]'.$suffix - ]); + ])->toArray(); break; } Cache::tag('tagArtDetail')->set('arts'.$ename.$type.$page,$artList,600); diff --git a/app/common/model/Comment.php b/app/common/model/Comment.php index 3e1ebbf..30f247c 100644 --- a/app/common/model/Comment.php +++ b/app/common/model/Comment.php @@ -29,9 +29,9 @@ class Comment extends Model } //获取评论 - public function getComment($id) + public function getComment($id, $page) { - $comments = $this::where(['article_id'=>$id,'status'=>1])->order(['cai'=>'asc','create_time'=>'asc'])->paginate(10); + $comments = $this::with(['user'])->where(['article_id'=>$id,'status'=>1])->order(['cai'=>'asc','create_time'=>'asc'])->paginate(['list_rows'=>10, 'page'=>$page]); return $comments; } diff --git a/app/common/model/Slider.php b/app/common/model/Slider.php index efc2b82..9fb1132 100644 --- a/app/common/model/Slider.php +++ b/app/common/model/Slider.php @@ -34,7 +34,7 @@ class Slider extends Model { $sliders = Cache::get('slider'.$type); if(!$sliders){ - $sliders = $this::where(['slid_status'=>1,'delete_time'=>0,'slid_type'=>$type])->whereTime('slid_over','>=',time())->select(); + $sliders = $this::where(['slid_status'=>1,'delete_time'=>0,'slid_type'=>$type])->whereTime('slid_over','>=',time())->select()->toArray(); Cache::set('slider'.$type,$sliders,3600); } return $sliders; diff --git a/app/index/controller/Article.php b/app/index/controller/Article.php index 7f173a6..84e3044 100644 --- a/app/index/controller/Article.php +++ b/app/index/controller/Article.php @@ -29,27 +29,35 @@ class Article extends BaseController // 抛出 HTTP 异常 throw new \think\exception\HttpException(404, '请求异常'); } + $page = Request::param('page') ? Request::param('page') : 1; //获取分类ID $ename = Request::param('ename'); $type = Request::param('type') ?? 'all'; $tpl = Db::name('cate')->where('ename',$ename)->value('detpl'); //分页伪静态 - $str = Request::baseUrl(); //不带参数在url + //$str = Request::baseUrl(); //不带参数在url + $path = Request::pathinfo(); + $str = '/'.app('http')->getName().'/'.$path; + //halt($str); + $patterns = "/\d+/"; //数字正则 - preg_match($patterns,$str,$arr); //正则查询页码出现在位置 + $p = preg_match($patterns,$str,$arr); //正则查询页码出现在位置 + //检测route配置中是否设置了伪静态后缀 $suffix = Config::get('route.url_html_suffix') ? '.'.Config::get('route.url_html_suffix') : '/'; if(Config::get('route.url_html_suffix')){ + //伪静态有后缀 if(isset($arr[0])){ $page = $arr[0]; $url = strstr($str,$arr[0],true); } else { $page = 1; - $url = strstr($str,'.html',true).'/'; + $url = strstr($str,'.html',true); } } else { + //伪静态后缀false if(isset($arr[0])){ $page = $arr[0]; @@ -59,10 +67,12 @@ class Article extends BaseController $url = $str.'/'; } } + //分类列表 $article = new ArticleModel(); $artList = $article->getCateList($ename,$type,$page,$url,$suffix); - $count = $artList->total(); + + //$count = $artList->total(); // 热议文章 $artHot = $article->getArtHot(10); @@ -74,30 +84,38 @@ class Article extends BaseController //分类钻展赞助 $ad_comm = $ad->getSliderList(6); - View::assign(['type'=>$type,'artList'=>$artList,'artHot'=>$artHot,'ad_cateImg'=>$ad_cateImg,'ad_comm'=>$ad_comm,'jspage'=>'jie','count'=>$count,'page'=>$page,'url'=>$url]); + View::assign(['type'=>$type,'artList'=>$artList,'artHot'=>$artHot,'ad_cateImg'=>$ad_cateImg,'ad_comm'=>$ad_comm,'jspage'=>'jie','url'=>$url]); return View::fetch('article/'.$tpl.'/cate'); } //文章详情页 public function detail($id) { - $page = input('page') ? input('page') : 1; - $article = new ArticleModel(); - $artDetail = $article->getArtDetail($id); - if(is_null($artDetail)){ + $id = input('id'); + $artStu = Db::name('article')->field('id')->where(['status'=>1,'delete_time'=>0])->find($id); + if(is_null($artStu)){ // 抛出 HTTP 异常 throw new \think\exception\HttpException(404, '异常消息'); } - $arId = $artDetail->cate->id; + + //输出内容 + $page = input('page') ? input('page') : 1; + $article = new ArticleModel(); + $artDetail = $article->getArtDetail($id,$page); + $arId = $artDetail['cate_id']; $tpl = Db::name('cate')->where('id',$arId)->value('detpl'); - $comments = $artDetail->comments()->where('status',1)->order(['cai'=>'asc','create_time'=>'asc'])->paginate(['list_rows'=>10, 'page'=>$page]); - //$comment = new \app\common\model\Comment(); - //$comments = $comment->getComment($id); - //dump($comments); - $count = $comments->total(); - $artDetail->inc('pv')->update(); + $download = $artDetail['upzip'] ? download($artDetail['upzip'],'file') : ''; + + //$count = $comments->total(); + //$artDetail->inc('pv')->update(); + + //浏览pv + Db::name('article')->where('id',$id)->inc('pv')->update(); $pv = Db::name('article')->field('pv')->where('id',$id)->value('pv'); - $download = $artDetail->upzip ? download($artDetail->upzip,'file') : ''; + + //评论 + $comment = new Comment; + $comments = $comment->getComment($id, $page); // 热议文章 $artHot = $article->getArtHot(10); @@ -108,7 +126,7 @@ class Article extends BaseController //分类钻展赞助 $ad_comm = $ad->getSliderList(7); - View::assign(['article'=>$artDetail,'pv'=>$pv,'comments'=>$comments,'artHot'=>$artHot,'ad_art'=>$ad_artImg,'ad_comm'=>$ad_comm,$download,'count'=>$count,'page'=>$page,'jspage'=>'jie']); + View::assign(['article'=>$artDetail,'pv'=>$pv,'artHot'=>$artHot,'ad_art'=>$ad_artImg,'ad_comm'=>$ad_comm,$download,'page'=>$page,'comments'=>$comments,'jspage'=>'jie']); return View::fetch('article/'.$tpl.'/detail'); } diff --git a/app/index/route/route.php b/app/index/route/route.php index d61dfdb..0ccc603 100644 --- a/app/index/route/route.php +++ b/app/index/route/route.php @@ -13,8 +13,10 @@ use think\facade\Route; Route::get('captcha/[:config]','\\think\\captcha\\CaptchaController@index'); Route::rule('/', 'index'); // 首页访问路由 Route::group(function () { - Route::get('jie/:id', 'article/detail'); - Route::get('column///','article/cate') + Route::get('jie/:id', 'article/detail'); + //Route::get('column/','article/cate'); + //Route::get('column//','article/cate'); + Route::get('column//[:type]/[:page]','article/cate') ->pattern([ 'ename' => '\w+', 'page' => '\d+', diff --git a/app/install/controller/Index.php b/app/install/controller/Index.php index e9b5f67..82c99f7 100644 --- a/app/install/controller/Index.php +++ b/app/install/controller/Index.php @@ -12,8 +12,9 @@ class Index extends BaseController // 检测是否安装过 protected function initialize(){ if(file_exists('./install.lock')){ - echo ""; - die(); + //echo ""; + //die(); + return response(""); } } @@ -144,7 +145,7 @@ class Index extends BaseController 'mysql', + 'default' => env('database.driver', 'mysql'), // 自定义时间查询规则 'time_query_rule' => [], // 自动写入时间戳字段 @@ -156,43 +157,44 @@ return [ // 数据库连接配置信息 'connections' => [ 'mysql' => [ - // 数据库类型 - 'type' => 'mysql', - // 服务器地址 - 'hostname' => '{$data['DB_HOST']}', - // 数据库名 - 'database' => '{$data['DB_NAME']}', - // 用户名 - 'username' => '{$data['DB_USER']}', - // 密码 - 'password' => '{$data['DB_PWD']}', - // 端口 - 'hostport' => '{$data['DB_PORT']}', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => '{$data['DB_PREFIX']}', - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 是否需要断线重连 - 'break_reconnect' => false, - // 监听SQL - 'trigger_sql' => true, - // 开启字段缓存 - 'fields_cache' => false, - // 字段缓存路径 - 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, - ], + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', '{$data['DB_HOST']}'), + // 数据库名 + 'database' => env('database.database', '{$data['DB_NAME']}'), + // 用户名 + 'username' => env('database.username', '{$data['DB_USER']}'), + // 密码 + 'password' => env('database.password', '{$data['DB_PWD']}'), + // 端口 + 'hostport' => env('database.hostport', '{$data['DB_PORT']}'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => 'utf8', + // 数据库表前缀 + 'prefix' => env('database.prefix', '{$data['DB_PREFIX']}'), + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => false, + // 字段缓存路径 + //'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, + ], + // 更多的数据库配置信息 ], ]; php; diff --git a/app/install/view/index/test.html b/app/install/view/index/test.html index 3b160bb..0edf090 100644 --- a/app/install/view/index/test.html +++ b/app/install/view/index/test.html @@ -21,13 +21,12 @@ php版本 - >7.1 + >7.2.5 - - - =7) && $php_version['1']>1): ?> √ + + =')): ?> √ × diff --git a/composer.lock b/composer.lock index 228497d..a5bd2d3 100644 --- a/composer.lock +++ b/composer.lock @@ -531,6 +531,65 @@ }, "time": "2021-11-05T16:50:12+00:00" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/log", "version": "1.1.4", @@ -767,16 +826,16 @@ }, { "name": "topthink/framework", - "version": "v6.0.9", + "version": "v6.0.10", "source": { "type": "git", "url": "https://github.com/top-think/framework.git", - "reference": "0b5fb453f0e533de3af3a1ab6a202510b61be617" + "reference": "d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/framework/zipball/0b5fb453f0e533de3af3a1ab6a202510b61be617", - "reference": "0b5fb453f0e533de3af3a1ab6a202510b61be617", + "url": "https://api.github.com/repos/top-think/framework/zipball/d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb", + "reference": "d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb", "shasum": "", "mirrors": [ { @@ -792,12 +851,14 @@ "league/flysystem-cached-adapter": "^1.0", "php": ">=7.2.5", "psr/container": "~1.0", + "psr/http-message": "^1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", "topthink/think-helper": "^3.1.1", "topthink/think-orm": "^2.0" }, "require-dev": { + "guzzlehttp/psr7": "^2.1.0", "mikey179/vfsstream": "^1.6", "mockery/mockery": "^1.2", "phpunit/phpunit": "^7.0" @@ -832,9 +893,9 @@ ], "support": { "issues": "https://github.com/top-think/framework/issues", - "source": "https://github.com/top-think/framework/tree/v6.0.9" + "source": "https://github.com/top-think/framework/tree/v6.0.10" }, - "time": "2021-07-22T03:24:49+00:00" + "time": "2021-12-31T09:14:28+00:00" }, { "name": "topthink/think-captcha", @@ -897,16 +958,16 @@ }, { "name": "topthink/think-helper", - "version": "v3.1.5", + "version": "v3.1.6", "source": { "type": "git", "url": "https://github.com/top-think/think-helper.git", - "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905" + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/think-helper/zipball/f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", - "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", "shasum": "", "mirrors": [ { @@ -918,6 +979,9 @@ "require": { "php": ">=7.1.0" }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, "type": "library", "autoload": { "psr-4": { @@ -940,9 +1004,9 @@ "description": "The ThinkPHP6 Helper Package", "support": { "issues": "https://github.com/top-think/think-helper/issues", - "source": "https://github.com/top-think/think-helper/tree/v3.1.5" + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" }, - "time": "2021-06-21T06:17:31+00:00" + "time": "2021-12-15T04:27:55+00:00" }, { "name": "topthink/think-multi-app", @@ -1000,16 +1064,16 @@ }, { "name": "topthink/think-orm", - "version": "v2.0.45", + "version": "v2.0.47", "source": { "type": "git", "url": "https://github.com/top-think/think-orm.git", - "reference": "3dcf9af447b048103093840833e8c74ab849152f" + "reference": "e69151fba9dd21f86e392a0ae208825904d6d49a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/think-orm/zipball/3dcf9af447b048103093840833e8c74ab849152f", - "reference": "3dcf9af447b048103093840833e8c74ab849152f", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/e69151fba9dd21f86e392a0ae208825904d6d49a", + "reference": "e69151fba9dd21f86e392a0ae208825904d6d49a", "shasum": "", "mirrors": [ { @@ -1055,9 +1119,9 @@ ], "support": { "issues": "https://github.com/top-think/think-orm/issues", - "source": "https://github.com/top-think/think-orm/tree/v2.0.45" + "source": "https://github.com/top-think/think-orm/tree/v2.0.47" }, - "time": "2021-11-30T14:31:05+00:00" + "time": "2021-12-31T06:12:13+00:00" }, { "name": "topthink/think-template", diff --git a/config/cookie.php b/config/cookie.php index f728024..bff8722 100644 --- a/config/cookie.php +++ b/config/cookie.php @@ -15,4 +15,6 @@ return [ 'httponly' => false, // 是否使用 setcookie 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', ]; diff --git a/config/database.php b/config/database.php index d954bcb..72068c9 100644 --- a/config/database.php +++ b/config/database.php @@ -1,7 +1,7 @@ 'mysql', + 'default' => env('database.driver', 'mysql'), // 自定义时间查询规则 'time_query_rule' => [], // 自动写入时间戳字段 @@ -13,42 +13,43 @@ return [ // 数据库连接配置信息 'connections' => [ 'mysql' => [ - // 数据库类型 - 'type' => 'mysql', - // 服务器地址 - 'hostname' => '', - // 数据库名 - 'database' => '', - // 用户名 - 'username' => '', - // 密码 - 'password' => '', - // 端口 - 'hostport' => '3306', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => 'tao_', - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 是否需要断线重连 - 'break_reconnect' => false, - // 监听SQL - 'trigger_sql' => true, - // 开启字段缓存 - 'fields_cache' => false, - // 字段缓存路径 - 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, - ], + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', ''), + // 数据库名 + 'database' => env('database.database', ''), + // 用户名 + 'username' => env('database.username', ''), + // 密码 + 'password' => env('database.password', ''), + // 端口 + 'hostport' => env('database.hostport', ''), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => 'utf8', + // 数据库表前缀 + 'prefix' => env('database.prefix', 'tao_'), + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => false, + // 字段缓存路径 + //'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, + ], + // 更多的数据库配置信息 ], ]; \ No newline at end of file diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index bf855c7..4062436 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -11,8 +11,8 @@ return array( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', '223fa6f9b46fbe5d6b44c5ff847bfceb' => $vendorDir . '/taoser/think-addons/src/helper.php', '1cfd2761b63b0a29ed23657ea394cb2d' => $vendorDir . '/topthink/think-captcha/src/helper.php', - '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', 'd421242fd42b2ea6cd13f802bcf18a6e' => $baseDir . '/extend/taoler/com/form.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 423d0f9..af4330b 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -22,6 +22,7 @@ return array( 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index c6fd617..1f22873 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -12,9 +12,9 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', '223fa6f9b46fbe5d6b44c5ff847bfceb' => __DIR__ . '/..' . '/taoser/think-addons/src/helper.php', '1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php', - '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', 'd421242fd42b2ea6cd13f802bcf18a6e' => __DIR__ . '/../..' . '/extend/taoler/com/form.php', ); @@ -52,6 +52,7 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2 array ( 'Psr\\SimpleCache\\' => 16, 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, 'Psr\\Container\\' => 14, 'Psr\\Cache\\' => 10, 'PHPMailer\\PHPMailer\\' => 20, @@ -136,6 +137,10 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2 array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-message/src', + ), 'Psr\\Container\\' => array ( 0 => __DIR__ . '/..' . '/psr/container/src', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 4939606..3bdd25d 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -542,6 +542,68 @@ }, "install-path": "../psr/container" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "install-path": "../psr/http-message" + }, { "name": "psr/log", "version": "1.1.4", @@ -1147,17 +1209,17 @@ }, { "name": "topthink/framework", - "version": "v6.0.9", - "version_normalized": "6.0.9.0", + "version": "v6.0.10", + "version_normalized": "6.0.10.0", "source": { "type": "git", "url": "https://github.com/top-think/framework.git", - "reference": "0b5fb453f0e533de3af3a1ab6a202510b61be617" + "reference": "d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/framework/zipball/0b5fb453f0e533de3af3a1ab6a202510b61be617", - "reference": "0b5fb453f0e533de3af3a1ab6a202510b61be617", + "url": "https://api.github.com/repos/top-think/framework/zipball/d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb", + "reference": "d9cadb6971ae92ff85ba5f2be77a40b0ad5718fb", "shasum": "", "mirrors": [ { @@ -1173,17 +1235,19 @@ "league/flysystem-cached-adapter": "^1.0", "php": ">=7.2.5", "psr/container": "~1.0", + "psr/http-message": "^1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", "topthink/think-helper": "^3.1.1", "topthink/think-orm": "^2.0" }, "require-dev": { + "guzzlehttp/psr7": "^2.1.0", "mikey179/vfsstream": "^1.6", "mockery/mockery": "^1.2", "phpunit/phpunit": "^7.0" }, - "time": "2021-07-22T03:24:49+00:00", + "time": "2021-12-31T09:14:28+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1215,7 +1279,7 @@ ], "support": { "issues": "https://github.com/top-think/framework/issues", - "source": "https://github.com/top-think/framework/tree/v6.0.9" + "source": "https://github.com/top-think/framework/tree/v6.0.10" }, "install-path": "../topthink/framework" }, @@ -1279,17 +1343,17 @@ }, { "name": "topthink/think-helper", - "version": "v3.1.5", - "version_normalized": "3.1.5.0", + "version": "v3.1.6", + "version_normalized": "3.1.6.0", "source": { "type": "git", "url": "https://github.com/top-think/think-helper.git", - "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905" + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/think-helper/zipball/f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", - "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", "shasum": "", "mirrors": [ { @@ -1301,7 +1365,10 @@ "require": { "php": ">=7.1.0" }, - "time": "2021-06-21T06:17:31+00:00", + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "time": "2021-12-15T04:27:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1325,7 +1392,7 @@ "description": "The ThinkPHP6 Helper Package", "support": { "issues": "https://github.com/top-think/think-helper/issues", - "source": "https://github.com/top-think/think-helper/tree/v3.1.5" + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" }, "install-path": "../topthink/think-helper" }, @@ -1384,17 +1451,17 @@ }, { "name": "topthink/think-orm", - "version": "v2.0.45", - "version_normalized": "2.0.45.0", + "version": "v2.0.47", + "version_normalized": "2.0.47.0", "source": { "type": "git", "url": "https://github.com/top-think/think-orm.git", - "reference": "3dcf9af447b048103093840833e8c74ab849152f" + "reference": "e69151fba9dd21f86e392a0ae208825904d6d49a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/think-orm/zipball/3dcf9af447b048103093840833e8c74ab849152f", - "reference": "3dcf9af447b048103093840833e8c74ab849152f", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/e69151fba9dd21f86e392a0ae208825904d6d49a", + "reference": "e69151fba9dd21f86e392a0ae208825904d6d49a", "shasum": "", "mirrors": [ { @@ -1414,7 +1481,7 @@ "require-dev": { "phpunit/phpunit": "^7|^8|^9.5" }, - "time": "2021-11-30T14:31:05+00:00", + "time": "2021-12-31T06:12:13+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1442,7 +1509,7 @@ ], "support": { "issues": "https://github.com/top-think/think-orm/issues", - "source": "https://github.com/top-think/think-orm/tree/v2.0.45" + "source": "https://github.com/top-think/think-orm/tree/v2.0.47" }, "install-path": "../topthink/think-orm" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index dce2203..ef8beb6 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '13037f7440f2dcce2cd78297df9d6a675744ecad', + 'reference' => 'f35436abc461b29e7056f63f10302c84aeb2bfbc', 'name' => 'taoser/taoler', 'dev' => true, ), @@ -82,6 +82,15 @@ 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'dev_requirement' => false, ), + 'psr/http-message' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + 'dev_requirement' => false, + ), 'psr/log' => array( 'pretty_version' => '1.1.4', 'version' => '1.1.4.0', @@ -142,7 +151,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '13037f7440f2dcce2cd78297df9d6a675744ecad', + 'reference' => 'f35436abc461b29e7056f63f10302c84aeb2bfbc', 'dev_requirement' => false, ), 'taoser/think-addons' => array( @@ -164,12 +173,12 @@ 'dev_requirement' => false, ), 'topthink/framework' => array( - 'pretty_version' => 'v6.0.9', - 'version' => '6.0.9.0', + 'pretty_version' => 'v6.0.10', + 'version' => '6.0.10.0', 'type' => 'library', 'install_path' => __DIR__ . '/../topthink/framework', 'aliases' => array(), - 'reference' => '0b5fb453f0e533de3af3a1ab6a202510b61be617', + 'reference' => 'd9cadb6971ae92ff85ba5f2be77a40b0ad5718fb', 'dev_requirement' => false, ), 'topthink/think-captcha' => array( @@ -182,12 +191,12 @@ 'dev_requirement' => false, ), 'topthink/think-helper' => array( - 'pretty_version' => 'v3.1.5', - 'version' => '3.1.5.0', + 'pretty_version' => 'v3.1.6', + 'version' => '3.1.6.0', 'type' => 'library', 'install_path' => __DIR__ . '/../topthink/think-helper', 'aliases' => array(), - 'reference' => 'f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905', + 'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff', 'dev_requirement' => false, ), 'topthink/think-multi-app' => array( @@ -200,12 +209,12 @@ 'dev_requirement' => false, ), 'topthink/think-orm' => array( - 'pretty_version' => 'v2.0.45', - 'version' => '2.0.45.0', + 'pretty_version' => 'v2.0.47', + 'version' => '2.0.47.0', 'type' => 'library', 'install_path' => __DIR__ . '/../topthink/think-orm', 'aliases' => array(), - 'reference' => '3dcf9af447b048103093840833e8c74ab849152f', + 'reference' => 'e69151fba9dd21f86e392a0ae208825904d6d49a', 'dev_requirement' => false, ), 'topthink/think-template' => array( diff --git a/vendor/psr/http-message/CHANGELOG.md b/vendor/psr/http-message/CHANGELOG.md new file mode 100644 index 0000000..74b1ef9 --- /dev/null +++ b/vendor/psr/http-message/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.0.1 - 2016-08-06 + +### Added + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Updated all `@return self` annotation references in interfaces to use + `@return static`, which more closelly follows the semantics of the + specification. +- Updated the `MessageInterface::getHeaders()` return annotation to use the + value `string[][]`, indicating the format is a nested array of strings. +- Updated the `@link` annotation for `RequestInterface::withRequestTarget()` + to point to the correct section of RFC 7230. +- Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation + to add the parameter name (`$uploadedFiles`). +- Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()` + method to correctly reference the method parameter (it was referencing an + incorrect parameter name previously). + +## 1.0.0 - 2016-05-18 + +Initial stable release; reflects accepted PSR-7 specification. diff --git a/vendor/psr/http-message/LICENSE b/vendor/psr/http-message/LICENSE new file mode 100644 index 0000000..c2d8e45 --- /dev/null +++ b/vendor/psr/http-message/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/psr/http-message/README.md b/vendor/psr/http-message/README.md new file mode 100644 index 0000000..2818533 --- /dev/null +++ b/vendor/psr/http-message/README.md @@ -0,0 +1,13 @@ +PSR Http Message +================ + +This repository holds all interfaces/classes/traits related to +[PSR-7](http://www.php-fig.org/psr/psr-7/). + +Note that this is not a HTTP message implementation of its own. It is merely an +interface that describes a HTTP message. See the specification for more details. + +Usage +----- + +We'll certainly need some stuff in here. \ No newline at end of file diff --git a/vendor/psr/http-message/composer.json b/vendor/psr/http-message/composer.json new file mode 100644 index 0000000..b0d2937 --- /dev/null +++ b/vendor/psr/http-message/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/http-message", + "description": "Common interface for HTTP messages", + "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"], + "homepage": "https://github.com/php-fig/http-message", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/psr/http-message/src/MessageInterface.php b/vendor/psr/http-message/src/MessageInterface.php new file mode 100644 index 0000000..dd46e5e --- /dev/null +++ b/vendor/psr/http-message/src/MessageInterface.php @@ -0,0 +1,187 @@ +getHeaders() as $name => $values) { + * echo $name . ": " . implode(", ", $values); + * } + * + * // Emit headers iteratively: + * foreach ($message->getHeaders() as $name => $values) { + * foreach ($values as $value) { + * header(sprintf('%s: %s', $name, $value), false); + * } + * } + * + * While header names are not case-sensitive, getHeaders() will preserve the + * exact case in which headers were originally specified. + * + * @return string[][] Returns an associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function getHeaders(); + + /** + * Checks if a header exists by the given case-insensitive name. + * + * @param string $name Case-insensitive header field name. + * @return bool Returns true if any header names match the given header + * name using a case-insensitive string comparison. Returns false if + * no matching header name is found in the message. + */ + public function hasHeader($name); + + /** + * Retrieves a message header value by the given case-insensitive name. + * + * This method returns an array of all the header values of the given + * case-insensitive header name. + * + * If the header does not appear in the message, this method MUST return an + * empty array. + * + * @param string $name Case-insensitive header field name. + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. + */ + public function getHeader($name); + + /** + * Retrieves a comma-separated string of the values for a single header. + * + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. + * + * NOTE: Not all header values may be appropriately represented using + * comma concatenation. For such headers, use getHeader() instead + * and supply your own delimiter when concatenating. + * + * If the header does not appear in the message, this method MUST return + * an empty string. + * + * @param string $name Case-insensitive header field name. + * @return string A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return an empty string. + */ + public function getHeaderLine($name); + + /** + * Return an instance with the provided value replacing the specified header. + * + * While header names are case-insensitive, the casing of the header will + * be preserved by this function, and returned from getHeaders(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new and/or updated header and value. + * + * @param string $name Case-insensitive header field name. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withHeader($name, $value); + + /** + * Return an instance with the specified header appended with the given value. + * + * Existing values for the specified header will be maintained. The new + * value(s) will be appended to the existing list. If the header did not + * exist previously, it will be added. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new header and/or value. + * + * @param string $name Case-insensitive header field name to add. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withAddedHeader($name, $value); + + /** + * Return an instance without the specified header. + * + * Header resolution MUST be done without case-sensitivity. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the named header. + * + * @param string $name Case-insensitive header field name to remove. + * @return static + */ + public function withoutHeader($name); + + /** + * Gets the body of the message. + * + * @return StreamInterface Returns the body as a stream. + */ + public function getBody(); + + /** + * Return an instance with the specified message body. + * + * The body MUST be a StreamInterface object. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * new body stream. + * + * @param StreamInterface $body Body. + * @return static + * @throws \InvalidArgumentException When the body is not valid. + */ + public function withBody(StreamInterface $body); +} diff --git a/vendor/psr/http-message/src/RequestInterface.php b/vendor/psr/http-message/src/RequestInterface.php new file mode 100644 index 0000000..a96d4fd --- /dev/null +++ b/vendor/psr/http-message/src/RequestInterface.php @@ -0,0 +1,129 @@ +getQuery()` + * or from the `QUERY_STRING` server param. + * + * @return array + */ + public function getQueryParams(); + + /** + * Return an instance with the specified query string arguments. + * + * These values SHOULD remain immutable over the course of the incoming + * request. They MAY be injected during instantiation, such as from PHP's + * $_GET superglobal, or MAY be derived from some other value such as the + * URI. In cases where the arguments are parsed from the URI, the data + * MUST be compatible with what PHP's parse_str() would return for + * purposes of how duplicate query parameters are handled, and how nested + * sets are handled. + * + * Setting query string arguments MUST NOT change the URI stored by the + * request, nor the values in the server params. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated query string arguments. + * + * @param array $query Array of query string arguments, typically from + * $_GET. + * @return static + */ + public function withQueryParams(array $query); + + /** + * Retrieve normalized file upload data. + * + * This method returns upload metadata in a normalized tree, with each leaf + * an instance of Psr\Http\Message\UploadedFileInterface. + * + * These values MAY be prepared from $_FILES or the message body during + * instantiation, or MAY be injected via withUploadedFiles(). + * + * @return array An array tree of UploadedFileInterface instances; an empty + * array MUST be returned if no data is present. + */ + public function getUploadedFiles(); + + /** + * Create a new instance with the specified uploaded files. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param array $uploadedFiles An array tree of UploadedFileInterface instances. + * @return static + * @throws \InvalidArgumentException if an invalid structure is provided. + */ + public function withUploadedFiles(array $uploadedFiles); + + /** + * Retrieve any parameters provided in the request body. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, this method MUST + * return the contents of $_POST. + * + * Otherwise, this method may return any results of deserializing + * the request body content; as parsing returns structured content, the + * potential types MUST be arrays or objects only. A null value indicates + * the absence of body content. + * + * @return null|array|object The deserialized body parameters, if any. + * These will typically be an array or object. + */ + public function getParsedBody(); + + /** + * Return an instance with the specified body parameters. + * + * These MAY be injected during instantiation. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, use this method + * ONLY to inject the contents of $_POST. + * + * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of + * deserializing the request body content. Deserialization/parsing returns + * structured data, and, as such, this method ONLY accepts arrays or objects, + * or a null value if nothing was available to parse. + * + * As an example, if content negotiation determines that the request data + * is a JSON payload, this method could be used to create a request + * instance with the deserialized parameters. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param null|array|object $data The deserialized body data. This will + * typically be in an array or object. + * @return static + * @throws \InvalidArgumentException if an unsupported argument type is + * provided. + */ + public function withParsedBody($data); + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + * + * @return array Attributes derived from the request. + */ + public function getAttributes(); + + /** + * Retrieve a single derived request attribute. + * + * Retrieves a single derived request attribute as described in + * getAttributes(). If the attribute has not been previously set, returns + * the default value as provided. + * + * This method obviates the need for a hasAttribute() method, as it allows + * specifying a default value to return if the attribute is not found. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $default Default value to return if the attribute does not exist. + * @return mixed + */ + public function getAttribute($name, $default = null); + + /** + * Return an instance with the specified derived request attribute. + * + * This method allows setting a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $value The value of the attribute. + * @return static + */ + public function withAttribute($name, $value); + + /** + * Return an instance that removes the specified derived request attribute. + * + * This method allows removing a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @return static + */ + public function withoutAttribute($name); +} diff --git a/vendor/psr/http-message/src/StreamInterface.php b/vendor/psr/http-message/src/StreamInterface.php new file mode 100644 index 0000000..f68f391 --- /dev/null +++ b/vendor/psr/http-message/src/StreamInterface.php @@ -0,0 +1,158 @@ + + * [user-info@]host[:port] + * + * + * If the port component is not set or is the standard port for the current + * scheme, it SHOULD NOT be included. + * + * @see https://tools.ietf.org/html/rfc3986#section-3.2 + * @return string The URI authority, in "[user-info@]host[:port]" format. + */ + public function getAuthority(); + + /** + * Retrieve the user information component of the URI. + * + * If no user information is present, this method MUST return an empty + * string. + * + * If a user is present in the URI, this will return that value; + * additionally, if the password is also present, it will be appended to the + * user value, with a colon (":") separating the values. + * + * The trailing "@" character is not part of the user information and MUST + * NOT be added. + * + * @return string The URI user information, in "username[:password]" format. + */ + public function getUserInfo(); + + /** + * Retrieve the host component of the URI. + * + * If no host is present, this method MUST return an empty string. + * + * The value returned MUST be normalized to lowercase, per RFC 3986 + * Section 3.2.2. + * + * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 + * @return string The URI host. + */ + public function getHost(); + + /** + * Retrieve the port component of the URI. + * + * If a port is present, and it is non-standard for the current scheme, + * this method MUST return it as an integer. If the port is the standard port + * used with the current scheme, this method SHOULD return null. + * + * If no port is present, and no scheme is present, this method MUST return + * a null value. + * + * If no port is present, but a scheme is present, this method MAY return + * the standard port for that scheme, but SHOULD return null. + * + * @return null|int The URI port. + */ + public function getPort(); + + /** + * Retrieve the path component of the URI. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * Normally, the empty path "" and absolute path "/" are considered equal as + * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically + * do this normalization because in contexts with a trimmed base path, e.g. + * the front controller, this difference becomes significant. It's the task + * of the user to handle both "" and "/". + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.3. + * + * As an example, if the value should include a slash ("/") not intended as + * delimiter between path segments, that value MUST be passed in encoded + * form (e.g., "%2F") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.3 + * @return string The URI path. + */ + public function getPath(); + + /** + * Retrieve the query string of the URI. + * + * If no query string is present, this method MUST return an empty string. + * + * The leading "?" character is not part of the query and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.4. + * + * As an example, if a value in a key/value pair of the query string should + * include an ampersand ("&") not intended as a delimiter between values, + * that value MUST be passed in encoded form (e.g., "%26") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.4 + * @return string The URI query string. + */ + public function getQuery(); + + /** + * Retrieve the fragment component of the URI. + * + * If no fragment is present, this method MUST return an empty string. + * + * The leading "#" character is not part of the fragment and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.5. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.5 + * @return string The URI fragment. + */ + public function getFragment(); + + /** + * Return an instance with the specified scheme. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified scheme. + * + * Implementations MUST support the schemes "http" and "https" case + * insensitively, and MAY accommodate other schemes if required. + * + * An empty scheme is equivalent to removing the scheme. + * + * @param string $scheme The scheme to use with the new instance. + * @return static A new instance with the specified scheme. + * @throws \InvalidArgumentException for invalid or unsupported schemes. + */ + public function withScheme($scheme); + + /** + * Return an instance with the specified user information. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified user information. + * + * Password is optional, but the user information MUST include the + * user; an empty string for the user is equivalent to removing user + * information. + * + * @param string $user The user name to use for authority. + * @param null|string $password The password associated with $user. + * @return static A new instance with the specified user information. + */ + public function withUserInfo($user, $password = null); + + /** + * Return an instance with the specified host. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified host. + * + * An empty host value is equivalent to removing the host. + * + * @param string $host The hostname to use with the new instance. + * @return static A new instance with the specified host. + * @throws \InvalidArgumentException for invalid hostnames. + */ + public function withHost($host); + + /** + * Return an instance with the specified port. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified port. + * + * Implementations MUST raise an exception for ports outside the + * established TCP and UDP port ranges. + * + * A null value provided for the port is equivalent to removing the port + * information. + * + * @param null|int $port The port to use with the new instance; a null value + * removes the port information. + * @return static A new instance with the specified port. + * @throws \InvalidArgumentException for invalid ports. + */ + public function withPort($port); + + /** + * Return an instance with the specified path. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified path. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * If the path is intended to be domain-relative rather than path relative then + * it must begin with a slash ("/"). Paths not starting with a slash ("/") + * are assumed to be relative to some base path known to the application or + * consumer. + * + * Users can provide both encoded and decoded path characters. + * Implementations ensure the correct encoding as outlined in getPath(). + * + * @param string $path The path to use with the new instance. + * @return static A new instance with the specified path. + * @throws \InvalidArgumentException for invalid paths. + */ + public function withPath($path); + + /** + * Return an instance with the specified query string. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified query string. + * + * Users can provide both encoded and decoded query characters. + * Implementations ensure the correct encoding as outlined in getQuery(). + * + * An empty query string value is equivalent to removing the query string. + * + * @param string $query The query string to use with the new instance. + * @return static A new instance with the specified query string. + * @throws \InvalidArgumentException for invalid query strings. + */ + public function withQuery($query); + + /** + * Return an instance with the specified URI fragment. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified URI fragment. + * + * Users can provide both encoded and decoded fragment characters. + * Implementations ensure the correct encoding as outlined in getFragment(). + * + * An empty fragment value is equivalent to removing the fragment. + * + * @param string $fragment The fragment to use with the new instance. + * @return static A new instance with the specified fragment. + */ + public function withFragment($fragment); + + /** + * Return the string representation as a URI reference. + * + * Depending on which components of the URI are present, the resulting + * string is either a full URI or relative reference according to RFC 3986, + * Section 4.1. The method concatenates the various components of the URI, + * using the appropriate delimiters: + * + * - If a scheme is present, it MUST be suffixed by ":". + * - If an authority is present, it MUST be prefixed by "//". + * - The path can be concatenated without delimiters. But there are two + * cases where the path has to be adjusted to make the URI reference + * valid as PHP does not allow to throw an exception in __toString(): + * - If the path is rootless and an authority is present, the path MUST + * be prefixed by "/". + * - If the path is starting with more than one "/" and no authority is + * present, the starting slashes MUST be reduced to one. + * - If a query is present, it MUST be prefixed by "?". + * - If a fragment is present, it MUST be prefixed by "#". + * + * @see http://tools.ietf.org/html/rfc3986#section-4.1 + * @return string + */ + public function __toString(); +} diff --git a/vendor/services.php b/vendor/services.php index 2bc1318..beea780 100644 --- a/vendor/services.php +++ b/vendor/services.php @@ -1,5 +1,5 @@ 'taoser\\addons\\Service', diff --git a/vendor/topthink/framework/README.md b/vendor/topthink/framework/README.md index 0ea03c9..aa16486 100644 --- a/vendor/topthink/framework/README.md +++ b/vendor/topthink/framework/README.md @@ -35,7 +35,7 @@ ThinkPHP6.0底层架构采用PHP7.1改写和进一步优化。 * 统一和精简大量用法 -> ThinkPHP6.0的运行环境要求PHP7.1+,兼容PHP8.0。 +> ThinkPHP6.0的运行环境要求PHP7.2+,兼容PHP8.1 ## 安装 diff --git a/vendor/topthink/framework/composer.json b/vendor/topthink/framework/composer.json index 4be2ae0..90793d3 100644 --- a/vendor/topthink/framework/composer.json +++ b/vendor/topthink/framework/composer.json @@ -27,13 +27,15 @@ "psr/log": "~1.0", "psr/container": "~1.0", "psr/simple-cache": "^1.0", + "psr/http-message": "^1.0", "topthink/think-orm": "^2.0", "topthink/think-helper": "^3.1.1" }, "require-dev": { "mikey179/vfsstream": "^1.6", "mockery/mockery": "^1.2", - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^7.0", + "guzzlehttp/psr7": "^2.1.0" }, "autoload": { "files": [], diff --git a/vendor/topthink/framework/src/helper.php b/vendor/topthink/framework/src/helper.php index 650edcb..e436e14 100644 --- a/vendor/topthink/framework/src/helper.php +++ b/vendor/topthink/framework/src/helper.php @@ -149,7 +149,7 @@ if (!function_exists('cookie')) { { if (is_null($value)) { // 删除 - Cookie::delete($name); + Cookie::delete($name, $option ?: []); } elseif ('' === $value) { // 获取 return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1)) : Cookie::get($name); diff --git a/vendor/topthink/framework/src/think/App.php b/vendor/topthink/framework/src/think/App.php index 056a341..101bb6d 100644 --- a/vendor/topthink/framework/src/think/App.php +++ b/vendor/topthink/framework/src/think/App.php @@ -39,7 +39,7 @@ use think\initializer\RegisterService; */ class App extends Container { - const VERSION = '6.0.9'; + const VERSION = '6.0.10LTS'; /** * 应用调试模式 @@ -168,7 +168,7 @@ class App extends Container */ public function __construct(string $rootPath = '') { - $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR; + $this->thinkPath = realpath(dirname(__DIR__)) . DIRECTORY_SEPARATOR; $this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath(); $this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR; $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR; @@ -450,13 +450,8 @@ class App extends Container // 加载全局初始化文件 $this->load(); - // 加载框架默认语言包 - $langSet = $this->lang->defaultLangSet(); - - $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php'); - // 加载应用默认语言包 - $this->loadLangPack($langSet); + $this->loadLangPack(); // 监听AppInit $this->event->trigger(AppInit::class); @@ -482,25 +477,13 @@ class App extends Container /** * 加载语言包 - * @param string $langset 语言 * @return void */ - public function loadLangPack($langset) + public function loadLangPack() { - if (empty($langset)) { - return; - } - - // 加载系统语言包 - $files = glob($this->appPath . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*'); - $this->lang->load($files); - - // 加载扩展(自定义)语言包 - $list = $this->config->get('lang.extend_list', []); - - if (isset($list[$langset])) { - $this->lang->load($list[$langset]); - } + // 加载默认语言包 + $langSet = $this->lang->defaultLangSet(); + $this->lang->switchLangSet($langSet); } /** diff --git a/vendor/topthink/framework/src/think/Container.php b/vendor/topthink/framework/src/think/Container.php index 74026bb..e3a4341 100644 --- a/vendor/topthink/framework/src/think/Container.php +++ b/vendor/topthink/framework/src/think/Container.php @@ -27,6 +27,7 @@ use ReflectionMethod; use think\exception\ClassNotFoundException; use think\exception\FuncNotFoundException; use think\helper\Str; +use Traversable; /** * 容器管理类 支持PSR-11 @@ -520,34 +521,38 @@ class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, C $this->delete($name); } - public function offsetExists($key) + #[\ReturnTypeWillChange] + public function offsetExists($key): bool { return $this->exists($key); } + #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->make($key); } + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { $this->bind($key, $value); } + #[\ReturnTypeWillChange] public function offsetUnset($key) { $this->delete($key); } //Countable - public function count() + public function count(): int { return count($this->instances); } //IteratorAggregate - public function getIterator() + public function getIterator(): Traversable { return new ArrayIterator($this->instances); } diff --git a/vendor/topthink/framework/src/think/Cookie.php b/vendor/topthink/framework/src/think/Cookie.php index ebbfd64..04774a6 100644 --- a/vendor/topthink/framework/src/think/Cookie.php +++ b/vendor/topthink/framework/src/think/Cookie.php @@ -158,11 +158,13 @@ class Cookie * Cookie删除 * @access public * @param string $name cookie名称 + * @param array $options cookie参数 * @return void */ - public function delete(string $name): void + public function delete(string $name, array $options = []): void { - $this->setCookie($name, '', time() - 3600, $this->config); + $config = array_merge($this->config, array_change_key_case($options)); + $this->setCookie($name, '', time() - 3600, $config); } /** diff --git a/vendor/topthink/framework/src/think/Env.php b/vendor/topthink/framework/src/think/Env.php index 4c26b33..1046bc4 100644 --- a/vendor/topthink/framework/src/think/Env.php +++ b/vendor/topthink/framework/src/think/Env.php @@ -26,6 +26,17 @@ class Env implements ArrayAccess */ protected $data = []; + /** + * 数据转换映射 + * @var array + */ + protected $convert = [ + 'true' => true, + 'false' => false, + 'off' => false, + 'on' => true, + ]; + public function __construct() { $this->data = $_ENV; @@ -39,7 +50,7 @@ class Env implements ArrayAccess */ public function load(string $file): void { - $env = parse_ini_file($file, true) ?: []; + $env = parse_ini_file($file, true, INI_SCANNER_RAW) ?: []; $this->set($env); } @@ -57,9 +68,14 @@ class Env implements ArrayAccess } $name = strtoupper(str_replace('.', '_', $name)); - if (isset($this->data[$name])) { - return $this->data[$name]; + $result = $this->data[$name]; + + if (is_string($result) && isset($this->convert[$result])) { + return $this->convert[$result]; + } + + return $result; } return $this->getEnv($name, $default); @@ -159,21 +175,25 @@ class Env implements ArrayAccess } // ArrayAccess + #[\ReturnTypeWillChange] public function offsetSet($name, $value): void { $this->set($name, $value); } + #[\ReturnTypeWillChange] public function offsetExists($name): bool { return $this->__isset($name); } + #[\ReturnTypeWillChange] public function offsetUnset($name) { throw new Exception('not support: unset'); } + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->get($name); diff --git a/vendor/topthink/framework/src/think/File.php b/vendor/topthink/framework/src/think/File.php index f7c37bd..087e808 100644 --- a/vendor/topthink/framework/src/think/File.php +++ b/vendor/topthink/framework/src/think/File.php @@ -176,7 +176,7 @@ class File extends SplFileInfo $this->hashName = call_user_func($rule); break; default: - $this->hashName = date('Ymd') . DIRECTORY_SEPARATOR . md5((string) microtime(true)); + $this->hashName = date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true) . $this->getPathname()); break; } } diff --git a/vendor/topthink/framework/src/think/Lang.php b/vendor/topthink/framework/src/think/Lang.php index 0b79b76..0226f81 100644 --- a/vendor/topthink/framework/src/think/Lang.php +++ b/vendor/topthink/framework/src/think/Lang.php @@ -18,6 +18,8 @@ namespace think; */ class Lang { + protected $app; + /** * 配置参数 * @var array @@ -62,15 +64,26 @@ class Lang * @access public * @param array $config */ - public function __construct(array $config = []) + public function __construct(App $app, array $config = []) { $this->config = array_merge($this->config, array_change_key_case($config)); $this->range = $this->config['default_lang']; + $this->app = $app; } - public static function __make(Config $config) + public static function __make(App $app, Config $config) { - return new static($config->get('lang')); + return new static($app, $config->get('lang')); + } + + /** + * 获取当前语言配置 + * @access public + * @return array + */ + public function getConfig(): array + { + return $this->config; } /** @@ -104,6 +117,35 @@ class Lang return $this->config['default_lang']; } + /** + * 切换语言 + * @access public + * @param string $langset 语言 + * @return void + */ + public function switchLangSet(string $langset) + { + if (empty($langset)) { + return; + } + + // 加载系统语言包 + $this->load([ + $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php', + ]); + + // 加载系统语言包 + $files = glob($this->app->getAppPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*'); + $this->load($files); + + // 加载扩展(自定义)语言包 + $list = $this->app->config->get('lang.extend_list', []); + + if (isset($list[$langset])) { + $this->load($list[$langset]); + } + } + /** * 加载语言定义(不区分大小写) * @access public @@ -202,6 +244,10 @@ class Lang { $range = $range ?: $this->range; + if (!isset($this->lang[$range])) { + $this->switchLangSet($range); + } + // 空参数返回所有定义 if (is_null($name)) { return $this->lang[$range] ?? []; @@ -241,6 +287,7 @@ class Lang /** * 自动侦测设置获取语言选择 + * @deprecated * @access public * @param Request $request * @return string @@ -280,6 +327,7 @@ class Lang /** * 保存当前语言到Cookie + * @deprecated * @access public * @param Cookie $cookie Cookie对象 * @return void diff --git a/vendor/topthink/framework/src/think/Request.php b/vendor/topthink/framework/src/think/Request.php index 1c15f63..fe9938d 100644 --- a/vendor/topthink/framework/src/think/Request.php +++ b/vendor/topthink/framework/src/think/Request.php @@ -13,6 +13,7 @@ declare (strict_types = 1); namespace think; use ArrayAccess; +use think\facade\Lang; use think\file\UploadedFile; use think\route\Rule; @@ -1227,7 +1228,7 @@ class Request implements ArrayAccess 7 => 'file write error', ]; - $msg = $fileUploadErrors[$error]; + $msg = Lang::get($fileUploadErrors[$error]); throw new Exception($msg, $error); } @@ -2150,19 +2151,23 @@ class Request implements ArrayAccess } // ArrayAccess + #[\ReturnTypeWillChange] public function offsetExists($name): bool { return $this->has($name); } + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->param($name); } + #[\ReturnTypeWillChange] public function offsetSet($name, $value) {} + #[\ReturnTypeWillChange] public function offsetUnset($name) {} diff --git a/vendor/topthink/framework/src/think/Response.php b/vendor/topthink/framework/src/think/Response.php index a8a61ff..49f26dc 100644 --- a/vendor/topthink/framework/src/think/Response.php +++ b/vendor/topthink/framework/src/think/Response.php @@ -130,16 +130,19 @@ abstract class Response // 处理输出数据 $data = $this->getContent(); - if (!headers_sent() && !empty($this->header)) { - // 发送状态码 - http_response_code($this->code); - // 发送头部信息 - foreach ($this->header as $name => $val) { - header($name . (!is_null($val) ? ':' . $val : '')); + if (!headers_sent()) { + if (!empty($this->header)) { + // 发送状态码 + http_response_code($this->code); + // 发送头部信息 + foreach ($this->header as $name => $val) { + header($name . (!is_null($val) ? ':' . $val : '')); + } + } + + if ($this->cookie) { + $this->cookie->save(); } - } - if ($this->cookie) { - $this->cookie->save(); } $this->sendData($data); diff --git a/vendor/topthink/framework/src/think/console/command/Make.php b/vendor/topthink/framework/src/think/console/command/Make.php index 662b337..a74e9e8 100644 --- a/vendor/topthink/framework/src/think/console/command/Make.php +++ b/vendor/topthink/framework/src/think/console/command/Make.php @@ -67,7 +67,7 @@ abstract class Make extends Command protected function getPathName(string $name): string { - $name = str_replace('app\\', '', $name); + $name = substr($name, 4); return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php'; } diff --git a/vendor/topthink/framework/src/think/console/command/RouteList.php b/vendor/topthink/framework/src/think/console/command/RouteList.php index ed579b8..e9d4c5d 100644 --- a/vendor/topthink/framework/src/think/console/command/RouteList.php +++ b/vendor/topthink/framework/src/think/console/command/RouteList.php @@ -91,14 +91,13 @@ class RouteList extends Command foreach ($routeList as $item) { $item['route'] = $item['route'] instanceof \Closure ? '' : $item['route']; + $row = [$item['rule'], $item['route'], $item['method'], $item['name']]; if ($this->input->hasOption('more')) { - $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $item['domain'], json_encode($item['option']), json_encode($item['pattern'])]; - } else { - $item = [$item['rule'], $item['route'], $item['method'], $item['name']]; + array_push($row, $item['domain'], json_encode($item['option']), json_encode($item['pattern'])); } - $rows[] = $item; + $rows[] = $row; } if ($this->input->getOption('sort')) { diff --git a/vendor/topthink/framework/src/think/filesystem/Driver.php b/vendor/topthink/framework/src/think/filesystem/Driver.php index 6712959..0e61cf4 100644 --- a/vendor/topthink/framework/src/think/filesystem/Driver.php +++ b/vendor/topthink/framework/src/think/filesystem/Driver.php @@ -17,6 +17,7 @@ use League\Flysystem\Adapter\AbstractAdapter; use League\Flysystem\Cached\CachedAdapter; use League\Flysystem\Cached\Storage\Memory as MemoryStore; use League\Flysystem\Filesystem; +use RuntimeException; use think\Cache; use think\File; @@ -91,6 +92,16 @@ abstract class Driver return $path; } + protected function concatPathToUrl($url, $path) + { + return rtrim($url, '/') . '/' . ltrim($path, '/'); + } + + public function url(string $path): string + { + throw new RuntimeException('This driver does not support retrieving URLs.'); + } + /** * 保存文件 * @param string $path 路径 diff --git a/vendor/topthink/framework/src/think/filesystem/driver/Local.php b/vendor/topthink/framework/src/think/filesystem/driver/Local.php index c10ccc3..31172d0 100644 --- a/vendor/topthink/framework/src/think/filesystem/driver/Local.php +++ b/vendor/topthink/framework/src/think/filesystem/driver/Local.php @@ -41,4 +41,12 @@ class Local extends Driver $permissions ); } + + public function url(string $path): string + { + if (isset($this->config['url'])) { + return $this->concatPathToUrl($this->config['url'], $path); + } + return parent::url($path); + } } diff --git a/vendor/topthink/framework/src/think/log/driver/File.php b/vendor/topthink/framework/src/think/log/driver/File.php index e5682fc..1f726b0 100644 --- a/vendor/topthink/framework/src/think/log/driver/File.php +++ b/vendor/topthink/framework/src/think/log/driver/File.php @@ -139,7 +139,9 @@ class File implements LogHandlerInterface try { if (count($files) > $this->config['max_files']) { + set_error_handler(function ($errno, $errstr, $errfile, $errline) {}); unlink($files[0]); + restore_error_handler(); } } catch (\Exception $e) { // diff --git a/vendor/topthink/framework/src/think/middleware/LoadLangPack.php b/vendor/topthink/framework/src/think/middleware/LoadLangPack.php index 478e29c..d6bf6a4 100644 --- a/vendor/topthink/framework/src/think/middleware/LoadLangPack.php +++ b/vendor/topthink/framework/src/think/middleware/LoadLangPack.php @@ -14,6 +14,8 @@ namespace think\middleware; use Closure; use think\App; +use think\Config; +use think\Cookie; use think\Lang; use think\Request; use think\Response; @@ -24,13 +26,14 @@ use think\Response; class LoadLangPack { protected $app; - protected $lang; + protected $config; - public function __construct(App $app, Lang $lang) + public function __construct(App $app, Lang $lang, Config $config) { - $this->app = $app; - $this->lang = $lang; + $this->app = $app; + $this->lang = $lang; + $this->config = $lang->getConfig(); } /** @@ -43,19 +46,71 @@ class LoadLangPack public function handle($request, Closure $next) { // 自动侦测当前语言 - $langset = $this->lang->detect($request); + $langset = $this->detect($request); if ($this->lang->defaultLangSet() != $langset) { - // 加载系统语言包 - $this->lang->load([ - $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php', - ]); - - $this->app->LoadLangPack($langset); + $this->lang->switchLangSet($langset); } - $this->lang->saveToCookie($this->app->cookie); + $this->saveToCookie($this->app->cookie, $langset); return $next($request); } + + /** + * 自动侦测设置获取语言选择 + * @access protected + * @param Request $request + * @return string + */ + protected function detect(Request $request): string + { + // 自动侦测设置获取语言选择 + $langSet = ''; + + if ($request->get($this->config['detect_var'])) { + // url中设置了语言变量 + $langSet = strtolower($request->get($this->config['detect_var'])); + } elseif ($request->header($this->config['header_var'])) { + // Header中设置了语言变量 + $langSet = strtolower($request->header($this->config['header_var'])); + } elseif ($request->cookie($this->config['cookie_var'])) { + // Cookie中设置了语言变量 + $langSet = strtolower($request->cookie($this->config['cookie_var'])); + } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) { + // 自动侦测浏览器语言 + $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches); + if ($match) { + $langSet = strtolower($matches[1]); + if (isset($this->config['accept_language'][$langSet])) { + $langSet = $this->config['accept_language'][$langSet]; + } + } + } + + if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) { + // 合法的语言 + $range = $langSet; + $this->lang->setLangSet($range); + } else { + $range = $this->lang->getLangSet(); + } + + return $range; + } + + /** + * 保存当前语言到Cookie + * @access protected + * @param Cookie $cookie Cookie对象 + * @param string $langSet 语言 + * @return void + */ + protected function saveToCookie(Cookie $cookie, string $langSet) + { + if ($this->config['use_cookie']) { + $cookie->set($this->config['cookie_var'], $langSet); + } + } + } diff --git a/vendor/topthink/framework/src/think/route/Dispatch.php b/vendor/topthink/framework/src/think/route/Dispatch.php index e77e299..0599dc1 100644 --- a/vendor/topthink/framework/src/think/route/Dispatch.php +++ b/vendor/topthink/framework/src/think/route/Dispatch.php @@ -12,6 +12,7 @@ declare (strict_types = 1); namespace think\route; +use Psr\Http\Message\ResponseInterface; use think\App; use think\Container; use think\Request; @@ -94,6 +95,12 @@ abstract class Dispatch { if ($data instanceof Response) { $response = $data; + } elseif ($data instanceof ResponseInterface) { + $response = Response::create($data->getBody()->getContents(), 'html', $data->getStatusCode()); + + foreach ($data->getHeaders() as $header => $values) { + $response->header([$header => implode(", ", $values)]); + } } elseif (!is_null($data)) { // 默认自动识别响应输出类型 $type = $this->request->isJson() ? 'json' : 'html'; diff --git a/vendor/topthink/framework/src/think/route/Url.php b/vendor/topthink/framework/src/think/route/Url.php index 8dd410c..b3f8b9f 100644 --- a/vendor/topthink/framework/src/think/route/Url.php +++ b/vendor/topthink/framework/src/think/route/Url.php @@ -320,7 +320,7 @@ class Url } if (empty($pattern)) { - return [rtrim($url, '?/-'), $domain, $suffix]; + return [rtrim($url, '?-'), $domain, $suffix]; } $type = $this->route->config('url_common_param'); @@ -331,11 +331,11 @@ class Url $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? (string) $vars[$key] : urlencode((string) $vars[$key]), $url); $keys[] = $key; $url = str_replace(['/?', '-?'], ['/', '-'], $url); - $result = [rtrim($url, '?/-'), $domain, $suffix]; + $result = [rtrim($url, '?-'), $domain, $suffix]; } elseif (2 == $val) { $url = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url); $url = str_replace(['/?', '-?'], ['/', '-'], $url); - $result = [rtrim($url, '?/-'), $domain, $suffix]; + $result = [rtrim($url, '?-'), $domain, $suffix]; } else { $result = null; $keys = []; diff --git a/vendor/topthink/framework/src/think/route/dispatch/Controller.php b/vendor/topthink/framework/src/think/route/dispatch/Controller.php index 611101b..f18512c 100644 --- a/vendor/topthink/framework/src/think/route/dispatch/Controller.php +++ b/vendor/topthink/framework/src/think/route/dispatch/Controller.php @@ -113,6 +113,13 @@ class Controller extends Dispatch }); } + protected function parseActions($actions) + { + return array_map(function ($item) { + return strtolower($item); + }, is_string($actions) ? explode(",", $actions) : $actions); + } + /** * 使用反射机制注册控制器中间件 * @access public @@ -128,30 +135,34 @@ class Controller extends Dispatch $reflectionProperty->setAccessible(true); $middlewares = $reflectionProperty->getValue($controller); + $action = $this->request->action(true); foreach ($middlewares as $key => $val) { if (!is_int($key)) { - if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) { - return strtolower($item); - }, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) { - continue; - } elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) { - return strtolower($item); - }, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) { - continue; - } else { - $val = $key; + $middleware = $key; + $options = $val; + } elseif (isset($val['middleware'])) { + $middleware = $val['middleware']; + $options = $val['options'] ?? []; + } else { + $middleware = $val; + $options = []; + } + + if (isset($options['only']) && !in_array($action, $this->parseActions($options['only']))) { + continue; + } elseif (isset($options['except']) && in_array($action, $this->parseActions($options['except']))) { + continue; + } + + if (is_string($middleware) && strpos($middleware, ':')) { + $middleware = explode(':', $middleware); + if (count($middleware) > 1) { + $middleware = [$middleware[0], array_slice($middleware, 1)]; } } - if (is_string($val) && strpos($val, ':')) { - $val = explode(':', $val); - if (count($val) > 1) { - $val = [$val[0], array_slice($val, 1)]; - } - } - - $this->app->middleware->controller($val); + $this->app->middleware->controller($middleware); } } } diff --git a/vendor/topthink/framework/tests/DispatchTest.php b/vendor/topthink/framework/tests/DispatchTest.php new file mode 100644 index 0000000..2b9e413 --- /dev/null +++ b/vendor/topthink/framework/tests/DispatchTest.php @@ -0,0 +1,32 @@ + ['tp', 'thinkphp'], 'psr' => 'psr-7'], '123'); + } + }; + + $response = $dispatch->run(); + + $this->assertInstanceOf(\think\Response::class, $response); + $this->assertEquals('123', $response->getContent()); + $this->assertEquals('tp, thinkphp', $response->getHeader('framework')); + $this->assertEquals('psr-7', $response->getHeader('psr')); + } +} diff --git a/vendor/topthink/framework/tests/EnvTest.php b/vendor/topthink/framework/tests/EnvTest.php index cf2e65f..9b3b615 100644 --- a/vendor/topthink/framework/tests/EnvTest.php +++ b/vendor/topthink/framework/tests/EnvTest.php @@ -21,8 +21,6 @@ class EnvTest extends TestCase $this->assertEquals('value1', $env->get('key1')); $this->assertEquals('value2', $env->get('key2')); - - $this->assertSame(['KEY1' => 'value1', 'KEY2' => 'value2'], $env->get()); } public function testServerEnv() diff --git a/vendor/topthink/framework/tests/RouteTest.php b/vendor/topthink/framework/tests/RouteTest.php index e992d0f..6a7f8ee 100644 --- a/vendor/topthink/framework/tests/RouteTest.php +++ b/vendor/topthink/framework/tests/RouteTest.php @@ -194,6 +194,10 @@ class RouteTest extends TestCase $this->createMiddleware()->mockery_getName() . ":params1:params2", $this->createMiddleware(0)->mockery_getName() => ['except' => 'bar'], $this->createMiddleware()->mockery_getName() => ['only' => 'bar'], + [ + 'middleware' => [$this->createMiddleware()->mockery_getName(), [new \stdClass()]], + 'options' => ['only' => 'bar'], + ], ]; $this->app->shouldReceive('parseClass')->with('controller', 'Foo')->andReturn($controller->mockery_getName()); @@ -211,7 +215,8 @@ class RouteTest extends TestCase $controller = m::mock(FooClass::class); $controller->shouldReceive('index')->andReturn('bar'); - $this->app->shouldReceive('parseClass')->once()->with('controller', 'Foo')->andReturn($controller->mockery_getName()); + $this->app->shouldReceive('parseClass')->once()->with('controller', 'Foo') + ->andReturn($controller->mockery_getName()); $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller); $request = $this->makeRequest('foo'); diff --git a/vendor/topthink/think-helper/.github/workflows/ci.yml b/vendor/topthink/think-helper/.github/workflows/ci.yml new file mode 100644 index 0000000..c63b5d4 --- /dev/null +++ b/vendor/topthink/think-helper/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + +jobs: + phpcs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup PHP environment + uses: shivammathur/setup-php@v2 + - name: Install dependencies + run: composer install + - name: PHPCSFixer check + run: composer check-style + phpunit: + strategy: + matrix: + php_version: [7.3, 7.4, 8.0] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup PHP environment + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php_version }} + coverage: xdebug + - name: Install dependencies + run: composer install + - name: PHPUnit check + run: ./vendor/bin/phpunit --coverage-text diff --git a/vendor/topthink/think-helper/.github/workflows/php.yml b/vendor/topthink/think-helper/.github/workflows/php.yml new file mode 100644 index 0000000..01d5b63 --- /dev/null +++ b/vendor/topthink/think-helper/.github/workflows/php.yml @@ -0,0 +1,36 @@ +name: PHP Composer + +on: + push: + branches: [ 3.0 ] + pull_request: + branches: [ 3.0 ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + + - name: Run test suite + run: composer test diff --git a/vendor/topthink/think-helper/.gitignore b/vendor/topthink/think-helper/.gitignore index d851bdb..5ea11e9 100644 --- a/vendor/topthink/think-helper/.gitignore +++ b/vendor/topthink/think-helper/.gitignore @@ -1,3 +1,4 @@ /vendor/ /.idea/ -composer.lock \ No newline at end of file +composer.lock +.phpunit.result.cache \ No newline at end of file diff --git a/vendor/topthink/think-helper/README.md b/vendor/topthink/think-helper/README.md index 7baf8f7..f8f226d 100644 --- a/vendor/topthink/think-helper/README.md +++ b/vendor/topthink/think-helper/README.md @@ -2,6 +2,8 @@ 基于PHP7.1+ +[![PHP Composer](https://github.com/larvatecn/think-helper/actions/workflows/php.yml/badge.svg)](https://github.com/larvatecn/think-helper/actions/workflows/php.yml) + > 以下类库都在`\\think\\helper`命名空间下 ## Str diff --git a/vendor/topthink/think-helper/composer.json b/vendor/topthink/think-helper/composer.json index b68c43b..0892fa6 100644 --- a/vendor/topthink/think-helper/composer.json +++ b/vendor/topthink/think-helper/composer.json @@ -10,7 +10,10 @@ ], "require": { "php": ">=7.1.0" - }, + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, "autoload": { "psr-4": { "think\\": "src" @@ -18,5 +21,16 @@ "files": [ "src/helper.php" ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" + } + }, + "scripts": { + "test": "./vendor/bin/phpunit --colors" + }, + "scripts-descriptions": { + "test": "Run all tests." } } diff --git a/vendor/topthink/think-helper/phpunit.xml.dist b/vendor/topthink/think-helper/phpunit.xml.dist new file mode 100644 index 0000000..c083f14 --- /dev/null +++ b/vendor/topthink/think-helper/phpunit.xml.dist @@ -0,0 +1,17 @@ + + + + + ./tests/ + + + + + ./src + + + diff --git a/vendor/topthink/think-helper/src/Collection.php b/vendor/topthink/think-helper/src/Collection.php index fa408c2..5b19ffc 100644 --- a/vendor/topthink/think-helper/src/Collection.php +++ b/vendor/topthink/think-helper/src/Collection.php @@ -20,6 +20,7 @@ use JsonSerializable; use think\contract\Arrayable; use think\contract\Jsonable; use think\helper\Arr; +use Traversable; /** * 数据集管理类 @@ -142,7 +143,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria public function intersect($items, string $indexKey = null) { if ($this->isEmpty() || is_scalar($this->items[0])) { - return new static(array_diff($this->items, $this->convertToArray($items))); + return new static(array_intersect($this->items, $this->convertToArray($items))); } $intersect = []; @@ -579,16 +580,19 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } // ArrayAccess - public function offsetExists($offset) + #[\ReturnTypeWillChange] + public function offsetExists($offset) : bool { return array_key_exists($offset, $this->items); } + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->items[$offset]; } + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { if (is_null($offset)) { @@ -598,24 +602,27 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria } } + #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->items[$offset]); } //Countable - public function count() + public function count(): int { return count($this->items); } //IteratorAggregate - public function getIterator() + #[\ReturnTypeWillChange] + public function getIterator(): Traversable { return new ArrayIterator($this->items); } //JsonSerializable + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); @@ -627,7 +634,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * @param integer $options json参数 * @return string */ - public function toJson(int $options = JSON_UNESCAPED_UNICODE) : string + public function toJson(int $options = JSON_UNESCAPED_UNICODE): string { return json_encode($this->toArray(), $options); } diff --git a/vendor/topthink/think-helper/src/helper/Str.php b/vendor/topthink/think-helper/src/helper/Str.php index 7391fbd..664dba2 100644 --- a/vendor/topthink/think-helper/src/helper/Str.php +++ b/vendor/topthink/think-helper/src/helper/Str.php @@ -179,7 +179,7 @@ class Str } if (!ctype_lower($value)) { - $value = preg_replace('/\s+/u', '', $value); + $value = preg_replace('/\s+/u', '', ucwords($value)); $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); } diff --git a/vendor/topthink/think-helper/tests/ArrTest.php b/vendor/topthink/think-helper/tests/ArrTest.php new file mode 100644 index 0000000..a8effe7 --- /dev/null +++ b/vendor/topthink/think-helper/tests/ArrTest.php @@ -0,0 +1,342 @@ + 'ThinkPHP'], 'price', 100); + $this->assertSame(['name' => 'ThinkPHP', 'price' => 100], $array); + } + + public function testCrossJoin() + { + // Single dimension + $this->assertSame( + [[1, 'a'], [1, 'b'], [1, 'c']], + Arr::crossJoin([1], ['a', 'b', 'c']) + ); + // Square matrix + $this->assertSame( + [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']], + Arr::crossJoin([1, 2], ['a', 'b']) + ); + // Rectangular matrix + $this->assertSame( + [[1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, 'b'], [2, 'c']], + Arr::crossJoin([1, 2], ['a', 'b', 'c']) + ); + // 3D matrix + $this->assertSame( + [ + [1, 'a', 'I'], [1, 'a', 'II'], [1, 'a', 'III'], + [1, 'b', 'I'], [1, 'b', 'II'], [1, 'b', 'III'], + [2, 'a', 'I'], [2, 'a', 'II'], [2, 'a', 'III'], + [2, 'b', 'I'], [2, 'b', 'II'], [2, 'b', 'III'], + ], + Arr::crossJoin([1, 2], ['a', 'b'], ['I', 'II', 'III']) + ); + // With 1 empty dimension + $this->assertSame([], Arr::crossJoin([], ['a', 'b'], ['I', 'II', 'III'])); + $this->assertSame([], Arr::crossJoin([1, 2], [], ['I', 'II', 'III'])); + $this->assertSame([], Arr::crossJoin([1, 2], ['a', 'b'], [])); + // With empty arrays + $this->assertSame([], Arr::crossJoin([], [], [])); + $this->assertSame([], Arr::crossJoin([], [])); + $this->assertSame([], Arr::crossJoin([])); + // Not really a proper usage, still, test for preserving BC + $this->assertSame([[]], Arr::crossJoin()); + } + + public function testDivide() + { + list($keys, $values) = Arr::divide(['name' => 'ThinkPHP']); + $this->assertSame(['name'], $keys); + $this->assertSame(['ThinkPHP'], $values); + } + + public function testDot() + { + $array = Arr::dot(['foo' => ['bar' => 'baz']]); + $this->assertSame(['foo.bar' => 'baz'], $array); + $array = Arr::dot([]); + $this->assertSame([], $array); + $array = Arr::dot(['foo' => []]); + $this->assertSame(['foo' => []], $array); + $array = Arr::dot(['foo' => ['bar' => []]]); + $this->assertSame(['foo.bar' => []], $array); + } + + public function testExcept() + { + $array = ['name' => 'ThinkPHP', 'price' => 100]; + $array = Arr::except($array, ['price']); + $this->assertSame(['name' => 'ThinkPHP'], $array); + } + + public function testExists() + { + $this->assertTrue(Arr::exists([1], 0)); + $this->assertTrue(Arr::exists([null], 0)); + $this->assertTrue(Arr::exists(['a' => 1], 'a')); + $this->assertTrue(Arr::exists(['a' => null], 'a')); + $this->assertFalse(Arr::exists([1], 1)); + $this->assertFalse(Arr::exists([null], 1)); + $this->assertFalse(Arr::exists(['a' => 1], 0)); + } + + public function testFirst() + { + $array = [100, 200, 300]; + $value = Arr::first($array, function ($value) { + return $value >= 150; + }); + $this->assertSame(200, $value); + $this->assertSame(100, Arr::first($array)); + + $this->assertSame('default', Arr::first([], null, 'default')); + + $this->assertSame('default', Arr::first([], function () { + return false; + }, 'default')); + } + + public function testLast() + { + $array = [100, 200, 300]; + $last = Arr::last($array, function ($value) { + return $value < 250; + }); + $this->assertSame(200, $last); + $last = Arr::last($array, function ($value, $key) { + return $key < 2; + }); + $this->assertSame(200, $last); + $this->assertSame(300, Arr::last($array)); + } + + public function testFlatten() + { + // Flat arrays are unaffected + $array = ['#foo', '#bar', '#baz']; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten(['#foo', '#bar', '#baz'])); + // Nested arrays are flattened with existing flat items + $array = [['#foo', '#bar'], '#baz']; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Flattened array includes "null" items + $array = [['#foo', null], '#baz', null]; + $this->assertSame(['#foo', null, '#baz', null], Arr::flatten($array)); + // Sets of nested arrays are flattened + $array = [['#foo', '#bar'], ['#baz']]; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Deeply nested arrays are flattened + $array = [['#foo', ['#bar']], ['#baz']]; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Nested arrays are flattened alongside arrays + $array = [new Collection(['#foo', '#bar']), ['#baz']]; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Nested arrays containing plain arrays are flattened + $array = [new Collection(['#foo', ['#bar']]), ['#baz']]; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Nested arrays containing arrays are flattened + $array = [['#foo', new Collection(['#bar'])], ['#baz']]; + $this->assertSame(['#foo', '#bar', '#baz'], Arr::flatten($array)); + // Nested arrays containing arrays containing arrays are flattened + $array = [['#foo', new Collection(['#bar', ['#zap']])], ['#baz']]; + $this->assertSame(['#foo', '#bar', '#zap', '#baz'], Arr::flatten($array)); + } + + public function testFlattenWithDepth() + { + // No depth flattens recursively + $array = [['#foo', ['#bar', ['#baz']]], '#zap']; + $this->assertSame(['#foo', '#bar', '#baz', '#zap'], Arr::flatten($array)); + // Specifying a depth only flattens to that depth + $array = [['#foo', ['#bar', ['#baz']]], '#zap']; + $this->assertSame(['#foo', ['#bar', ['#baz']], '#zap'], Arr::flatten($array, 1)); + $array = [['#foo', ['#bar', ['#baz']]], '#zap']; + $this->assertSame(['#foo', '#bar', ['#baz'], '#zap'], Arr::flatten($array, 2)); + } + + public function testGet() + { + $array = ['products.item' => ['price' => 100]]; + $this->assertSame(['price' => 100], Arr::get($array, 'products.item')); + $array = ['products' => ['item' => ['price' => 100]]]; + $value = Arr::get($array, 'products.item'); + $this->assertSame(['price' => 100], $value); + // Test null array values + $array = ['foo' => null, 'bar' => ['baz' => null]]; + $this->assertNull(Arr::get($array, 'foo', 'default')); + $this->assertNull(Arr::get($array, 'bar.baz', 'default')); + // Test null key returns the whole array + $array = ['foo', 'bar']; + $this->assertSame($array, Arr::get($array, null)); + // Test $array is empty and key is null + $this->assertSame([], Arr::get([], null)); + $this->assertSame([], Arr::get([], null, 'default')); + } + + public function testHas() + { + $array = ['products.item' => ['price' => 100]]; + $this->assertTrue(Arr::has($array, 'products.item')); + $array = ['products' => ['item' => ['price' => 100]]]; + $this->assertTrue(Arr::has($array, 'products.item')); + $this->assertTrue(Arr::has($array, 'products.item.price')); + $this->assertFalse(Arr::has($array, 'products.foo')); + $this->assertFalse(Arr::has($array, 'products.item.foo')); + $array = ['foo' => null, 'bar' => ['baz' => null]]; + $this->assertTrue(Arr::has($array, 'foo')); + $this->assertTrue(Arr::has($array, 'bar.baz')); + $array = ['foo', 'bar']; + $this->assertFalse(Arr::has($array, null)); + $this->assertFalse(Arr::has([], null)); + $array = ['products' => ['item' => ['price' => 100]]]; + $this->assertTrue(Arr::has($array, ['products.item'])); + $this->assertTrue(Arr::has($array, ['products.item', 'products.item.price'])); + $this->assertTrue(Arr::has($array, ['products', 'products'])); + $this->assertFalse(Arr::has($array, ['foo'])); + $this->assertFalse(Arr::has($array, [])); + $this->assertFalse(Arr::has($array, ['products.item', 'products.price'])); + $this->assertFalse(Arr::has([], [null])); + } + + public function testIsAssoc() + { + $this->assertTrue(Arr::isAssoc(['a' => 'a', 0 => 'b'])); + $this->assertTrue(Arr::isAssoc([1 => 'a', 0 => 'b'])); + $this->assertTrue(Arr::isAssoc([1 => 'a', 2 => 'b'])); + $this->assertFalse(Arr::isAssoc([0 => 'a', 1 => 'b'])); + $this->assertFalse(Arr::isAssoc(['a', 'b'])); + } + + public function testOnly() + { + $array = ['name' => 'ThinkPHP', 'price' => 100, 'orders' => 10]; + $array = Arr::only($array, ['name', 'price']); + $this->assertSame(['name' => 'ThinkPHP', 'price' => 100], $array); + } + + public function testPrepend() + { + $array = Arr::prepend(['one', 'two', 'three', 'four'], 'zero'); + $this->assertSame(['zero', 'one', 'two', 'three', 'four'], $array); + $array = Arr::prepend(['one' => 1, 'two' => 2], 0, 'zero'); + $this->assertSame(['zero' => 0, 'one' => 1, 'two' => 2], $array); + } + + public function testPull() + { + $array = ['name' => 'ThinkPHP', 'price' => 100]; + $name = Arr::pull($array, 'name'); + $this->assertSame('ThinkPHP', $name); + $this->assertSame(['price' => 100], $array); + // Only works on first level keys + $array = ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane']; + $name = Arr::pull($array, 'i@example.com'); + $this->assertSame('Joe', $name); + $this->assertSame(['jack@localhost' => 'Jane'], $array); + // Does not work for nested keys + $array = ['emails' => ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane']]; + $name = Arr::pull($array, 'emails.i@example.com'); + $this->assertNull($name); + $this->assertSame(['emails' => ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane']], $array); + } + + public function testRandom() + { + $randomValue = Arr::random(['foo', 'bar', 'baz']); + $this->assertContains($randomValue, ['foo', 'bar', 'baz']); + $randomValues = Arr::random(['foo', 'bar', 'baz'], 1); + $this->assertIsArray($randomValues); + $this->assertCount(1, $randomValues); + $this->assertContains($randomValues[0], ['foo', 'bar', 'baz']); + $randomValues = Arr::random(['foo', 'bar', 'baz'], 2); + $this->assertIsArray($randomValues); + $this->assertCount(2, $randomValues); + $this->assertContains($randomValues[0], ['foo', 'bar', 'baz']); + $this->assertContains($randomValues[1], ['foo', 'bar', 'baz']); + } + + public function testSet() + { + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::set($array, 'products.item.price', 200); + Arr::set($array, 'goods.item.price', 200); + $this->assertSame(['products' => ['item' => ['price' => 200]], 'goods' => ['item' => ['price' => 200]]], $array); + } + + public function testWhere() + { + $array = [100, '200', 300, '400', 500]; + $array = Arr::where($array, function ($value, $key) { + return is_string($value); + }); + $this->assertSame([1 => '200', 3 => '400'], $array); + } + + public function testWhereKey() + { + $array = ['10' => 1, 'foo' => 3, 20 => 2]; + $array = Arr::where($array, function ($value, $key) { + return is_numeric($key); + }); + $this->assertSame(['10' => 1, 20 => 2], $array); + } + + public function testForget() + { + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::forget($array, null); + $this->assertSame(['products' => ['item' => ['price' => 100]]], $array); + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::forget($array, []); + $this->assertSame(['products' => ['item' => ['price' => 100]]], $array); + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::forget($array, 'products.item'); + $this->assertSame(['products' => []], $array); + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::forget($array, 'products.item.price'); + $this->assertSame(['products' => ['item' => []]], $array); + $array = ['products' => ['item' => ['price' => 100]]]; + Arr::forget($array, 'products.final.price'); + $this->assertSame(['products' => ['item' => ['price' => 100]]], $array); + $array = ['shop' => ['cart' => [150 => 0]]]; + Arr::forget($array, 'shop.final.cart'); + $this->assertSame(['shop' => ['cart' => [150 => 0]]], $array); + $array = ['products' => ['item' => ['price' => ['original' => 50, 'taxes' => 60]]]]; + Arr::forget($array, 'products.item.price.taxes'); + $this->assertSame(['products' => ['item' => ['price' => ['original' => 50]]]], $array); + $array = ['products' => ['item' => ['price' => ['original' => 50, 'taxes' => 60]]]]; + Arr::forget($array, 'products.item.final.taxes'); + $this->assertSame(['products' => ['item' => ['price' => ['original' => 50, 'taxes' => 60]]]], $array); + $array = ['products' => ['item' => ['price' => 50], null => 'something']]; + Arr::forget($array, ['products.amount.all', 'products.item.price']); + $this->assertSame(['products' => ['item' => [], null => 'something']], $array); + // Only works on first level keys + $array = ['i@example.com' => 'Joe', 'i@thinkphp.com' => 'Jane']; + Arr::forget($array, 'i@example.com'); + $this->assertSame(['i@thinkphp.com' => 'Jane'], $array); + // Does not work for nested keys + $array = ['emails' => ['i@example.com' => ['name' => 'Joe'], 'jack@localhost' => ['name' => 'Jane']]]; + Arr::forget($array, ['emails.i@example.com', 'emails.jack@localhost']); + $this->assertSame(['emails' => ['i@example.com' => ['name' => 'Joe']]], $array); + } + + public function testWrap() + { + $string = 'a'; + $array = ['a']; + $object = new stdClass(); + $object->value = 'a'; + $this->assertSame(['a'], Arr::wrap($string)); + $this->assertSame($array, Arr::wrap($array)); + $this->assertSame([$object], Arr::wrap($object)); + } +} diff --git a/vendor/topthink/think-helper/tests/CollectionTest.php b/vendor/topthink/think-helper/tests/CollectionTest.php new file mode 100644 index 0000000..b69c175 --- /dev/null +++ b/vendor/topthink/think-helper/tests/CollectionTest.php @@ -0,0 +1,70 @@ + 'Hello']); + $this->assertSame(['name' => 'Hello', 'id' => 1], $c->merge(['id' => 1])->all()); + } + + public function testFirst() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertSame('Hello', $c->first()); + } + + public function testLast() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertSame(25, $c->last()); + } + + public function testToArray() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertSame(['name' => 'Hello', 'age' => 25], $c->toArray()); + } + + public function testToJson() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertSame(json_encode(['name' => 'Hello', 'age' => 25]), $c->toJson()); + $this->assertSame(json_encode(['name' => 'Hello', 'age' => 25]), (string) $c); + $this->assertSame(json_encode(['name' => 'Hello', 'age' => 25]), json_encode($c)); + } + + public function testSerialize() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $sc = serialize($c); + $c = unserialize($sc); + + $this->assertSame(['name' => 'Hello', 'age' => 25], $c->all()); + } + + public function testGetIterator() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertInstanceOf(\ArrayIterator::class, $c->getIterator()); + + $this->assertSame(['name' => 'Hello', 'age' => 25], $c->getIterator()->getArrayCopy()); + } + + public function testCount() + { + $c = new Collection(['name' => 'Hello', 'age' => 25]); + + $this->assertCount(2, $c); + } +} diff --git a/vendor/topthink/think-helper/tests/StrTest.php b/vendor/topthink/think-helper/tests/StrTest.php new file mode 100644 index 0000000..813ad4c --- /dev/null +++ b/vendor/topthink/think-helper/tests/StrTest.php @@ -0,0 +1,59 @@ +assertSame('fooBar', Str::camel('FooBar')); + $this->assertSame('fooBar', Str::camel('FooBar')); + $this->assertSame('fooBar', Str::camel('foo_bar')); + $this->assertSame('fooBar', Str::camel('_foo_bar')); + $this->assertSame('fooBar', Str::camel('_foo_bar_')); + } + + public function testStudly() + { + $this->assertSame('FooBar', Str::studly('fooBar')); + $this->assertSame('FooBar', Str::studly('_foo_bar')); + $this->assertSame('FooBar', Str::studly('_foo_bar_')); + $this->assertSame('FooBar', Str::studly('_foo_bar_')); + } + + public function testSnake() + { + $this->assertSame('think_p_h_p_framework', Str::snake('ThinkPHPFramework')); + $this->assertSame('think_php_framework', Str::snake('ThinkPhpFramework')); + $this->assertSame('think php framework', Str::snake('ThinkPhpFramework', ' ')); + $this->assertSame('think_php_framework', Str::snake('Think Php Framework')); + $this->assertSame('think_php_framework', Str::snake('Think Php Framework ')); + // ensure cache keys don't overlap + $this->assertSame('think__php__framework', Str::snake('ThinkPhpFramework', '__')); + $this->assertSame('think_php_framework_', Str::snake('ThinkPhpFramework_', '_')); + $this->assertSame('think_php_framework', Str::snake('think php Framework')); + $this->assertSame('think_php_frame_work', Str::snake('think php FrameWork')); + // prevent breaking changes + $this->assertSame('foo-bar', Str::snake('foo-bar')); + $this->assertSame('foo-_bar', Str::snake('Foo-Bar')); + $this->assertSame('foo__bar', Str::snake('Foo_Bar')); + $this->assertSame('żółtałódka', Str::snake('ŻółtaŁódka')); + } + + public function testTitle() + { + $this->assertSame('Welcome Back', Str::title('welcome back')); + } + + public function testRandom() + { + $this->assertIsString(Str::random(10)); + } + + public function testUpper() + { + $this->assertSame('USERNAME', Str::upper('username')); + $this->assertSame('USERNAME', Str::upper('userNaMe')); + } +} diff --git a/vendor/topthink/think-helper/tests/TestCase.php b/vendor/topthink/think-helper/tests/TestCase.php new file mode 100644 index 0000000..87f6cb3 --- /dev/null +++ b/vendor/topthink/think-helper/tests/TestCase.php @@ -0,0 +1,13 @@ + + */ +class TestCase extends BaseTestCase +{ +} diff --git a/vendor/topthink/think-orm/src/Model.php b/vendor/topthink/think-orm/src/Model.php index 00016d0..e1de7f0 100644 --- a/vendor/topthink/think-orm/src/Model.php +++ b/vendor/topthink/think-orm/src/Model.php @@ -243,6 +243,29 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab } } + $this->filter(function ($result, $options) { + // 关联查询 + if (!empty($options['relation'])) { + $result->relationQuery($options['relation'], $options['with_relation_attr']); + } + + // 预载入查询 + if (empty($options['is_resultSet']) && !empty($options['with'])) { + $result->eagerlyResult($result, $options['with'], $options['with_relation_attr'], false, $options['with_cache'] ?? false); + } + + // JOIN预载入查询 + if (empty($options['is_resultSet']) && !empty($options['with_join'])) { + $result->eagerlyResult($result, $options['with_join'], $options['with_relation_attr'], true, $options['with_cache'] ?? false); + } + + // 关联统计 + if (!empty($options['with_count'])) { + foreach ($options['with_count'] as $val) { + $result->relationCount($this, (array) $val[0], $val[1], $val[2], false); + } + } + }); // 执行初始化操作 $this->initialize(); } @@ -260,11 +283,12 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab /** * 创建新的模型实例 * @access public - * @param array $data 数据 - * @param mixed $where 更新条件 + * @param array $data 数据 + * @param mixed $where 更新条件 + * @param array $options 参数 * @return Model */ - public function newInstance(array $data = [], $where = null): Model + public function newInstance(array $data = [], $where = null, array $options = []): Model { $model = new static($data); @@ -284,6 +308,11 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab $model->setUpdateWhere($where); + // 查询数据处理 + foreach ($this->filter as $filter) { + call_user_func_array($filter, [$model, $options]); + } + $model->trigger('AfterRead'); return $model; @@ -970,21 +999,25 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab } // ArrayAccess + #[\ReturnTypeWillChange] public function offsetSet($name, $value) { $this->setAttr($name, $value); } + #[\ReturnTypeWillChange] public function offsetExists($name): bool { return $this->__isset($name); } + #[\ReturnTypeWillChange] public function offsetUnset($name) { $this->__unset($name); } + #[\ReturnTypeWillChange] public function offsetGet($name) { return $this->getAttr($name); @@ -1037,10 +1070,6 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab return call_user_func_array(static::$macro[static::class][$method]->bindTo($this, static::class), $args); } - if ('withattr' == strtolower($method)) { - return call_user_func_array([$this, 'withAttribute'], $args); - } - return call_user_func_array([$this->db(), $method], $args); } diff --git a/vendor/topthink/think-orm/src/Paginator.php b/vendor/topthink/think-orm/src/Paginator.php index d8d43d7..2f755ef 100644 --- a/vendor/topthink/think-orm/src/Paginator.php +++ b/vendor/topthink/think-orm/src/Paginator.php @@ -410,7 +410,8 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @return Traversable An instance of an object implementing Iterator or * Traversable */ - public function getIterator() + #[\ReturnTypeWillChange] + public function getIterator(): Traversable { return new ArrayIterator($this->items->all()); } @@ -421,7 +422,8 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @param mixed $offset * @return bool */ - public function offsetExists($offset) + #[\ReturnTypeWillChange] + public function offsetExists($offset): bool { return $this->items->offsetExists($offset); } @@ -432,6 +434,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @param mixed $offset * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->items->offsetGet($offset); @@ -443,6 +446,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @param mixed $offset * @param mixed $value */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->items->offsetSet($offset, $value); @@ -455,6 +459,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @return void * @since 5.0.0 */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { $this->items->offsetUnset($offset); @@ -498,6 +503,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * Specify data which should be serialized to JSON */ + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); diff --git a/vendor/topthink/think-orm/src/db/BaseQuery.php b/vendor/topthink/think-orm/src/db/BaseQuery.php index a0acdbe..63b8d22 100644 --- a/vendor/topthink/think-orm/src/db/BaseQuery.php +++ b/vendor/topthink/think-orm/src/db/BaseQuery.php @@ -106,6 +106,12 @@ abstract class BaseQuery $name = Str::snake(substr($method, 5)); array_unshift($args, $name); return call_user_func_array([$this, 'where'], $args); + } elseif ($this->model && in_array($method, ['hidden', 'visible', 'append'])) { + // 调用模型类方法 + $this->model->filter(function ($model, $options) use ($method, $args) { + call_user_func_array([$model, $method], $args); + }); + return $this; } elseif ($this->model && method_exists($this->model, 'scope' . $method)) { // 动态调用命名范围 $method = 'scope' . $method; @@ -137,7 +143,7 @@ abstract class BaseQuery $query->name($this->name); } - if (isset($this->options['json'])) { + if (!empty($this->options['json'])) { $query->json($this->options['json'], $this->options['json_assoc']); } @@ -278,7 +284,9 @@ abstract class BaseQuery public function column($field, string $key = ''): array { $result = $this->connection->column($this, $field, $key); - $this->resultSet($result, false); + if (count($result) != count($result, 1)) { + $this->resultSet($result, false); + } return $result; } @@ -867,6 +875,7 @@ abstract class BaseQuery { $this->options['json'] = $json; $this->options['json_assoc'] = $assoc; + return $this; } @@ -1124,7 +1133,7 @@ abstract class BaseQuery * 查找单条记录 * @access public * @param mixed $data 查询数据 - * @return array|Model|null|static + * @return array|Model|null|static|mixed * @throws Exception * @throws ModelNotFoundException * @throws DataNotFoundException @@ -1178,7 +1187,7 @@ abstract class BaseQuery $this->parseView($options); } - foreach (['data', 'order', 'join', 'union'] as $name) { + foreach (['data', 'order', 'join', 'union', 'filter', 'json'] as $name) { if (!isset($options[$name])) { $options[$name] = []; } diff --git a/vendor/topthink/think-orm/src/db/PDOConnection.php b/vendor/topthink/think-orm/src/db/PDOConnection.php index 1a3d4a2..40ac99e 100644 --- a/vendor/topthink/think-orm/src/db/PDOConnection.php +++ b/vendor/topthink/think-orm/src/db/PDOConnection.php @@ -279,7 +279,7 @@ abstract class PDOConnection extends Connection */ protected function getFieldType(string $type): string { - if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) { + if (0 === stripos($type, 'set') || 0 === stripos($type, 'enum')) { $result = 'string'; } elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) { $result = 'float'; @@ -287,11 +287,11 @@ abstract class PDOConnection extends Connection $result = 'int'; } elseif (preg_match('/bool/is', $type)) { $result = 'bool'; - } elseif (0 === strpos($type, 'timestamp')) { + } elseif (0 === stripos($type, 'timestamp')) { $result = 'timestamp'; - } elseif (0 === strpos($type, 'datetime')) { + } elseif (0 === stripos($type, 'datetime')) { $result = 'datetime'; - } elseif (0 === strpos($type, 'date')) { + } elseif (0 === stripos($type, 'date')) { $result = 'date'; } else { $result = 'string'; @@ -1273,7 +1273,7 @@ abstract class PDOConnection extends Connection $type = is_array($val) ? $val[1] : PDO::PARAM_STR; if (self::PARAM_FLOAT == $type || PDO::PARAM_STR == $type) { - $value = '\'' . addslashes($value) . '\''; + $value = '\'' . addcslashes($value, "'") . '\''; } elseif (PDO::PARAM_INT == $type && '' === $value) { $value = '0'; } diff --git a/vendor/topthink/think-orm/src/db/builder/Sqlite.php b/vendor/topthink/think-orm/src/db/builder/Sqlite.php index 40cab7f..78a307d 100644 --- a/vendor/topthink/think-orm/src/db/builder/Sqlite.php +++ b/vendor/topthink/think-orm/src/db/builder/Sqlite.php @@ -94,4 +94,16 @@ class Sqlite extends Builder return $key; } + + /** + * 设置锁机制 + * @access protected + * @param Query $query 查询对象 + * @param bool|string $lock + * @return string + */ + protected function parseLock(Query $query, $lock = false): string + { + return ''; + } } diff --git a/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php b/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php index ffb72de..3213f75 100644 --- a/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php +++ b/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php @@ -51,42 +51,6 @@ trait ModelRelationQuery return $this->model; } - /** - * 设置需要隐藏的输出属性 - * @access public - * @param array $hidden 需要隐藏的字段名 - * @return $this - */ - public function hidden(array $hidden) - { - $this->options['hidden'] = $hidden; - return $this; - } - - /** - * 设置需要输出的属性 - * @access public - * @param array $visible 需要输出的属性 - * @return $this - */ - public function visible(array $visible) - { - $this->options['visible'] = $visible; - return $this; - } - - /** - * 设置需要追加输出的属性 - * @access public - * @param array $append 需要追加的属性 - * @return $this - */ - public function append(array $append) - { - $this->options['append'] = $append; - return $this; - } - /** * 添加查询范围 * @access public @@ -187,7 +151,9 @@ trait ModelRelationQuery $this->options['with_attr'][$name] = $callback; } - return $this; + return $this->filter(function ($result) { + return $this->getResultAttr($result, $this->options['with_attr']); + }, 'with_attr'); } /** @@ -418,23 +384,10 @@ trait ModelRelationQuery return $this->model->toCollection(); } - // 检查动态获取器 - if (!empty($this->options['with_attr'])) { - foreach ($this->options['with_attr'] as $name => $val) { - if (strpos($name, '.')) { - [$relation, $field] = explode('.', $name); - - $withRelationAttr[$relation][$field] = $val; - unset($this->options['with_attr'][$name]); - } - } - } - - $withRelationAttr = $withRelationAttr ?? []; - + $withRelationAttr = $this->getWithRelationAttr(); foreach ($resultSet as $key => &$result) { // 数据转换为模型对象 - $this->resultToModel($result, $this->options, true, $withRelationAttr); + $this->resultToModel($result, $this->options, true); } if (!empty($this->options['with'])) { @@ -451,74 +404,75 @@ trait ModelRelationQuery return $this->model->toCollection($resultSet); } + /** + * 检查动态获取器 + * @access protected + * @return array + */ + protected function getWithRelationAttr(): array + { + if (isset($this->options['with_relation_attr'])) { + return $this->options['with_relation_attr']; + } + + $withRelationAttr = []; + if (!empty($this->options['with_attr'])) { + foreach ($this->options['with_attr'] as $name => $val) { + if (strpos($name, '.')) { + [$relation, $field] = explode('.', $name); + + $withRelationAttr[$relation][$field] = $val; + unset($this->options['with_attr'][$name]); + } + } + } + + $this->options['with_relation_attr'] = $withRelationAttr; + return $withRelationAttr; + } + /** * 查询数据转换为模型对象 * @access protected * @param array $result 查询数据 * @param array $options 查询参数 * @param bool $resultSet 是否为数据集查询 - * @param array $withRelationAttr 关联字段获取器 * @return void */ - protected function resultToModel(array &$result, array $options = [], bool $resultSet = false, array $withRelationAttr = []): void + protected function resultToModel(array &$result, array $options = [], bool $resultSet = false): void { - // 动态获取器 - if (!empty($options['with_attr']) && empty($withRelationAttr)) { - foreach ($options['with_attr'] as $name => $val) { - if (strpos($name, '.')) { - [$relation, $field] = explode('.', $name); - - $withRelationAttr[$relation][$field] = $val; - unset($options['with_attr'][$name]); - } - } - } + $options['with_relation_attr'] = $this->getWithRelationAttr(); + $options['is_resultSet'] = $resultSet; // JSON 数据处理 if (!empty($options['json'])) { - $this->jsonResult($result, $options['json'], $options['json_assoc'], $withRelationAttr); + $this->jsonResult($result, $options['json'], $options['json_assoc'], $options['with_relation_attr']); } - $result = $this->model - ->newInstance($result, $resultSet ? null : $this->getModelUpdateCondition($options)); - - // 动态获取器 - if (!empty($options['with_attr'])) { - $result->withAttribute($options['with_attr']); + foreach ($this->options['filter'] as $filter) { + $result = call_user_func($filter, $result); } - // 输出属性控制 - if (!empty($options['visible'])) { - $result->visible($options['visible']); - } elseif (!empty($options['hidden'])) { - $result->hidden($options['hidden']); - } - - if (!empty($options['append'])) { - $result->append($options['append']); - } - - // 关联查询 - if (!empty($options['relation'])) { - $result->relationQuery($options['relation'], $withRelationAttr); - } - - // 预载入查询 - if (!$resultSet && !empty($options['with'])) { - $result->eagerlyResult($result, $options['with'], $withRelationAttr, false, $options['with_cache'] ?? false); - } - - // JOIN预载入查询 - if (!$resultSet && !empty($options['with_join'])) { - $result->eagerlyResult($result, $options['with_join'], $withRelationAttr, true, $options['with_cache'] ?? false); - } - - // 关联统计 - if (!empty($options['with_count'])) { - foreach ($options['with_count'] as $val) { - $result->relationCount($this, (array) $val[0], $val[1], $val[2], false); - } - } + $result = $this->model->newInstance($result, $resultSet ? null : $this->getModelUpdateCondition($options), $options); } + /** + * 查询软删除数据 + * @access public + * @return Query + */ + public function withTrashed() + { + return $this->model ? $this->model->queryWithTrashed() : $this; + } + + /** + * 只查询软删除数据 + * @access public + * @return Query + */ + public function onlyTrashed() + { + return $this->model ? $this->model->queryOnlyTrashed() : $this; + } } diff --git a/vendor/topthink/think-orm/src/db/concern/ResultOperation.php b/vendor/topthink/think-orm/src/db/concern/ResultOperation.php index 77409d1..d8b5a4c 100644 --- a/vendor/topthink/think-orm/src/db/concern/ResultOperation.php +++ b/vendor/topthink/think-orm/src/db/concern/ResultOperation.php @@ -26,6 +26,23 @@ use think\Model; */ trait ResultOperation { + /** + * 设置数据处理 + * @access public + * @param callable $filter 数据处理Callable + * @param string $index 索引(唯一) + * @return $this + */ + public function filter(callable $filter, string $index = null) + { + if ($index) { + $this->options['filter'][$index] = $filter; + } else { + $this->options['filter'][] = $filter; + } + return $this; + } + /** * 是否允许返回空数据(或空模型) * @access public @@ -62,11 +79,9 @@ trait ResultOperation $this->jsonResult($result, $this->options['json'], true); } - if (!empty($this->options['with_attr'])) { - $this->getResultAttr($result, $this->options['with_attr']); + foreach ($this->options['filter'] as $filter) { + $result = call_user_func($filter, $result); } - - $this->filterResult($result); } /** @@ -78,22 +93,8 @@ trait ResultOperation */ protected function resultSet(array &$resultSet, bool $toCollection = true): void { - if (!empty($this->options['json'])) { - foreach ($resultSet as &$result) { - $this->jsonResult($result, $this->options['json'], true); - } - } - - if (!empty($this->options['with_attr'])) { - foreach ($resultSet as &$result) { - $this->getResultAttr($result, $this->options['with_attr']); - } - } - - if (!empty($this->options['visible']) || !empty($this->options['hidden'])) { - foreach ($resultSet as &$result) { - $this->filterResult($result); - } + foreach ($resultSet as &$result) { + $this->result($result); } // 返回Collection对象 @@ -102,36 +103,14 @@ trait ResultOperation } } - /** - * 处理数据的可见和隐藏 - * @access protected - * @param array $result 查询数据 - * @return void - */ - protected function filterResult(&$result): void - { - $array = []; - if (!empty($this->options['visible'])) { - foreach ($this->options['visible'] as $key) { - $array[] = $key; - } - $result = array_intersect_key($result, array_flip($array)); - } elseif (!empty($this->options['hidden'])) { - foreach ($this->options['hidden'] as $key) { - $array[] = $key; - } - $result = array_diff_key($result, array_flip($array)); - } - } - /** * 使用获取器处理数据 * @access protected * @param array $result 查询数据 * @param array $withAttr 字段获取器 - * @return void + * @return array */ - protected function getResultAttr(array &$result, array $withAttr = []): void + protected function getResultAttr(array $result, array $withAttr = []): array { foreach ($withAttr as $name => $closure) { $name = Str::snake($name); @@ -147,6 +126,8 @@ trait ResultOperation $result[$name] = $closure($result[$name] ?? null, $result); } } + + return $result; } /** @@ -170,7 +151,7 @@ trait ResultOperation * 查找单条记录 不存在返回空数据(或者空模型) * @access public * @param mixed $data 数据 - * @return array|Model|static + * @return array|Model|static|mixed */ public function findOrEmpty($data = null) { @@ -242,7 +223,7 @@ trait ResultOperation * 查找单条记录 如果不存在则抛出异常 * @access public * @param array|string|Query|Closure $data 数据 - * @return array|Model|static + * @return array|Model|static|mixed * @throws ModelNotFoundException * @throws DataNotFoundException */ diff --git a/vendor/topthink/think-orm/src/db/concern/WhereQuery.php b/vendor/topthink/think-orm/src/db/concern/WhereQuery.php index d2deb03..ef845f5 100644 --- a/vendor/topthink/think-orm/src/db/concern/WhereQuery.php +++ b/vendor/topthink/think-orm/src/db/concern/WhereQuery.php @@ -361,9 +361,7 @@ trait WhereQuery $field = $this->options['via'] . '.' . $field; } - if ($field instanceof Raw) { - return $this->whereRaw($field, is_array($op) ? $op : [], $logic); - } elseif ($strict) { + if ($strict) { // 使用严格模式查询 if ('=' == $op) { $where = $this->whereEq($field, $condition); diff --git a/vendor/topthink/think-orm/src/model/Collection.php b/vendor/topthink/think-orm/src/model/Collection.php index f017e32..c8ff385 100644 --- a/vendor/topthink/think-orm/src/model/Collection.php +++ b/vendor/topthink/think-orm/src/model/Collection.php @@ -157,7 +157,7 @@ class Collection extends BaseCollection public function withAttr($name, $callback = null) { $this->each(function (Model $model) use ($name, $callback) { - $model->withAttribute($name, $callback); + $model->withAttr($name, $callback); }); return $this; diff --git a/vendor/topthink/think-orm/src/model/concern/Attribute.php b/vendor/topthink/think-orm/src/model/concern/Attribute.php index 34cb59a..a48c74e 100644 --- a/vendor/topthink/think-orm/src/model/concern/Attribute.php +++ b/vendor/topthink/think-orm/src/model/concern/Attribute.php @@ -106,6 +106,12 @@ trait Attribute */ private $withAttr = []; + /** + * 数据处理 + * @var array + */ + private $filter = []; + /** * 获取模型对象的主键 * @access public @@ -177,6 +183,24 @@ trait Attribute return $this; } + /** + * 设置模型数据处理 + * @access public + * @param callable $filter 数据处理Callable + * @param string $index 索引(唯一) + * @return $this + */ + public function filter(callable $filter, string $index = null) + { + if ($index) { + $this->filter[$index] = $filter; + } else { + $this->filter[] = $filter; + } + + return $this; + } + /** * 获取实际的字段名 * @access protected @@ -633,11 +657,11 @@ trait Attribute * @param callable $callback 闭包获取器 * @return $this */ - public function withAttribute($name, callable $callback = null) + public function withAttr($name, callable $callback = null) { if (is_array($name)) { foreach ($name as $key => $val) { - $this->withAttribute($key, $val); + $this->withAttr($key, $val); } } else { $name = $this->getRealFieldName($name); diff --git a/vendor/topthink/think-orm/src/model/concern/Conversion.php b/vendor/topthink/think-orm/src/model/concern/Conversion.php index 35d96d0..22d6256 100644 --- a/vendor/topthink/think-orm/src/model/concern/Conversion.php +++ b/vendor/topthink/think-orm/src/model/concern/Conversion.php @@ -330,6 +330,7 @@ trait Conversion } // JsonSerializable + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); diff --git a/vendor/topthink/think-orm/src/model/concern/SoftDelete.php b/vendor/topthink/think-orm/src/model/concern/SoftDelete.php index 8d76bb0..117f1ef 100644 --- a/vendor/topthink/think-orm/src/model/concern/SoftDelete.php +++ b/vendor/topthink/think-orm/src/model/concern/SoftDelete.php @@ -55,6 +55,16 @@ trait SoftDelete return $model->withTrashedData(true)->db(); } + /** + * 查询软删除数据 + * @access public + * @return Query + */ + public function queryWithTrashed(): Query + { + return $this->withTrashedData(true)->db(); + } + /** * 是否包含软删除数据 * @access protected @@ -86,6 +96,23 @@ trait SoftDelete return $model->db(); } + /** + * 只查询软删除数据 + * @access public + * @return Query + */ + public function queryOnlyTrashed(): Query + { + $field = $this->getDeleteTimeField(true); + + if ($field) { + return $this->db() + ->useSoftDelete($field, $this->getWithTrashedExp()); + } + + return $this->db(); + } + /** * 获取软删除数据的查询条件 * @access protected @@ -152,12 +179,12 @@ trait SoftDelete public static function destroy($data, bool $force = false): bool { // 传入空值(包括空字符串和空数组)的时候不会做任何的数据删除操作,但传入0则是有效的 - if(empty($data) && $data !== 0){ + if (empty($data) && 0 !== $data) { return false; } // 仅当强制删除时包含软删除数据 $model = (new static()); - if($force){ + if ($force) { $model->withTrashedData(true); } $query = $model->db(false); diff --git a/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php b/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php index 5f177c1..75eab1e 100644 --- a/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php +++ b/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php @@ -19,7 +19,6 @@ use think\db\Raw; use think\Model; use think\model\Pivot; use think\model\Relation; -use think\Paginator; /** * 多对多关联类 @@ -120,31 +119,6 @@ class BelongsToMany extends Relation } } - /** - * 合成中间表模型 - * @access protected - * @param array|Collection|Paginator $models - */ - protected function hydratePivot(iterable $models) - { - foreach ($models as $model) { - $pivot = []; - - foreach ($model->getData() as $key => $val) { - if (strpos($key, '__')) { - [$name, $attr] = explode('__', $key, 2); - - if ('pivot' == $name) { - $pivot[$attr] = $val; - unset($model->$key); - } - } - } - - $model->setRelation($this->pivotDataName, $this->newPivot($pivot)); - } - } - /** * 延迟获取关联数据 * @access public @@ -158,62 +132,9 @@ class BelongsToMany extends Relation $closure($this->getClosureType($closure)); } - $result = $this->relation($subRelation) + return $this->relation($subRelation) ->select() ->setParent(clone $this->parent); - - $this->hydratePivot($result); - - return $result; - } - - /** - * 重载select方法 - * @access public - * @param mixed $data - * @return Collection - */ - public function select($data = null): Collection - { - $this->baseQuery(); - $result = $this->query->select($data); - $this->hydratePivot($result); - - return $result; - } - - /** - * 重载paginate方法 - * @access public - * @param int|array $listRows - * @param int|bool $simple - * @return Paginator - */ - public function paginate($listRows = null, $simple = false): Paginator - { - $this->baseQuery(); - $result = $this->query->paginate($listRows, $simple); - $this->hydratePivot($result); - - return $result; - } - - /** - * 重载find方法 - * @access public - * @param mixed $data - * @return Model - */ - public function find($data = null) - { - $this->baseQuery(); - $result = $this->query->find($data); - - if ($result && !$result->isEmpty()) { - $this->hydratePivot([$result]); - } - - return $result; } /** @@ -673,6 +594,23 @@ class BelongsToMany extends Relation $foreignKey = $this->foreignKey; $localKey = $this->localKey; + $this->query->getModel()->filter(function ($result, $options) { + $pivot = []; + + foreach ($result->getData() as $key => $val) { + if (strpos($key, '__')) { + [$name, $attr] = explode('__', $key, 2); + + if ('pivot' == $name) { + $pivot[$attr] = $val; + unset($result->$key); + } + } + } + + $result->setRelation($this->pivotDataName, $this->newPivot($pivot)); + }); + // 关联查询 if (null === $this->parent->getKey()) { $condition = ['pivot.' . $localKey, 'exp', new Raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk())]; diff --git a/view/taoler/index/article/ask/cate.html b/view/taoler/index/article/ask/cate.html index 963af87..ed75801 100644 --- a/view/taoler/index/article/ask/cate.html +++ b/view/taoler/index/article/ask/cate.html @@ -17,7 +17,7 @@ -
{$comments|raw}
+
@@ -285,7 +285,7 @@ layui.use(['fly', 'face','colorpicker','plyr', 'laypage'], function(){ //执行一个laypage实例 laypage.render({ elem: 'pages' //注意,这里的 test1 是 ID,不用加 # 号 - ,count: {$count} //数据总数,从服务端得到 + ,count: "{$article.comments_count}" //数据总数,从服务端得到 ,limit: 10 ,curr : {$page} @@ -294,8 +294,10 @@ layui.use(['fly', 'face','colorpicker','plyr', 'laypage'], function(){ //首次不执行 if(!first){ var page = obj.curr; - var url = "{:url('article/detail',['id'=>$article.id])}" - $.post(url,{"page":page},function(){ + console.log(page); + var url = "{:url('article/detail',['id'=>$article.id])}"; + var id = "{$article.id}"; + $.post("{:url('article/detail')}",{"page":page,"id":id},function(){ window.location.href = url + '?page=' + page + '#flyReply'; }); } diff --git a/view/taoler/index/article/cate.html b/view/taoler/index/article/cate.html index e413baf..5236d3d 100644 --- a/view/taoler/index/article/cate.html +++ b/view/taoler/index/article/cate.html @@ -12,14 +12,14 @@ {include file="public/filter" /}