假设我有这样的东西:
class User{
/**
* Object that is lazy loaded
*/
private $statistic; //object with some stored data and some calculated data
}
$statistic 的一些属性存储在数据库中,但其他一些属性是通过分析用户事件(查询数据记录)来计算的。
问题是我得到了一个 $user,当我按照预期运行 $user->getStatistic() 时,我得到了存储的 $statistic 数据,我需要使用 sql 查询添加更多数据,但我不知道在哪里对此功能进行编程。 ¿覆盖存储库?我尝试重写 find() 方法,但它不起作用
我知道,如果我使用事件记录模式,这可以毫无问题地完成,因为我可以在构造方法或 getter 中访问数据库,等等。
但我不知道如何通过学说标准行为来做到这一点。
我相信必须有一种方法来确保统计类的每个实例都有此计算数据。
我正在使用 symfony...也许是一项服务或其他东西...
最佳答案
有多种方法可以解决您的问题。
Doctrine listener
这可能是最简单的一个。使用教义 postLoad
事件来填写 User
模型上所需的数据。
这是一种完全有效的方法,但有一些缺点:
- 每次学说从数据库获取用户实体实例时都会运行该命令。如果它获取 100 个用户的列表,它将运行 100 次。如果您在那里执行一些耗时的任务,这可能会导致性能问题。
- 它们很难调试:如果遇到错误,事件通常会使代码流变得不太清晰,从而使调试变得更加困难。如果您做简单的事情,并且不过度使用它们,那么可能没问题,否则请考虑其他选择。
抽象主义
我强烈支持这种方法,并且我几乎在每个项目中都使用它。
尽管我是尝试拥有最少必要层数和间接性的人之一,但我确实认为将数据持久性包装到您自己的服务中是一个好主意。它将系统的其余部分与您的数据如何存储隔离。
我建议不要直接使用 Doctrine 存储库/实体管理器。相反,将它们包装在您自己的服务中。
这使得您的持久性 API 非常干净和明显,同时使您能够在模型到达业务逻辑之前对其进行操作。
以下是我如何解决您的问题的示例:
# src/AppBundle/Repository/UserRepository.php
class UserRepository
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function findById($userId)
{
$user = $this->em->getRepository(User::class)->find($userId);
$this->calculateUserStatistics($user);
return $user;
}
public function save(User $user)
{
$this->em->persist($user);
$this->em->flush();
}
// ...
private function calculateUserStatistics(User $user)
{
// calculate and set statistics on user object
}
}
这种方法有很多优点:
与学说脱钩
您的业务代码不再与 Doctrine 耦合,它根本不知道 Doctrine 存储库/实体管理器的存在。如果需要,您可以更改 UserRepository
实现,以从远程 API、磁盘上的文件......从任何地方加载用户。
模型操作
它允许您在模型进入业务逻辑之前对其进行操作,从而允许您计算未作为数据库字段保留的值。例如,从 Redis、某些 API 或其他方式获取它们...
清洁 API
它使您的系统具有哪些功能变得非常明显,使理解更容易,测试也更容易。
性能优化
与第一种方法相比,它不会遇到性能问题。举个例子:
您的 User
模型上有 $eventsCount
字段。
如果您加载 100 个用户的列表并使用第一种方法,则需要触发 100 个查询来计算属于每个用户的事件数。
SELECT COUNT(*) FROM events WHERE user_id = 1;
SELECT COUNT(*) FROM events WHERE user_id = 2;
SELECT COUNT(*) FROM events WHERE user_id = 3;
SELECT COUNT(*) FROM events WHERE user_id = 4;
...
但是,如果您有自己的 UserRepository 实现,则只需创建方法 getEventCountsForUsers($userIds)
即可触发一个查询:
SELECT COUNT(*) FORM events WHERE user_id IN (:user_ids) GROUP BY user_id;
关于php - 重写原则延迟加载方法以将计算数据包含到对象中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36607604/