Where to put Model logic methods?

Fro my projects I am using my own framework which resembles Propel ORM structure at least as far as the Model part is concerned. This basically means that each table from the database has its corresponding class and every instance of that class holds one row of data:

// creating a new user and saving it in the db:
$user = new User;
$user->username = 'lemon';
$user->status = 'new';
$user->save();

Now I use the User class as my model - a place where I put all functionalities regarding a single user. In other words I extend the base User class and add my own methods, for example:

public function changePassword($old_password, $new_password) {
    // some code here...
}

public function isOnline() {
    // some code here to check whether the user is now online
    return $isOnline;
}

// Usage:
$user->changePassword('12345', '23456');

$isOnline = $user->isOnline();

So far this is clear and probably that’s what many people are familiar with. I find this way of organizing code pretty nice.

But then I have a problem with different type of methods: those that do not work on a single user instance (data row) but affect many users or gather information about many users. For example:

deleteOldInactiveUsers();
countOnlineUsers();

I can’t put them in the User class because that class is designed to work on a single user. Propel introduced static Peer classes for that and so I have a UserPeer class with some common methods for fetching data:

$user = UserPeer::getByPK(77);  // get a User object

$users = UserPeer::doSelect($criteria);  // get a collection of User objects

For these basic fetching operations the Peer class works well. So logically I can put my new deleteOldInactiveUsers() and countOnlineUsers() methods into the UserPeer class and use:

UserPeer::deleteOldInactiveUsers();
$count = UserPeer::countOnlineUsers();

However, the problem is that these methods are static and for simple things they are enough but there are times where a lot more code is necessary and putting all the components into static methods is not that convenient. So my main question is about code organization - where would be the best place to put the deleteOldInactiveUsers() and countOnlineUsers() methods?

I have thought about a few solutions but I’m not sure which would be the best:

  1. Change UserPeer so that is has no static methods and requires an instance. However, that would require more code every time I want to do something as simple as getByPK(). Creating new instances would also mean more memory consumption - I could use a singleton the get the instance each time but that doesn’t sound very attractive either.

  2. Leave the basic fetching static methods in UserPeer class as they are (getByPK, doSelect, etc.) and create separate dedicated classes to use for more complex stuff.

  3. Put all the necessary methods in the UserPeer class and if more complex code is necessary then the static class itself uses a separate dedicated class for the task at hand. This way I always call the methods in the same way from the outside, for example: MailingMessagePeer::sendMailing() and the sendMailing static method may decide to use a dedicated class for the task.

Currently, I find it convenient to have the UserPeer class as a container for all methods that have anything to do with users generally, because I always know where this stuff is located. So when I want to send mailing messages I know that will be located in the MailingMessagePeer class: MailingMessagePeer::sendMailing(). I hope I made myself clear enough - this is a question about good code organization pracitces, I want to find a place to store methods that work on a certain type of object (e.g. User) but not on a single one but on many.

The problem is that in there are two types of model.

The domain model, which you have. This represents the state of the problem domain.

What you’re missing is the application model. This application model deals with the state of the application. Things such as “Which records are being edited?” “What is the current filter on the data being set?”

The application model is the one accessed by controllers and views. Your domain model sits behind this.

Now, the two models can be mixed. But since you have already separated out specfic domain entities it makes more sense to just add an application model.

Thanks, I didn’t know there was such a distinction between the domain and application models. This article looks like it has some good points but it’s very general and the question remains: where do I put the application model? How do I structure it in php? Maybe I’m looking too hard for some fancy solutions whereas I should simply create my own set of classes dealing with concrete application model tasks, put them in a separate directory, name them descriptively and that’s it?

The application model sits between your views (and controllers) and the domain model which you have already. The application model usually encapsulates the domain model completley. However, adding application models to an existing system may not be feasible as it might need a fundamental change to the underlying architecture, affecting (probably breaking :wink: ) the whole system.

Your best bet is, as you suggested, add application models where you need them. Allow the controller/view to access the domain model and the application model. The important thing is that the application model also has access to the domain model.

Ok, thanks for the explanation. I am building a new site so I can design the application model however I like. Should I use live objects for the application model or are static methods okay sometimes? Many tasks are simple, like counting online users, and it seems a little bit overboard to create a separate class just for that. I think the most convenient solution would be to mix them depending on the requirements and complexity of a given task.

