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:
-
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.
-
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.
-
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.