开源经验分享:从ThinkPHP迁移到Laravel11
为什么要迁移到Laravel
ThinkPHP框架非常适合小型应用开发,简单高效,无需关注太多设计哲学,而Laravel拥有更完整的生态,例如提供完整的日志系统、队列系统以及优雅的开发调试体验等。这些都是TP框架所不完全具备的。最近基于Likeadmin全栈开发框架,在TP迁移到Laravel的实践中,总结了一些经验,分享给大家。
ORM模型语法差异
// 查询一条数据
User::field(['id, name'])->where('id', 1)->find(); // TP
User::select(['id', 'name'])->where('id', 1)->first(); // Laravel
// 查询多条数据
User::where('status', 1)->limit(1,10)->select(); // TP
User::where('status', 1)->limit(10)->offset(1)->get(); // Laravel
// 排序
User::where('status', 1)->order('id desc')->select(); // TP
User::where('status', 1)->orderBy('id', 'desc')->get(); // Laravel
// TP的where()可接受多个条件数组
User::where(([['name', 'like', '张三'], ['id', 'in', [1, 2, 3]]])->select();
// Laravel where()不支持in操作符,只能用whereIn
User::where([['name', 'like', '张三']])->whereIn('id', [1,2,3])->get();
// TP的order()可接受多个排序字段
User::where('status', 1)->order(['id' => 'desc', 'sort' => 'desc'])->select();
// Laravel orderBy()不支持多个排序字段,只能用多个orderBy链式调用
User::where('status', 1)->orderBy('id', 'desc')->orderBy('sort', 'desc')->get();
如何抹平差异
使用Builder::macro()来扩展Laravel查询构造器,让where和order方法可接受多个条件和排序字段,抹平和TP的语法差异。源码参考:likeadmin_laravel
// 用法:$query->applySearchWhere([['name', 'like', '张三'], ['id', 'in', [1, 2, 3]]]);
Builder::macro('applySearchWhere', function ($searchWhere) {
foreach ($searchWhere as $where) {
if ($where[1] == 'in') {
$this->whereIn($where[0], $where[2]);
} else {
$this->where(...$where);
}
}
return $this;
});
// 用法:$query->applySortOrder(['id' => 'desc', 'sort' => 'desc']);
Builder::macro('applySortOrder', function ($sortOrder) {
foreach ($sortOrder as $key => $value) {
$this->orderBy($key, $value);
}
return $this;
});
模型定义差异
模型时间戳字段的定义差异,TP的自动时间戳字段以UNIX时间戳格式存储在数据库中,Laravel的自动时间戳字段以Carbon对象存储在数据库中。为了保持数据的一致性,需要在模型中定义时间戳字段的格式化方法。
<?php
use Illuminate\Database\Eloquent\Model;
/**
* 基础模型
*/
class BaseModel extends Model
{
// 全部字段都允许批量赋值
public $guarded = [];
// 查询时自动转换成国内习惯的时间格式
public $casts = [
'create_time' => 'datetime:Y-m-d H:i:s',
'update_time' => 'datetime:Y-m-d H:i:s',
];
// TP的自动时间戳字段以UNIX时间戳格式存储在数据库中
protected $dateFormat = 'U';
// TP的自动时间戳字段-创建时间
public function getCreatedAtColumn()
{
return 'create_time';
}
// TP的自动时间戳字段-更新时间
public function getUpdatedAtColumn()
{
return 'update_time';
}
// 查询时自动转换成国内时区
protected function serializeDate(\DateTimeInterface $date)
{
return $date->timezone(Config::get('app.timezone'))->format('Y-m-d H:i:s');
}
}
未完待续
本文章出自开源项目likeadmin_laravel的实施经验,后续会继续更新,欢迎关注。
项目进度:
████░░░░░░ 40%
欢迎加入开源共建~ 仓库地址:likeadmin_laravel
技术栈:
- PHP 8.0 => PHP 8.2
- ThinkPHP 8 => Laravel 11
- 管理后台:Vue3 + TypeScript + ElementPlus UI + TailwindCSS
- 小程序:Vue3 + TypeScript + Uniapp + TailwindCSS
- PC端:Vue3 + Nuxt
本作品采用《CC 协议》,转载必须注明作者和本文链接
gitee上边是空的。原来开发中,加油
niubi :+1: :+1: :+1: :+1:
这样改过去挺没劲的……,不过就你这个模型查询这里而言,其实还有更好的方式。
在新的版中,在模型里面覆盖
$builder
这个静态属性为自定义的 Builder 、这个 Builder 继承自 Laravel 的\Illuminate\Database\Eloquent\Builder
然后覆盖 where 和 orderBy 方法就好了。当然,旧版可能没有
$builder
这个模型静态属性,那你也还可以直接覆写模型的newEloquentBuilder
方法,来返回一个新的 Builder 实例就好了,这个方法接收一个\Illuminate\Database\Query\Builder
参数,再传给 Builder 的构造方法就好了,可以参考\Illuminate\Database\Eloquent\Model::newEloquentBuilder
的实现。但是吧,我还是更推荐你入乡随俗。