### 2019 年 3 月 10 日 发布
>[danger]### 本文主要用于指导开发者从`5.1`升级到`5.2`最新(RC)版本,由于`5.2`不支持`5.1`的无缝升级,下面的升级步骤和指导仅供学习参考,或有遗漏及考虑不周之处,因此不保证你的所有功能都能正常升级。在建项目应该在官方正式发布`5.2`版本之后,再进行升级为宜。
`5.2`版本必须使用`composer`安装,所以你需要首先安装新的`5.2`版本,然后把原来`5.1`的文件复制进去,完成升级工作。
~~~cmd
composer create-project topthink/think:5.2.x-dev tp
~~~
安装完成后,把原来`application`目录下面的文件复制到`app`目录下面,然后把`config`和`route`目录下的文件复制到同名目录下。接下来,按照下面的步骤来升级操作。
>[info] 从`5.1`多模块迁移到`5.2`的多应用后,应用类库的命名空间原则上可以无需调整,但不再支持跨应用调用(包括路由,每个应用的路由是独立的),这点务必引起重视。
[TOC=2,2]
## 第一步:入口文件修改
如果你之前是多模块模式,你需要按照下面的方式修改默认入口文件,增加`autoMulti()`方法。
~~~
<?php
// [ 应用入口文件 ]
namespace think;
require __DIR__ . '/../vendor/autoload.php';
// 执行应用并响应
(new App())->autoMulti()
->initialize()
->run()
->send();
~~~
更改后,可以删除`app`目录下的默认自带的`controller`目录,这些文件已经不再需要。
如果你原来的默认模块不是`index`,那么还需要调用`name`方法(假如默认模块之前是`home`)。
```
// 执行应用并响应
(new App())->autoMulti()
->name('home')
->initialize()
->run()
->send();
```
如果你之前是单一模块模式,那么入口文件可以保持默认代码不变。
~~~
<?php
// [ 应用入口文件 ]
namespace think;
require __DIR__ . '/../vendor/autoload.php';
// 执行应用并响应
(new App())->initialize()
->run()
->send();
~~~
如果你自定义了访问控制器层的名称,那么需要在入口文件的`initialize()`方法之前调用。
```
->controllerLayer('layer_name')
```
如果你更改了默认的空控制器名,那么需要在入口文件中添加
```
->emptyController('你的空控制器名称')
```
如果你的控制器类开启了类后缀,需要在入口文件中添加
```
->controllerSuffix()
```
## 第二步:配置调整
请按照如下顺序检查及调整你的配置文件和相关配置代码。
### 配置获取调整
原来获取一级配置参数的方式
```
Config::pull('app');
```
需要改成
```
Config::get('app');
```
所有的配置读取必须从第一级配置开始,例如,原来的
```
Config::get('exception_handle');
```
必须改成
```
Config::get('app.exception_handle');
```
### 废弃动态设置
动态更改配置参数的用法已经废弃,下面的用法不再支持。
```
Config::set('route.default_return_type', 'json');
```
如果你需要把数据库的配置参数读入配置,可以使用
```
$config = Db::name('config')->column('value', 'name');
Config::set($config, 'route');
```
### `Config`类不再支持数组方式读取
`Config`类不再使用`ArrayAccess`接口,因此不再支持数组方式读取。
### 路由和URL配置独立
路由和URL请求相关的配置参数独立为`route.php`配置文件,而不再使用`app.php`配置文件。
## 第三步:路由和请求调整
### 路由定义文件位置调整
单应用模式下,路由定义文件和之前一样就在`route`目录下面,如果你的项目是采用了多应用的话,每个应用的路由定义和匹配都是独立的,也没有模块的概念,路由定义文件的位置应该是在`route/应用子目录`下面,例如:
~~~
route/index/route.php // index应用的路由定义文件
route/index/web.php // index应用的第二个路由定义文件
route/admin/route.php // admin应用的路由定义文件
~~~
> 应用的路由规则其实是定义的入口文件(或者应用名)后面的URL部分,而不包含应用。
### 路由注册方法调整
首先如果你的路由定义采用的是返回数组形式,全部改成方法定义。
例如:
~~~
return [
'hello/:name' => 'index/hello',
];
~~~
必须改成:
~~~
Route::get('hello/:name', 'index/hello');
~~~
如果路由定义方法(包括`rule`/`get`/`post`/`put`/`delete`/`patch`/`miss`/`group`等方法)使用了`option`和`pattern`参数,全部改成方法调用形式,例如原来的:
~~~
Route::get('hello/:name', 'index/hello', [ 'ext' => 'html'], [ 'name' => '\w+']);
~~~
需要改成
~~~
Route::get('hello/:name', 'index/hello')
->ext('html')
->pattern([ 'name' => '\w+']);
~~~
### 路由分组调整
如果路由分组定义使用了数组,改成闭包方式定义,例如:
~~~
Route::group('blog', [
':id' => 'Blog/read',
':name' => 'Blog/read',
])->ext('html')->pattern(['id' => '\d+']);
~~~
必须改成
~~~
Route::group('blog', function() {
Route::get(':id', 'Blog/read');
Route::get(':name', 'Blog/read');
})->ext('html')->pattern(['id' => '\d+']);
~~~
如果你需要注册一个虚拟的路由分组,可以直接在第一个参数使用闭包
~~~
Route::group(function() {
Route::get('blog/:id', 'Blog/read');
Route::get('user/:name', 'User/read');
})->ext('html')->pattern(['id' => '\d+']);
~~~
### 取消了`url_controller_layer`配置
改为在入口文件中使用`controllerLayer`方法设置。
~~~
(new App())->controllerLayer('Action')
->initialize()
->run()
->send();
~~~
### 取消`controller_suffix`配置
改为在入口文件中使用`useClassSuffix`方法设置。
~~~
(new App())->useClassSuffix(true)
->initialize()
->run()
->send();
~~~
同时`class_suffix`配置参数已经无效。
### 取消`mergeExtraVars`方法和对应参数
改为在路由规则中明确指定变量规则。
### `header`方法参数类型调整
由于强类型约束的原因,`header`方法改为仅支持数组参数传入。
### 取消`Request`类的`hook`方法
由于不建议扩展`Request`类的方法,该方法已经在最新版本中取消。如果你使用了该功能,只能自定义请求对象(必须继承`think\Request`),然后在入口文件中绑定`request`到容器。
```
bind('request', new \my\Request());
```
### 取消`URL`参数模式配置
原来的URL参数模式配置参数`url_param_type`,统一使用参数/值的方式。如果你设置了该配置参数为1,必须改成定义路由的方式。
### 取消别名路由
因为使用场景有限和性能开销问题,取消原来的别名路由功能,建议使用资源路由或者单独的路由替代。
### 取消快捷路由
因为使用场景有限和不太符合规范,取消了原来的控制器快捷路由功能。
### 取消空操作功能
建议使用分组MISS路由功能替代。
## 第四步:控制器和视图调整
### 视图和模板引擎从核心分离
视图和模板引擎类不再内置到核心框架,但使用
~~~
composer create-project topthink/think
~~~
会默认安装该组件(如果不需要使用的话可以自己卸载`topthink/think-view`)。
安装后,由于内置的`think\Controller`类不再封装视图方法,如果你的控制器类需要调用`fetch`/`display`/`assign`等视图方法,必须改为继承`think\ViewController`类,如果是使用`view`助手函数方式的话,可以无需调整。
### `assign`方法调整
`assign`方法只能传入数组,统一设置模板变量。建议统一使用`view`助手函数。
### `share`方法取消
原来视图类的`share`方法取消,可以使用
```
think\facade\View::assign($vars);
```
## 第五步:数据库和模型调整
### `Db`改为使用门面对象
新版的`Db`类不再是静态类,需要使用`think\facade\Db`门面进行静态代理。
~~~
\think\facade\Db::name('user')->find();
~~~
### 数据库配置信息调整
数据库配置文件或者`connect`方法取消`DSN`数据库配置定义方式,全部采用数组方式配置定义。
~~~
Db::connect('mysql://root:1234@127.0.0.1:3306/thinkphp#utf8')
->table('user')
->find();
~~~
必须改成
~~~
Db::connect([
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'thinkphp',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '1234',
// 数据库连接端口
'hostport' => '3306',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
])
->table('user')
->find();
~~~
### 取消`fetchPdo`方法
取消了`Query`类的`fetchPdo`方法,需要的时候直接使用`getPdo`方法替代。
### 取消查询方法传入`Query`对象
取消Query类的CURD查询方法传入当前对象,如果需要请使用闭包替代。
### `insert`/`insertGetId`/`insertAll`方法取消`replace`参数
`insert`/`insertGetId`/`insertAll`方法的第二个`replace`参数已经取消,改为使用`replace`方法。
~~~
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->insert($data, true);
~~~
需要改为
~~~
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->replace()->insert($data);
~~~
### 取消`db`和`model`助手函数
这两个助手函数`5.1`版本已经不再建议使用了,`5.2`版本已经废弃掉这两个助手函数,请直接使用`\think\facade\Db`类静态方法和实际的模型类调用。
### 取消`setInc`/`setDec`方法
取消Query类的`setInc`/`setDec`方法,统一使用`inc`/`dec`方法替代,同时改进了`inc`/`dec`方法支持延时更新。例如:
~~~
Db::name('user')->where('id', 1)
->inc('exp')
->dec('score')
->update();
~~~
### 取消`setField`方法
取消Query类的`setField`方法,请直接使用`data`方法或者`update`方法。
### 取消`__TABLE_NAME__`支持
`table`方法取消`__TABLE_NAME__`支持,必须明确调用完整表名或者使用`name`方法。
### 取消`whereOr`等方法传入`Query`对象
因为`Query`对象查询只能使用一次,除了`where`方法本身可以传入`Query`对象外,其它的所有`where`查询方法(例如`whereOr`/`whereExp`等)都不再支持传入`Query`对象。
### 取消`resultset_type`配置参数
数据集查询结果不再受`resultset_type`配置参数影响,默认情况下,Db查询统一返回数组,模型查询统一返回模型对象和模型数据集对象。如果Db查询的时候也需要返回数据集的话,可以显式调用`fetchCollection`方法。
### 取消`Query`类的`extend`方法
取消了`Query`类的`extend`方法,如果需要扩展查询方法,建议自定义`Query`类并继承系统的`think\db\Query`类即可,然后在模型中定义`query`属性或者配置数据库连接的`query`参数为你的自定义类。
### `Expression`对象调整
原来的`Expression`对象已经更改为更适合的`Raw`对象,但不影响`Db::raw()`方法的调用。
### 取消查询`eq/neq/gt/lt/egt/elt`表达式
由于存在两种用法,并且不够直观,全部统一为更直观的用法。
下面的用法不再支持
~~~
Db::name('user')->where('id', 'egt', 1)
->where('status', 'neq' ,1)
->select();
~~~
统一使用
~~~
Db::name('user')->where('id', '>=', 1)
->where('status', '<>' ,1)
->select();
~~~
### 取消分表功能
出于分表的性能问题和复杂性,不再提供分表方法,建议使用数据库的分区功能替代。新版可以使用`partition`方法指定当前查询的分区。
### 数据库的查询统计合并
数据库的查询次数合并到`queryTimes`,不再区分读写操作,你可以使用下面的方法获取当前请求的数据库查询次数(包括读写)
~~~
Db::getQueryTimes();
~~~
### 取消了模型的`get`/`all`方法
无论使用`Db`类还是模型类查询,全部统一使用`find`/`select`方法,取消了之前模型类额外提供的`get`/`all`方法。同时取消的方法还包括`getOrFail`/`allOrFail`。
### 取消全局查询范围`base`方法
取消模型类的全局查询范围`base`方法,改由使用`globalScope`属性定义(数组)需要全局查询的查询范围方法。或者在`db($scope)`方法中传入全局查询范围。如果是静态查询,可以使用`useGlobalScope($scope)`。
### 模型事件调整
模型事件不再支持使用`event`方法注册事件,统一使用模型事件观察者类,你只需要在模型定义或者初始化的时候设置`observerClass`属性。
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $observerClass = 'app\index\observe\User';
}
~~~
所有的模型事件统一在观察者类中进行定义,方法的命名规范如下:
~~~
<?php
namespace app\index\observe;
class User
{
public function onAfterRead($user){
$user->extra = 'extra';
}
public function onBeforeWrite($user){
$user->extra = 'extra';
}
}
~~~
并且模型增加`after_read`事件,在查询后创建模型对象实例的时候触发。
### 模型属性和数据表字段的对应关系
默认情况下,模型对象数据字段严格区分大小写,你可以关闭严格模式(前提是必须保持数据表字段的小写和下划线定义规范),然后在模型中使用的时候,如果使用驼峰命名调用,则会自动转换为小写和下划线规范的字段(关连模型除外),例如:
~~~
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $strict = false;
}
~~~
然后,下面的代码
~~~
$user = User::find();
echo $user->nick_name;
$user->nick_name = 'test';
$user->save();
~~~
和下面的用法是等效的
~~~
$user = User::find();
echo $user->nickName;
$user->nickName = 'test';
$user->save();
~~~
> 如果你的数据表字段不符合规范(存在大小写混合使用的情况),那么必须在模型中开启`strict`属性。
### 模型`save`方法调整
模型类的`save`方法不再支持`where`参数。
### 关联统计调整
如果你的关联统计使用了闭包方式返回关联统计字段,需要调整为如下方式:
```
User::withCount(['cards' => function($query,&$name) {
$query->where('status', 1);
$name = 'card_count';
}])->select();
```
### 模型和数据集的输出调整
取消`hidden`/`visible`/`append`方法的第二个参数,当你调用这几个方法的时候,无论模型是否设置了相关属性,都会直接覆盖之前设置的值。
### 查询缓存调整
如果希望在更新和删除之后自动清除之前的查询缓存,必须在`cache`方法中传入key值而不是`true`。
### 删除关联类`selfRelation`方法
如果你在定义关联的时候使用了`selfRelation`方法,请直接删除该方法,目前已经不再需要,会自动识别是否为自关联。
### 删除关联类的`setEagerlyType`方法
一对一关联无需在定义关联的时候指定为`JOIN`查询,在查询的时候直接使用`withJoin`方法即可使用`JOIN`方式进行关联查询。
### 多对多关联
多对多关联的`pivotDataName`方法更名为更简单的`name`方法。
## 第六步:行为调整
行为和`Hook`已经用新版的事件机制替代,需要把你的行为改成事件响应或者中间件(部分请求拦截的行为可以直接改为中间件)。
原来的系统内置钩子的行为类
~~~
<?php
namespace app\index\behavior;
class Hello
{
public function run($params)
{
// 行为逻辑
}
}
~~~
可以改成事件监听类
~~~
namespace app\index\listener;
class Hello
{
public function handle($event)
{
// 事件监听处理
}
}
~~~
然后在应用目录的`event.php`文件中配置事件监听。
~~~
return [
'listen' => [
'AppBegin' => ['\app\index\listener\Hello'],
// 更多事件监听
],
];
~~~
如果有自定义的钩子,首先需要创建事件类,可以通过命令行生成事件类。
~~~
php think make:event index@UserLogin
~~~
会生成`index`应用下面的`UserLogin`事件类。
~~~
<?php
namespace app\index\event;
class UserLogin
{
}
~~~
然后生成监听器
~~~
php think make:listener index@UserLogin
~~~
~~~
<?php
namespace app\index\listener;
class UserLogin
{
public function handle($event)
{
// 事件监听处理
}
}
~~~
在`event.php`定义文件中添加
~~~
return [
'bind' => [
'UserLogin' => ['\app\index\event\UserLogin'],
],
'listen' => [
'UserLogin' => ['\app\index\listener\UserLogin'],
],
];
~~~
修改完成后,你可以删除应用目录下不再使用的`tags.php`文件。
内置事件和钩子的对应关系如下:
| 事件| 对应`5.1`钩子| 参数 |
| --- | --- | --- |
| `AppInit` | `app_init `| 无 |
| `AppBegin` | `app_begin` | 无 |
| `AppEnd` | `app_end `| 当前响应对象实例 |
| `LogWrite` | `log_write `| 当前写入的日志信息 |
| `LogLevel` | `log_level `| 包含日志类型和日志信息的数组 |
| `ResponseSend` | `response_send `| 当前响应对象 |
| `ResponseEnd` | `response_end `| 当前响应对象 |
>[danger] 原来的`action_begin`、`module_init`和`view_filter`钩子已经废弃。
## 第七步:其它调整及注意事项
### 应用类库后缀规范
取消了`controller_suffix`和`class_suffix`配置参数,App类增加了`controllerSuffix`方法用于开启控制器类库的`Controller`后缀(默认不开启)。其它应用类库的后缀由项目自己决定,框架不再强制规范。
>[info] 需要注意的是,如果你的模型类命名使用了`Model`后缀的话,一定要定义`name`属性或者`table`属性。
### 系统`Facade`类库别名取消
系统`Facade`类库的别名已经取消,因此不能再使用
```
use Route;
Route::rule('hello/:name', 'index/hello');
```
必须使用
```
use think\facade\Route;
Route::rule('hello/:name', 'index/hello');
```
### 严格类型检查
由于新版框架核心类库全面启用强类型参数,并且使用严格模式,所以在调用系统方法的时候一定要注意参数的类型,或者注意看抛出的异常信息进行修正。
>[success]### 最后,希望你的`5.2`升级之旅顺利^_^ 希望大家在升级和使用`5.2`的过程中,多反馈和建议,帮助我们尽快完善和发布正式版本。
- 值得升级到5.1的18个理由
- 5.1.7版本新特性
- JSON字段类型在ORM中的使用
- 文件下载响应对象
- 教你使用5.1的数组对象查询
- 模型三大利器之一:搜索器
- 在ThinkPHP中使用Yaconf
- 掌握命令行的表格输出
- 5.1.25查询参数绑定的改进
- ThinkPHP安全规范指引
- 巧用数据集的排序功能实现统计排序
- think-orm ——基于5.1的独立ORM库
- think-template——基于ThinkPHP的独立模板引擎
- ThinkPHP5.1.26版本发布——修正版本,包含安全更新
- ThinkPHP5.0和3.2再发安全更新
- 官宣:ThinkPHP发布首个LTS版本
- 你真的了解Db类和模型的正确使用姿势么?
- 如何更有效的记录和管理日志
- 模型三大利器之二:修改器
- ThinkPHP5.1.28版本发布——修正上一版本问题,改进关联查询
- 模型三大利器之三:获取器
- API版本控制的几种思路
- ThinkPHP5.2第一个Beta版本发布测试
- 让你少犯错的数据查询基本原则
- ThinkPHP发布5.1.29版本——常规更新
- 这15个好习惯让你更容易升级到5.2
- 如何有效提高ThinkPHP的应用性能
- 让你提高开发效率的查询技巧
- 模型关联查询不完全指南
- 5.2发布Beta2版本——统一和精简大量用法
- ThinkPHP发布5.1.30版本——支持微秒时间字段写入
- ThinkPHP的数据缓存使用
- ThinkPHP5.2安装及入口文件
- ThinkPHP荣获2018 年度最受欢迎中国开源开发框架第1名
- 5.1路由使用心得技巧
- ThinkPHP5.*版本发布安全更新
- ThinkPHP项目及代码规范指北
- 5.2版本的设计规范指导
- ThinkPHP5.1.32版本发布——圣诞快乐
- 利用Trait特性给模型增加乐观锁功能
- 5.2数据库和模型的变化(摘要)
- ThinkPHP模板引擎实现和常见问题
- ThinkPHP5.0.24版本发布——安全更新
- 不忘初心,方得始终——ThinkPHP十三周年报告
- ThinkPHP5+相关资源汇总
- 异步社区ThinkPHP周年庆专享优惠活动
- 5.2路由的调整和改进
- ThinkPHP发布5.1.33版本——包含安全更新
- ThinkPHP扩展开发指南
- ThinkPHP发布5.2Beta3版本
- ThinkPHP发布5.1.34版本——喜迎新年
- ThinkPHP发布5.2RC1版本
- ThinkPHP发布5.1.35版本——常规更新
- 5.2配置类的调整
- 5.2时间查询的改进和优化
- 5.2RC版本升级不完全指导(仅供学习参考)
- ThinkPHP5.2版本正式变更为6.0版本
- ThinkPHP百度云云虚拟主机专享免费活动
- 事件系统以及查询事件、模型事件的使用
- ThinkPHP6.0RC2版本发布——架构升级、精简核心
- ThinkPHP5.1.36LTS版本发布——常规更新
- 新版Session和Cookie设计变化
- ThinkPHP5.1.37版本发布——常规更新
- ThinkPHP6.0RC3版本发布——细节完善,体验优化
- 6.0中间件使用详解
- Composer各大厂商镜像地址
- ThinkPHP6.0发布计划公告
- 「ThinkPHP开发者周刊」招募志愿者
- ThinkPHP6.0日志变化
- ThinkPHP5.1.38版本发布——常规更新
- ThinkPHP6.0RC4版本发布——ORM独立,日志多通道支持
- ThinkORM2.0开发指南上线
- ThinkPHP6.0RC5版本发布——多应用模式独立,中间件机制调整
- ThinkPHP6.0版本发布——程序员节福利
- ThinkPHP5.1.39LTS版本发布——常规更新
- ThinkPHP6.0.1版本发布——圣诞快乐!
- 回顾2019,展望2020!
- ThinkPHPV6.0.2版本发布——2020新春快乐!
- 周年福利系列:Swoole合作优惠
- 亿速云成为ThinkPHPV6.0独家赞助发布商🎉
- 新冠疫情工具和限免资源专题(保持更新中)
- 周年福利系列:创宇信用认证合作优惠
- 周年福利系列:码云企业版限时10%优惠
- 周年福利系列:想天短说抵现优惠
- think-swoole直播:从零开始掌握swoole开发
- 周年福利系列:B2C开源电商ShopXO授权8折优惠
- 周年福利系列:LayuiAdmin 永久授权限时优惠
- ThinkPHP资源导航站上线——构建生态 服务未来
- ThinkPHP官方技术支持服务和应用服务市场上线公测
- ThinkPHP市场精选——推广基本要素
- ThinkPHP市场精选——客服聊天专题
- ThinkPHPV6.0.3版本发布——端午安康
- ThinkPHP开发者扶持计划
- 6.0.3版本关键更新及升级事项
- 「ThinkPHP开发者周刊」改版重启
- ThinkPHP市场精选——企业建站专题
- ThinkPHP 提供统一API接口服务
- ThinkPHP市场精选——直播电商专题
- ThinkAPI服务SDK发布
- 官方服务市场启用独立子域名
- ThinkPHP市场精选——刷脸支付专题
- ThinkAPI推出会员服务计划
- ThinkPHPV6.0.4版本发布——中秋国庆双节快乐
- ThinkPHPV5.1.40版本发布——常规更新
- 1024程序员节福利走一波
- ThinkPHP V6.0.5版本发布——兼容Composer2.0
- 知识图谱应用场景——源论技术沙龙
- ThinkPHP5.*版本改进Composer2.0的兼容
- 官方市场双十一精选推荐
- 技术人做产品有机会么(文末送课程)
- 本周秒杀——古德云售后获客营销系统
- ThinkAPI服务更新——支持接口分组和PHP版本依赖调整
- PHP8新特性盘点
- PHP8新特性系列:构造器属性提升使用及注意事项
- ThinkPHP2021新年寄语
- ThinkPHP V6.0.6&V5.1.41版本发布——兼容PHP8.0
- PHP如何更优雅地调用API接口
- ThinkPHP V6.0.7发布——修正版本
- ThinkAPI服务更新——IP白名单
- 最新版ThinkORM对于时间字段的调整
- ThinkAPI短信接口正式上线
- ThinkPHP V6.0.8版本发布——多环境变量配置支持
- 顶想云写作服务开启第一次公测
- ThinkSSL上线——官方SSL/TLS证书服务
- MDBootstrap国内用户福利——ThinkPHP官方市场首发
- ThinkPHP V6.0.9版本发布——常规更新
- ThinkORM功能盘点——虚拟模型
- 全面支持主流GIT版本库——云写作服务第二次公测
- 云写作服务私有化部署方案之:版本库私有化
- 看云双十一活动
- ThinkPHP V6.0.10LTS发布——兼容PHP8.1
- ThinkPHP V6.0.12发布——命令行兼容8.1
- 顶想云知识管理上线公测——构建企业文档中心和知识库
- 顶想云上线——助力生态数字化建设
- 618活动进行中——官方市场迎来一波更新
- 顶想云知识管理正式上线——看云文档启动迁移服务
- ThinkPHP V6.0.13发布——常规更新
- 顶想云网站助理服务上线——构建产品支持服务
- ThinkPHP发布6.1.0&6.0.14版本——安全更新
- ThinkPHP新版社区上线试运营
- ThinkAPI上架人脸核身接口——助力网站实名认证
- 辞旧迎新——旧版社区停止注册及发帖
- ThinkPHP6.1.2版本发布——兼容PHP8.2