使用外部数据源实现域模型和数据映射器模式

时间:2012-08-18 01:57:17

标签: model-view-controller design-patterns frameworks datamapper domain-model

更新

好的一些更新,最后我们决定了框架(Yii)并有一些初始结构。我将粘贴一些相关代码来说明我们的当前状态: (这里只有阅读动作)

控制器

class SponsorController extends RestController
{
    public function actionRestView($id)
    {
        $sponsorMapper = new SponsorMapper(
            new Db1Adapter(), // Gateway to the external SOAP Webservice
            new Db2Adapter()  // Gateway to the external REST Webservice
        );

        $data = $sponsorMapper->read($id);

        $this->renderJson(
            array(
                'success' => true,
                'message' => 'Record Retrieved Successfully',
                'data' => $data
            )
        );
    }
}

域名模型

class Sponsor extends CModel
{
    public $id;
    public $db1Result;
    public $db2Result;

    public function attributeNames()
    {
        return array(
            'id',
            'db1Result',
            'db2Result',
        );
    }
}

数据映射器

class SponsorMapper extends Mapper
{
    public function __construct(SoapAdapter $db1Adapter,
                                RestAdapter $db2Adapter)
    {
        $this->adapters['soap'] = $db1Adapter;
        $this->adapters['rest'] = $db2Adapter;
    }

    public function read($id)
    {
        $db1Result = $this->adapters['soap']->demoRequest();
        $db2Result = $this->adapters['rest']->demoRequest();

        return $this->createEntity($db1Result, $db2Result);
    }

    protected function createEntity($db1Result, $db2Result)
    {
        $sponsor = new Sponsor();
        $sponsor->db1Result = $db1Result;
        $sponsor->db2Result = $db2Result;

        return $sponsor;
    }
}

现在我有两个问题:

  1. 现在赞助商对象的属性只是db1Result和db2Result,我会将其更改为实际属性(例如firstName,lastName,email),所以SponsorMapper :: createEntity将是这样的:

    protected function createEntity($db1Result, $db2Result)
    {
        $sponsor = new Sponsor();
        $sponsor->firstName = $db1Result->result->first_name;
        $sponsor->lastName = $db1Result->result->last_name;
        $sponsor->email = $db2Result->QueryResult->ItemObject->email;
    
        return $sponsor;
    }
    
  2. 在我看来,这些东西应该发生在域对象内而不是mapper;我知道我可以将db1Result和db2Result视为自己的域对象并创建与Sponsor域对象的关系,但我不确定这是否是正确的方向。我应该在映射器中进行吗?

    1. 我需要介绍一个缓存层,因为从外部数据库中检索数据并不快。引入缓存层的最佳位置/实践在哪里?一种方法是在控制器中,所以代码缓存层作为另一个映射器,如果这个缓存映射器不返回数据,那么我们可以很长时间从外部检索东西。但是这个解决方案意味着我需要将所有这些逻辑放在控制器操作上,也许有更好的方法来放置缓存层?
    2. 初步问题:

      我们正在PHP MVC框架之上设计/创建RESTFul API项目。该项目的目标是作为两个“外部”API(一个SOAP,另一个REST)之间的适配器。

      我认为这个项目中的模型应该大致如下:

      • 假设我们在“外部”数据库上都有一组用户数据 在他们各自的API背后,我们在本地创建了一个模型“用户”
      • 假设我们在“用户”模型中有一个“GetById”方法,这需要 to:通过id从两个外部API中获取用户数据,组合和 返回结果。
      • 我可能会在“User”模型中使用构建器模式 实例化2个其他模型(对于每个外部API),并询问那些2 模型来获取数据。有了这个结构,我可以让2个额外的 继承事物的模型需要他们与他们沟通 的API。
      • 所以我们有这些模型:

        1. 用户
        2. SOAPBuilder
        3. RESTBuilder
        4. UserSOAP
        5. UserREST

      现在我不喜欢这个设计,结构有点复杂,我不知道根据他们的“类型”将这些模型文件放到不同的地方的好方法(用户模型本身,建造者模型等)。

      我是否过度设计了这个?我应该考虑更好的模式吗?

1 个答案:

答案 0 :(得分:1)

MVC中没有“多个模型”。模型是两层之一(连同表示层),它构成了MVC设计模式。人们通常所说的“模特”实际上是domain objects。您可能会发现this相关。

那就是说,你正在以错误的方式看待这个问题。您目前拥有的是active record模式的变体。在这种情况下,存储介质不是数据库,而是REST API和/或SOAP接口,而不是传统的SQL存储。

在这种情况下,最好的选择是将域对象(例如:User)与存储相关逻辑的不同元素分开。我个人更喜欢为此实施data mappers。基本上,如果你有一个域对象,你将它传递给mapper的方法,然后从该对象检索信息并将其发送到存储或从存储中检索数据并将其应用于该域对象。

User实例并不关心它是否保存。它对域逻辑没有影响。