的确,这东西很标准。但我仍然与它斗争。
我的第一个想法是设置类似:
class Employee
{
protected $name; //etc
/**
* @var Organization
*/
protected $organization;
/**
* @var Role
*/
protected $role;
// And then getters/setters for Role and Organization
}
然后一个 EmployeeMapper 类似:
class EmployeeMapper
{
/**
* @Var DB
*/
protectd $db;
public function __construct(DB $db)
{
$this->db = $db
}
public function getEmployeesByOrganization($orgId)
{
// query here that joins employees, roles, and organizations
}
}
这让我觉得很干净,代表了你描述的结构。
但是这样做的问题是,当 EmployeeMapper 必须构造 Employee 对象时,他需要知道连接的查询结果中的角色字段和组织字段如何映射到角色和组织对象中的字段。对我来说,这些知识应该严格地存在于 RoleMapper 和 OrganizationMapper 中。因此,也许这些映射器需要将此映射功能作为公共方法提供,我们需要有一种方法将 RoleMapper 和 OrganizationMapper 实例注入到 EmployeeMapper 中以供使用。有关基于 ZF 的示例,请参阅生存深渊。
此外,似乎有时 - 如您提供的“查看员工列表”示例中 - 您希望获得有关这些附加角色和组织实体的信息。在这种情况下,加入和构建对象图的开销是合理的,并且(肯定比为角色和组织进行单独的循环查询更好)。但在其他情况下,您实际上只需要单个员工的一些简单员工信息,例如他的姓名或电话号码。在后一种情况下,为什么会产生加入和构建完整对象图的开销?
这些问题有一些架构解决方案,通常使用代理对象(代表角色和组织对象并在需要时延迟加载它们)和自定义存储库对象(您想要强制连接的地方)。
但我发现自己设计这一切是一件痛苦的事。最后,我发现像Doctrine这样的 ORM已经解决了所有问题,并为我提供了上述功能(代理、自定义存储库等)。