开源经验分享:从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 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 5

gitee上边是空的。原来开发中,加油

3个月前 评论
admin0000 (楼主) 3个月前

niubi :+1: :+1: :+1: :+1:

2个月前 评论

这样改过去挺没劲的……,不过就你这个模型查询这里而言,其实还有更好的方式。

在新的版中,在模型里面覆盖 $builder 这个静态属性为自定义的 Builder 、这个 Builder 继承自 Laravel 的 \Illuminate\Database\Eloquent\Builder 然后覆盖 where 和 orderBy 方法就好了。

当然,旧版可能没有 $builder 这个模型静态属性,那你也还可以直接覆写模型的 newEloquentBuilder 方法,来返回一个新的 Builder 实例就好了,这个方法接收一个 \Illuminate\Database\Query\Builder 参数,再传给 Builder 的构造方法就好了,可以参考 \Illuminate\Database\Eloquent\Model::newEloquentBuilder 的实现。

但是吧,我还是更推荐你入乡随俗。

2个月前 评论
admin0000 (楼主) 2个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!