【问题标题】:PHP Data mapper - map multiple domain objects togetherPHP 数据映射器 - 将多个域对象映射在一起
【发布时间】:2016-10-10 04:00:31
【问题描述】:

我正在开发一个页面,用户可以在其中查看代表 Internet 流量进出网络设备端口的图形图像概览。有关这些端口的信息收集在一个表中。该表的每个端口至少包含以下列:

  • 端口号
  • 设备 ID
  • 端口名称
  • 还有更多...

设备 ID 列是另一个表的主键:设备。该表至少有以下列:

  • 设备 ID
  • 设备名称
  • 还有更多...

如您所见,这两个表之间存在设备 ID 关系。我已将这两个表都翻译为域对象“端口”和“设备”。两个域对象都由两个域映射器“PortMapper”和“DeviceMapper”填充。我需要每个端口的一个属性是我可以通过设备 ID 获得的设备名称。我的问题是如何最好地将这两个域对象映射在一起。

我的 PortMapper 的 findById() 函数如下所示:

public function findById($id, DeviceMapper $deviceMapper) {
    $ports = $this->db->sql_select('SELECT * FROM ports WHERE customer_id = ?', [$id]);

    $arrayOfPorts = [];

    foreach($ports as $port) {   
        $device = $deviceMapper->findById($port['device_id']);
        $port['device'] = $device;
        $arrayOfPorts[] = $this->createObject($port);
    }

    return $arrayOfPorts;
}

还有我的 DeviceMapper 的 findById() 函数:

public function findById($id) {
    $device = $this->db->sql_select('SELECT * FROM devices WHERE device_id = ?', [$id]);
    return $this->createObject($device);        
}

我在控制器中实例化它的方式:

$db = new Database('librenms');
$portMapper = new PortMapper($db);
$deviceMapper = new DeviceMapper($db);
$ports = $portMapper->findById($_SESSION['user']['id'], $deviceMapper);

foreach($ports as $port) {
    echo $port->getHostname();
}

我得到每个端口的设备主机名就好了。但是我实例化整个事情的方式真的很糟糕。对于两个域对象之间的关系,有什么更好的方法?

我可以做一个简单的 LEFT JOIN 查询,这样我就不需要将两个域对象映射在一起,但这不是我想去的地方。

【问题讨论】:

  • 你为什么不用像Doctrine ORM这样的ORM框架?
  • 通过编写自己的代码,我学到的不仅仅是使用像 Doctrine 这样的大型 ORM 框架。
  • 足够好。然后按照 Doctrine 或其他框架使用的模式自己实现功能。
  • 我来看看 Doctrine ORM。

标签: php oop design-patterns datamapper


【解决方案1】:

我认为你需要重组一些东西。首先,我建议您的数据映射器填充您的域对象。毕竟,这就是他们应该做的:将数据映射到对象上。此方法允许您在域对象上设置已知属性,然后在已知变量的情况下调用数据映射器“获取”其余数据。

我建议的下一件事是创建域对象集合类。这些实体集合本质上是经过美化的数组,如果正确实施,它们就可以发挥作用。这些更改将有助于生成您想要更好地映射的关系(请参见下面的代码)。此外,有了这个建议,您的映射器将承担更单一的责任,如果您愿意,则将其他关系逻辑排除在映射器之外/在帮助器类中。

下面我将说明我将如何构建此任务。首先,创建一个 PortCollection 并设置 ID 的条件。然后我们可以将 PortCollection 映射到 PortCollectionMapper。在进行必要的数据库调用后,PortCollectionMapper 将结果发送到 PortCollection,PortCollection 为获取的每一行实例化新的 Port 实例并将其添加到 PortCollection。

现在,我们可以遍历 PortCollection 并使用 DeviceMapper 填充有关设备的信息。

<?php

$portCollection = new PortCollection;
$portCollection->setId( $_SESSION['user']['id'] );

$portCollectionMapper = new PortCollectionMapper;
$portCollectionMapper->fetch( $portCollection );
//$portCollection is now populated with Port instances

$deviceMapper = new DeviceMapper;

foreach( $portCollection as $port )
{
    //create a device from the port device ID
    $device = new Device;
    $device->setId( $port->getDeviceId() );

    //populate the device with data
    $deviceMapper->fetch( $device );

    //assign the device to the port
    $port->setDevice( $device );
}

【讨论】:

  • 我认为提及fetch 正在使用按引用传递是很有用的。剩下的很好的例子。
  • 感谢这个例子。我曾考虑过使用集合,但由于某种原因无法理解。在编写这样的代码时,我应该始终牢记单一职责原则。
  • this 会是一个很好的关于处理集合的教程吗?
  • @Jeremy 我也用过你的another answer。很有帮助!
  • 是否也可以将 $portCollection 传递给 $portCollectionMapper 的构造函数而不是传递给 fetch()?
猜你喜欢
  • 1970-01-01
  • 2016-05-13
  • 2010-10-04
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多