I’m also thinking about how to organize the application model. Many tasks are clearly related to a specific domain model (db table) so it seems reasonable to organize the classes based on that (classes related to users, articles, etc.). Then there would be classes not closely related to any domain model so I would keep them separate as well.

Definitely not static application models. Why? Because it prevents you using the same MVC triad once per page.

For instance you may have a (application) Model, View and Controller dealing with the details of one specific product (maybe with an add to basket) link.

If you use static methods/properties it would be impossible to reuse that triad for a “Compare two products” type page.

The only difference between the two triads is that “productId” or whatever in the application model differs. They use the exact same code.

The application model is linked (insofar as it knows they will need some way to retrieve data) to the view and controller.

Each view needs an application model, whether that’s related to the domain model at all is irrelevant.

Tom, I think what you are writing makes sense but I don’t fully understand your point. Let me give you some sample code, I think it will be easiest to me to grasp it by examples.

By “Compare two products” type page do you mean a page which combines these two product pages by calling the two controllers, which in final effect produce the product information from their views?

The only difference between the two triads is that “productId” or whatever in the application model differs. They use the exact same code.

The thing I don’t understand it why would I have two controllers for two different products? Usually one controller will handle all product pages. Or do you mean two instances of the product controller?

So far I have been doing thing like this - first the product controller that will be responsible for the product page display:


class PorductController {
  // action called when product page is requested
  public function product($request) {
    $product = ProductPeer::getByPK($request['product_id']);
    $view = new ProductView;
    $view->setData('product', $product);

    // returned view data will be passed to the template
    return $view;
}

I know that I bypass the application model completely, because the $product (domain model object) is passed directly to the view and the view gets data straight from the domain model. The view is then obviously tied to the domain model. You are suggesting adding the application model in between - I’ve read the article from your signature so it makes sense to me (more or less). But I don’t see why this setup prevents me from reusing the MVC triad:


class PorductController {
  // product comparison page
  public function product_comparison($request) {
    $view1 = $this->product(array('product_id' => $request['id1']));
    $view2 = $this->product(array('product_id' => $request['id2']));

    $view = new ProductComparisonView;
    $view->combineProductViews($view1, $view2);
    return $view;
}

I made it up now because I wouldn’t do this myself like this. I’d rather go for this:


class PorductController {
  // product comparison page
  public function product_comparison($request) {
    $product1 = ProductPeer::getByPK($request['product_id1']);
    $product2 = ProductPeer::getByPK($request['product_id2']);
    $view = new ProductComparisonView;
    $view->setData('product1', $product1);
    $view->setData('product2', $product2);

    return $view;
}

This is reusable enough for me but probably you meant something different. If there’s something fundemantally wrong with this approach feel free to give me a link to some good resources about this.

What I was asking about was tasks like counting online users. Using static methods this could be done like this:


class Controller {
  // main page of a web site
  public function home($request) {
     $view = new HomeView;
     $view->setData('onlineUsersCount', UserAppModel::countOnlineUsers());
     // do some other stuff necessary for home page
     // ....
     return $view;
}

I invoke countOnlineUsers() statically. If you say that countOnlineUsers() should belong to the application model then I have now made the static method as part of the application model. If I make it non-static I would need to instantiate a whole class just to call a very simple function.

I’m sorry if I couldn’t fully understant your point, I seem to understand the theory but I’d like to see some code examples because I’m interested in how to organize the application model - what classes to make, how to call the needed methods, etc.

Firstly, although people will probably say I’m like a broken record, the controller extracting data from the model and passing it to the view is not really MVC and causes more issues than it solves.

Ignoring issues regarding whether the controller:view relationship should be 1:1, your problem is exactly the lack of a proper MVC model.

Introduce the application model (And give the view access to it) and all the problems you’ve encountered go away.


class Controller { 
  // main page of a web site 
  public function home($request) { 
     $view = new HomeView(new AppModel); 
     return $view; 
   }
}  


class AppModel {
	public function countOnlineUsers() {
		return $this->model->users->numOnline();
	}	
}

The view would then read directly from the model. (Application model in this case).

Online users probably isn’t a great example due to it’s simplicity, let’s use products again along with a slight restructure to decouple everything:


class ProductAppModel {
	protected $productId;

