ZF MVC - 对象和映射器

问题描述:

I'm using ZF for an MVC application and am massively confused about how my code should be structured.

I've got a procedural application which is basically 1 huge long file with functions for everything I want my app to do.... like: getUsername($id) etc. So now I'm remaking the entire thing in ZF because my current codebase is unworkable, crap and hard to debug.

I'm new to MVC and massively confused about how it should all be laid out, what should talk to what etc. So I know about Views about being templates and Controllers needing to be skinny and that you should have fat models but I'm confused where the logic needs to be.

I'm making a game and there usual objects like.... Users, Villages, Armies, MapSquares, Resources etc.

If I was thinking about it completely by theory I would just say: 1 User Object contains many villages, each village belongs to one square and contains an army (which contains many units).

So what I thought was that my Models should contain no logic, just a list of get and set functions for retrieving the data and that the logic for processing, asking questions should be done inside the Mapper... like:

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

When I want to determine say the outcome of two villages attacking one another, where would this be done? Would I do something like:

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

Or would I have say... a battle object with a bit of logic inside it?

$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());

I have a bunch of DbTable php files, which I guess all the Database code lives in... so my question is: Should my Mapper objects ONLY really be used for things like, getting and saving to the database?

Thanks, Dom

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

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

我是MVC的新手并且大肆混淆应该如何布局,应该怎样 谈论什么等所以我知道关于模板和控制器需要瘦的观点,你应该有胖模型,但我很困惑逻辑需要的地方。 p>

我 用户,村庄,军队,MapSquares,资源等通用对象。 p>

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

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

  $ villageMapper = new VillageMapper(); 
 //使用mapper从数据库获取村庄
 $ village = $ villageMapper  - > getVillage($ id,new Village()); 
  code>  pre> 
 
 

当我想确定说两个村庄相互攻击的结果时,这将是 做了什么? 我会做类似的事情: p>

  $ outcome = $ villageMapper-> determineAttackOutcome($ village1,$ village2); 
  code>  pre> 
 \  n 

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

  $ battle = new Battle(); 
 //添加 参与者
 $ battle-> addAttacker($ village1) - > addDefender($ village2); 
 $ outcome = $ battle-> performAttack(); 
 //保存村庄变化战斗原因
 $ villageMapper  - >保存($百战> getAttacker()); 
 $的villageMapper->保存($百战> getDefender()); 
 代码>  PRE> 
 
 

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

谢谢,Dom p> div>

There are many different interpretations of MVC, but this is how I understand it:

Model: Contains virtually all the logic pertaining to a specific item. Each thing that must be modeled (in your case users, villiages, etc) has a model to go with it. The model has functions to get data out and put data in (i.e. getters and setters). The model also does error checking and such and makes sure that nothing conflicting is entered in.

View: Has no logic whatsoever. In a web application, this is literally just the thing that says where to put stuff on the page. In some frameworks you feed a view a model (i.e. ASP.NET MVC3), in other frameworks (like Savant3 for php) it can be fed anything. The controller generally feeds the view, but the if the view is given a model it just reads from the model and doesn't write to it.

Controller: Controls the interaction between the user and the model. When the user does something, the controller translates that into things that the model must do. For example, if you say to the program "Please move my character 6 spaces north", the controller will say "Is there anything to run in to 6 spaces north of here?" and if it sees the spot is clear it tells the character model "Move yourself 6 spaces north". After doing that, it will send data to the view about whatever should be displayed as a result of that. Most of the actual logic implemented in a controller should be user-model instead of model-model. The interactions between models can be either taken care of by methods in individual models or other models that encapsulate some sort of behavior or interaction.

So, on to your implementation:

I would make a battle object (which is a model) whose constructor takes two villages or whatever is fighting. It would have a method called execute or doBattle or something that the controller would call and then the battle object would perform its logic to decide the outcome and update the status of the combatants (i.e. lowering hp, giving experience, etc). It would return to the controller the result so that the controller knows what to do (i.e. if the controller needs to forget about a model because it died, it would tell it that). This return value could also be the thing sent to the view to tell the outcome of the battle.

Some of your models (such as user, village, etc) would be kept in the database and so the model would know how to map itself to that database (or it would talk to another layer that knows how to map it) and also take care the exact implementation of updating the database and stuff (the controller would call the actual method to "save", but the model would be the only thing knowing what goes on behind the scenes). Other models (such as battle) don't need to exist in the database since they are just logic encapsulating some interaction.

Having a fat model means then nearly all of the logic exists within the model.

Some sugesstions...

If you are doing Domain Driven Design (http://en.wikipedia.org/wiki/Domain-driven_design) your village object could be an aggregate root that manages the business logic of that village.

A battle could also be an aggregate root that consists of two (or more) village objects, or a service that takes in two village objects and returns an "outcome" object. You could also do something along the lines of $village->attack($anotherVillage) that could return a battle object that you may then persist.

I would suggest following Domain Driven Design and the Repository pattern when it comes to creating and persisting these business objects http://msdn.microsoft.com/en-us/library/ff649690.aspx

Datamapper should only be used for storing and retrieving data from your database and mapping that data to your domain objects (Users, Villages, Armies, MapSquares).

You could put your logic inside your domain objects, but I like to use a service layer instead.

In your controller your would do something like:

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

GameService would look like:

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);
    }

}

And finally VillageService would have:

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

So controllers talk to services only, and services talk to each other or to datamappers logically associated with them. Services host most of the "business logic" and are database independent. Datamappers are independent of services & controllers ofcourse.