ZF MVC - 对象和映射器

时间:2012-04-12 20:03:56

标签: php model-view-controller oop zend-framework

我正在使用ZF作为MVC应用程序,并且对我的代码应该如何构建感到非常困惑。

我有一个程序性的应用程序,它基本上是一个巨大的长文件,其中包含我希望我的应用程序执行的所有功能....例如:getUsername($ id)等所以现在我正在改造整个事情ZF,因为我目前的代码库不可行,废话,难以调试。

我是MVC的新手并且大量混淆了它应该如何布局,应该与什么交谈等等所以我知道关于模板和控制器的观点需要瘦,而且你应该有胖模型但是我很困惑逻辑需要在哪里。

我正在制作一款游戏,通常有像......用户,村庄,军队,MapSquares,资源等。

如果我完全按理论思考它,我会说: 1个用户对象包含许多村庄,每个村庄属于一个方格,包含一个军队(包含许多单位)。

所以我认为我的模型不应该包含任何逻辑,只需要一个用于检索数据的get和set函数列表,以及用于处理的逻辑,提问应该在Mapper中完成......如:

$villageMapper = new VillageMapper();
// Get village from database using mapper 
$village = $villageMapper->getVillage($id, new Village());

当我想确定两个村庄相互攻击的结果时,会在哪里进行?我会做点什么:

$outcome = $villageMapper->determineAttackOutcome($village1, $village2);

或者我会说......一个内部有一点逻辑的战斗对象?

$battle = new Battle();
// Add participants
$battle->addAttacker($village1)->addDefender($village2);
$outcome = $battle->performAttack();
// Save village changes cause of battle
$villageMapper->save($battle->getAttacker());
$villageMapper->save($battle->getDefender());

我有一堆DbTable php文件,我猜所有数据库代码都存在...所以我的问题是:我的Mapper对象是否真的应该用于诸如获取和保存到数据库之类的东西?

谢谢,Dom

3 个答案:

答案 0 :(得分:5)

对MVC有许多不同的解释,但这就是我理解它的方式:

模型:几乎包含与特定项目相关的所有逻辑。必须建模的每件事(在你的情况下,用户,villiages等)都有一个模型可以使用它。该模型具有将数据输出并将数据输入(即,吸气剂和设定者)的功能。该模型还进行错误检查等,并确保没有输入任何冲突。

观点:没有任何逻辑。在Web应用程序中,这实际上就是说在页面上放置内容的位置。在某些框架中,您可以在其他框架(如Savant3 for php)中为视图提供模型(即ASP.NET MVC3),它可以提供任何内容。控制器通常会提供视图,但如果给视图一个模型,它只是从模型中读取而不会写入模型。

控制器:控制用户与模型之间的交互。当用户执行某些操作时,控制器会将其转换为模型必须执行的操作。例如,如果您对程序说“请将我的角色向北移动6个空格”,控制器会说“这里有6个空格可以运行吗?”如果它看到斑点是清晰的,它会告诉角色模型“自己向北移动6个空间”。在这之后,它会将数据发送到视图中,以便显示由此产生的任何内容。在控制器中实现的大多数实际逻辑应该是用户模型而不是模型模型。模型之间的交互可以通过单个模型中的方法或封装某种行为或交互的其他模型来处理。

那么,关于你的实现:

我会制作一个战斗对象(这是一个模型),其构造函数需要两个村庄或任何正在战斗的东西。它将有一个名为execute或doBattle的方法或控制器将调用的东西,然后战斗对象将执行其逻辑来决定结果并更新战斗员的状态(即降低hp,给予经验等)。它将返回控制器结果,以便控制器知道该做什么(即如果控制器需要忘记模型,因为它死了,它会告诉它)。此返回值也可以是发送到视图的事物,以告知战斗的结果。

您的某些模型(例如用户,村庄等)将保留在数据库中,因此模型将知道如何将自身映射到该数据库(或者它将与另一个知道如何映射它的图层对话)并且还要注意更新数据库和东西的确切实现(控制器会将实际方法称为“保存”,但模型将是了解幕后发生的事情的唯一方法)。其他模型(例如战斗)不需要存在于数据库中,因为它们只是逻辑封装了一些交互。

答案 1 :(得分:1)

拥有胖模型意味着模型中几乎存在所有逻辑。

一些sugesstions ......

如果您正在进行域驱动设计(http://en.wikipedia.org/wiki/Domain-driven_design),您的村庄对象可能是管理该村庄业务逻辑的聚合根。

战斗也可以是由两个(或更多)村庄对象组成的聚合根,或者是接收两个村庄对象并返回“结果”对象的服务。您还可以按照$ village->攻击($ anotherVillage)的方式执行某些操作,这些攻击可能会返回您可能会持续存在的战斗对象。

在创建和保存这些业务对象时,我建议遵循域驱动设计和存储库模式http://msdn.microsoft.com/en-us/library/ff649690.aspx

答案 2 :(得分:1)

Datamapper应仅用于存储和检索数据库中的数据,并将数据映射到域对象(用户,村庄,军队,MapSquares)。

您可以将逻辑放在域对象中,但我喜欢使用服务层。

在您的控制器中,您可以执行以下操作:

function  attackAction() {
    $gameService->doVillageBattle($villageId1,$villageId2);
}

GameService看起来像:

doVillageBattle($villageId1,$villageId2) {
    $village1 = villageService->getById( $villageId1);
    $village2 = villageService->getById( $villageId2);

    if ($village1->getStrength() > $village2->getStrength()) {
         $village1->winBattle();
         $village2->looseBattle();
         $villageService->save($village1);
         $villageService->save($village2);
    }

}

最后,VillageService会:

function save( $village ) {
    villageMapper->save( $village );
}

因此,控制器仅与服务通信,服务相互通信或与逻辑相关的数据映射器进行通信。服务托管大多数“业务逻辑”并且与数据库无关。数据处理器独立于服务和当然的控制者。