ZF MVC - Objects and Mappers

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

Answers


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.


Need Your Help

How to Align Text in UITextView Vertically?

iphone objective-c xcode ios5 uitextview

I have a custom cell with UITextView in it. The length of text that I'm loading to this UITextView changes from very short to very long. So please, don't say "use a label instead". I want to keep my

Favourite AJAX library for classic ASP?

ajax json asp-classic vbscript

Just wondering if there are any good server-side libraries for AJAX (prefer JSON rather then XML but anything is good) for classic ASP (VBScript)...