缓存 Laravel 模型的小问题

缓存嵌套关联

最近在公司项目中想要缓存 Laravel 的模型,因为加载了很多嵌套关联的模型,使用 json 系列函数并不能轻松地将 json 重新转回模型对象,所以使用了 serialize 系列函数

$json = $redis->get($cacheKey);
$user = $json ? new User(json_decode($json, true)) : User::find($id);
// 模型没有关联时,可以直接从 json 取得数据填充新模型
$ser = $redis->get($cacheKey);
$user = $ser ? unserialize($ser) : User::with('a.b')->find($id);

反序列化不调用构造方法

起初并没有什么问题,从缓存中取出反序列化后就能像一般的模型正常使用,直到我需要在模型的构造函数中初始化一些属性。因为 unserialize 并不会调用构造方法,所以在访问这些属性时是并未初始化的空值。在反序列化时触发的 __wakeup 魔术方法中也要做属性的初始化操作,完成后问题就解决了

public function __construct(array $attributes = [])
{
    parent::__construct($attributes);
    $this->srv = new UserService();
}
public function __wakeup()
{
    parent::__wakeup();
    $this->srv = new UserService();
}

全局静态初始化方法 booted

我之后注意到 Laravel 提供了一个静态的全局初始化方法可供重写 booted,如果需要初始化的属性可以是静态时,这样做或许更优雅吧

protected static function booted()
{
    self::$srv = new UserService();
}

如果 IDE 没有方法提示,可以加注释

/* @var UserService */
static $srv;

调用 refresh 的问题

在拿到缓存的模型后,如果需要重新从数据库读取数据,调用 refresh 只会读取模型本身的关联,不会读取嵌套的关联。需要重新 load 一遍关联,或者在对应模型的 with 数组加入每次需要带上的关联

$user->refresh();
$user->load('a.b');

好像有人也发现了这个问题,提了 issue Eloquent - nested relations lost when calling refresh on model,Dries Vints(Laravel 项目维护者)回复是“这似乎是一个问题而不是 bug,建议到社区讨论”。我想了下,觉得他是对的,因为 with 上面附带的关联时作用于那次查询的,跟查询出来的模型没有关系。不看查询只看模型的话,要重新加载关联,那么只能自己 load 所需的关联,或者在模型的 with 属性带上关联


备注
  • Laravel 模型缓存框架有很多,站里也有教程。不过公司用的是原生 PHP,只是我为了方便单独引入 Laravel 的 Eloquent 模型,所以那些缓存框架无法使用
  • 我对 Laravel 模型用法的理解可能有偏差,如果有错误请指出,有更好的方法请赐教
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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