1

I bet this question has been asked already but I can't form my thought as you can see from the title, so I couldn't find anything. I am working with MVC for quite some time now and I'm pretty happy to say that when things work out good they are nearly perfect ( in my eyes ), however I never feel like I'm doing a good job at this particular task.

Say I have my model for a user, with all of its properties and methods like,

namespace Models;

class User {

    private $id;
    private $name;

    public function __get($name){
        return $this->$name;
    }

    public function setName($name){
        $this->name = $name;
        return true;
    }

    public function save(){
        // Save user to database
    }

    public function getById($id){
        // fill properties from database with id $id
    }

}

All fine all good, but then when I need to display a list of users for, say a search page or something, I always end up doing something like adding a static method getUsers or something that returns an array of \Models\User objects which just doesn't give me that "good code" feeling, hopefully you know what I mean. It gets even worse when I need to only get a couple of columns from the database, then the greater number of properties is empty and just feels like I'm messing up.

I want to ask you what is the correct way to do this?

php_nub_qq
  • 2,204
  • 4
  • 17
  • 25
  • `getById`, `getUsers` and `save` would typically be the responsibility of your [data mapper](http://martinfowler.com/eaaCatalog/dataMapper.html), not your model. If you are unfamiliar with the pattern, you could take a look at [Spot](https://github.com/vlucas/spot2). Its codebase is small enough for you to go through all of it, yet stable enough to use on production. There are several other PHP based implementations (Doctrine, Propel, etc), but their codebases are a bit on the TL;DR side. – yannis Jan 27 '15 at 14:09
  • @YannisRizos I see that you are referencing an ORM, but I think that an ORM is something I don't really need. I have no problem with writing SQL the issue is that it doesn't look clean, having a static method on a class that doesn't make perfect sense. I'm quite confused as you can see, sorry.. – php_nub_qq Jan 27 '15 at 14:15
  • What you are building is essentially an active record, which _is_ an ORM. Just a very poor one. If you're comfortable with SQL, you can hack yourself a datamapper without all the fancy query generations. You don't need them anyway. What you need to avoid your models getting fatter and fatter over time is a more sensical distribution of responsibilities. A few more details on the subject here: [Does the ActiveRecord pattern follow/encourage the SOLID design principles?](http://programmers.stackexchange.com/q/119352/25936) – yannis Jan 27 '15 at 14:23
  • (btw, my "very poor" comment above refers to the active record pattern being a poor way to map objects to a database, not to your code being poor) – yannis Jan 27 '15 at 15:03
  • @YannisRizos it's ok, I don't take offense. I still can't understand, though. You say I can build myself a data mapper, which is what I have done, but I can't figure out how to include such functionality that allows me to return many records ( possibly matching a criteria ). Like adding a static function to the class `User` still makes sense but just doesn't feel right. I'm thinking maybe design patterns are what I'm looking for but can't really find the one, I've been looking at Factory and Gateway but can't really dig into them, it's all one big mess in my head. – php_nub_qq Jan 27 '15 at 15:25
  • The inheritance trick in Hipp04's answer is a good start. With minimal code you can share generic functions (like `save`, `getAll`, `getByCriteria`) across your models. Now, the next step would be to move those functions to their own class (the mapper). – yannis Jan 27 '15 at 16:23
  • @YannisRizos I think I've figured something out, basically besides every class that maps to a table row, i create an additional class named list - for example `UserList` where I have methods of the type `getLatest`, `getFromCity` etc. where every single one accepts a page parameter which allows me to get a specific page, as well as every object has individual `resultsPerPage` property. List classes store results in an internal array and have extra methods like `push()`, `item($index)`, `items()`. This makes sense for me, but I would like to hear what you think. – php_nub_qq Jan 28 '15 at 11:16

1 Answers1

1

I don't know if this is what you're looking for but here goes.

Methods like save, get, getBy, getAll, etc, are generic and would ideally work across multiple models. For the most part, the only difference is going to be SPECIFICALLY where that data is. So why not make a super model of sorts for all your models to extend.

class Super_Model
{
    public $table; // this will be defined in the model

    public function getAll(){
        // returns all from $table
    }

    // etc
}

class User_Model extends Super_Model
{
    public function __construct()
    {
        $this->table = 'Users';
    }
}

Now you can do the following without having to define getUsers:

$user_model = new User_Model();
$users = $user_model->getAll();
Hipp04
  • 11
  • 2