【发布时间】:2016-02-10 16:18:34
【问题描述】:
目标:我想用附加功能“装饰” Laravel 的查询构建器(不直接修改它)。
示例问题:我会尽量保持简短。我在装饰器上实现了get 方法:
public function get($columns = ['*'])
{
return $this->cache->get(implode('.', $columns), function () use ($columns) {
return $this->queryBuilder->get($columns);
});
}
我还将所有对装饰器上未实现的方法的调用委托给查询生成器。
public function __call($method, $parameters)
{
return call_user_func_array([$this->queryBuilder, $method], $parameters);
}
如您所料,直接调用装饰器时效果很好。但几乎每个人都习惯于在使用 Query Builder 时将方法链接在一起。
$queryBuilder = (new CachingDecorator( new QueryBuilder , $app['cache.store'] ));
// get all users
$queryBuilder->from('users')->get();
// get one user
$queryBuilder->from('users')->first(); // <-- delegates to get() internally
问题:上面直接调用的结果没有被缓存。显然是因为from 方法返回的是 Laravel Query Builder 的一个实例,而不是我的装饰器。
问题:是否有一些有用的模式可以帮助解决这个问题?或者这是装饰器模式的限制?
我的第一个想法是尝试将 $this 绑定到另一个对象,就像在 Javascript 中一样。我认为 PHP 不允许这样做。
我能想出的最佳解决方案包括一个将查询构建器对象映射到其装饰器的类,和/或某种基本装饰器,它重新实现查询构建器对象中的几乎所有方法(不是喜欢这个,因为它完全抛弃了 DRY 原则)。
附加说明:我知道我可以通过不将方法调用链接在一起来回避这个问题。没脑子吧?除非要求团队中的每个开发人员避免将他们的调用链接在一起是不合理的。我更愿意解决这个问题而不是回避它。
【问题讨论】:
-
你没有使用 laravel 缓存系统有什么原因吗?
-
@jfadich 我是。
$this->cache是Illuminate\Contracts\Cache\Repository的一个实例。与使用Cache::get()相同。
标签: php laravel decorator method-chaining