在哪里放置与 Eloquent 无关的 SQL 查询
Posted
技术标签:
【中文标题】在哪里放置与 Eloquent 无关的 SQL 查询【英文标题】:Where to put not Eloquent related SQL queries 【发布时间】:2014-06-30 19:09:05 【问题描述】:我使用 Eloquent 来实现我的模型。它有很多方法可以更轻松地处理模型。但是,在某些情况下,我必须实现访问数据库但不返回 Eloquent 模型的功能。
例如,想象一个常见的用户模型。 Eloquent 在 User 模型的 CRUD 操作中帮助了我很多,但是如果我必须实现一个方法来返回一些关于用户的统计信息(例如,有多少总用户、多少活跃用户等)。
我应该在哪里实现这个功能?在 Eloquent 模型中,作为public static
函数,(例如User::getStats()
),或者应该为此设置不同的类。
在 Eloquent 模型上使用这些方法似乎有点不自然,因为它们与 Eloquent 无关。
【问题讨论】:
我在这种情况下使用存储库。存储库在构造函数中采用 User 模型的实例。然后我只使用 UserRepository,而不是直接使用 User。 您的存储库中有 sql 查询,对吧? 【参考方案1】:这完全取决于您,但最好决定约定并坚持下去。
我的经验是这样的:
如果它与通常由 Eloquent 模型表示的单个项目相关,则将其作为该模型上的公共静态方法执行。例如,在我当前的项目中,我有一个 Contract
模型。我需要一种可以为新合同生成合同 ID 字符串(为了与遗留系统兼容)的方法。这与单个项目(合同)有关,但出于技术原因需要与 Eloquent 模型分开生成(即它基于具有不同连接的单独数据库)。所以我创建了一个公共静态方法:public static function generateContractIdentifier($id, $salesRep)
。如果您使用存储库来访问您的数据库,则可以将其放在那里。
如果它更通用(即不绑定到 Eloquent 模型的实例),我会将其放入单独的库中。例如,在同一个应用程序中,我有一个处理打印项目的队列(工业过程)。该应用程序有一个仪表板,我需要显示当前队列状态以进行管理。为此,我创建了一个ProcessStatus
库并实现了一个方法:public function getStatus()
,它运行一个查询并将结果作为数组提供以在视图中显示。这与队列中的任何特定项目无关,因此我将其放在单独的库中。
【讨论】:
【参考方案2】:与往常一样,这取决于您的项目以及用户在其中扮演的角色。
但基本上,不,我认为构建报告的逻辑不属于用户模型。虽然它可能与用户有关,但关于 SOLID 原则,User 类应该只有一个职责,在这种情况下是处理 User 实体。
这包含获取和设置实例的属性,在一个简单的项目中,在模型上定义一些范围也可能很好,例如只选择活跃用户,例如User::getActive();
但是随着项目的增长,您应该考虑使用更具体的类。
例如,您可以将 Eloquent 功能抽象到用户存储库中。所以现在你有一个处理实体本身的操作的处理程序,比如
$userRepo->getAll();
$userRepo->getActive();
$userRepo->getInactive();
和一个用户实例的处理程序:
$user->getName();
$user->setStatus();
创建报告和统计数据是一个完全不同的主题。所以你可以有类似 UserReportBuilder
或 UserStatisticsService
的东西:
$userStats->getMostActive();
$userStats->getRegistrationsPerDay();
一个简单的例子:
// 用户存储库:
class UserRepository
protected $model = $model;
public function __construct($model)
// you pass in an instance of the actual Eloquent model
// so you have the whole power of eloquent in here
$this->model = $model;
public function getActive()
// this returns a collection of models
return $this->model->where('status', 'active')->get();
$userRepo = new UserRepo(new User);
差不多就是这样。你仍然可以使用 Eloquent,但是你已经将功能分离为具有明确责任的部分。因此,您的 UserStats 类只能用于构建用户统计信息:
class UserStats
// You could pass in the Repository through the constructor
// or just use the Eloquent model directly
public function getRegistrationsPerDay()
return User::groupBy('day')->get(
[
DB::raw('DATE(created_at) as day'),
DB::raw('count(*) as registration_count')
]
);
User 实例或 UserStats-builder 不需要知道如何获取所有用户,并且 User 实例或 UserRepository 不需要知道如何计算每天的注册量,因此将该功能拆分为单独的、独立的部分只做一件事。
我想你明白了,我希望它是有道理的。也许您应该让自己更加熟悉SOLID-principles,并在遇到此类问题时尽量记住它们。
【讨论】:
很棒的答案。实际上为我回答了更多问题。以上是关于在哪里放置与 Eloquent 无关的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章
我可以在哪里放置 SQL 代码以在 AWS Data Pipeline 中删除表?