	public function setProduct($id) {
		$this->productId = $id;
	}

	public function getProduct() {
		//Ask the DOMAIN model about the product in use
		return $this->model->product->findById($this->productId);
	}

}

class ProductController {
	public function __construct(Model $model) {
		$this->model = $model;
		$this->view = $view;
	}

	public function main($id) {
		$this->model->setProduct($id);		
	}
}

class ProductView {
	public function __construct(Controller $controller, Model $model) {
		$this->controller = $controller;
		$this->model = $model;
	}

	public function output() {
		//Would probably want to introduce a basic template system at this stage
		if ($this->model->getProduct() == null) return '<em>No product selected</em>';
		else return 'Viewing product ' . $this->model->getProduct()->name;
	}
}


//In your front controller
$model = new ProductAppModel;
$controller = new ProductController($model);
$controller->main($_GET['productid']);
$view = new ProductView($controller, $model);
echo $view->output();

Hope that clears it up a little.

edit: you might also be interested in my article here

Haha, I have read your articles on MVC and I think I understand why you may feel like a broken record :D. I’ve never really bothered to do any research to check if the structure I am using is pure MVC since it works well enough - at least that’s how it seems. I picked it up at a company I used to work for where they were building large web applications using the fat controller style. At the time I was more interested in the code auto-generation to speed up tedious form building and most administrative actions creation than in MVC purity. Still this was a huge step from an almost framwork-less coding but it seems there is still a lot to improve.

Introduce the application model (And give the view access to it) and all the problems you’ve encountered go away.

This sounds tempting and exciting. Unfortunately, I’m not sure I will be able to use it fully in my nearest project because the time is pressing me and I feel that learning to implement new design patterns now will eat quite a lot of time initially - probably better to work with the sh*t I know very well than dig into something newer and potentially better but fail to get things done on time. I’ll see if I can make a better MVC implementation at least for the public site, certainly I won’t do it for the admin part which has a lot of generated code.

Thanks for the code examples, they will be of much use when I have time to try it all out. And your articles are great, they answer a lot of questions I have accumulated over time when programming. Still this article lacks code examples of application models, hence my previous questions.

Thanks!

Lemon Juice I have pretty much the same setup in my framework, and it works pretty well.
For functionality that deals with more than one row, I just make those methods static.

Ex:


$user = new User(1); # Load user id 1
$user->username = 'lemon'; # Set the name
$user->status = 'new'; # Set the status
$user->save(); # Save (deals with this user only)

$users = User::findByName('lemon'); # Find all users named lemon
$users = User::findByNameAndStatus('lemon', 'new'); # Find all users named lemon, with a status of new
$messages = Message::findByOwner($user); # Get all messages that belong to $user

You get the idea.

I find this simple because you end up having all the objects functionality in one place.
So when you work on something, you only have to worry about that one thing, and not think of any other functionality that is not directly involved in the object your working on.

One down side to this, is that your objects will be linked to each-other (ex: the findByOwner method in the Message class, will have to know about the User class).
I didn’t reach a point where this caused me problems, but I know of people complain that they can’t reuse the Message class outside the current project (where you might get messages from something else that just Users…)

So the only difference is that I use separate Peer classes for static methods but this is nothing substantial. Sometimes the classes get quite big so I think I prefer to have them separated. My main question was what do you do when your static method is not enough due to complexity of an operation. For example you have

User::findBySomeVeryComplexCriteria('lemon', 'new');

and in order to code this comfortably you would need a class with several separate methods and properties. Where do you place all that?

Another question is where do you put methods not related directly to any data object (or related to many objects) and not necessarily returning any value, for example deleteObsoleteSessions() or findCurrentUsers().

One down side to this, is that your objects will be linked to each-other (ex: the findByOwner method in the Message class, will have to know about the User class).

Instead of:

Message::findByOwner($user);

I prefer:

$user->findMessages();

I find it cleaner, are there any real differences?

I didn’t reach a point where this caused me problems, but I know of people complain that they can’t reuse the Message class outside the current project (where you might get messages from something else that just Users…)

When I have time to experiment more with frameworks I’ll try a more pure MVC implementation as TomB suggested, I’ll see how that compares to the what we use here.