7

I'm writing my own MVC framework in PHP, just for learning purposes. It wasn't really hard to have a router/dispatcher class to call the right controller/action etc.

But now i'm at the part where i'm going to use models. Or actually, the model layer. But there's something that confuses me.

Alot of other MVC frameworks have a 'BaseModel'. I've read that this is actually bad practise, because the "Model" shouldn't be seen as another class. But as a real 'layer', which can contain things like the 'mapper' pattern or 'repository' pattern etc.

But to be honest, i don't see any advantages in that. To me, a 'BaseModel' class seems to be the fastest way to go, with the same results.

I can simply do something like:

class User extends BaseModel
{
    // the GetUserBy* could easily be something that's handled by the
    // BaseModel class, like in the Repo pattern.

    public function getUserByName ( $name )
    {
        // no error handling of any kind, just for simplicity
        return $this->db->exec("SELECT * FROM users WHERE name='".$name."'");
    }

    // $data = array
    public function saveUser ( $data )
    {
        // Make sure no extra fields are added to the array
        $user = array ( 'name' => $data['name'],
                        'address' => $data['address']);

        $this->db->autoSave ( $user );
    }
}

But if i'd go for a repository pattern then i have to create the following: Repositories Entities DAO

Entities have Aggregates to other repositories. So basically i'm manually writing out my entire database scheme to objects...

In the end, what's the difference??? Except that i probably could have saved alot of time by simply using a BaseModel class...

But why is it still considered to be a bad thing then?? It's not that the repo pattern decouples my application more then i'm doing now. Because to me, those patterns mentioned above seem to be highly overrated. It probably would only work in an application that has a shared state; Save objects locally (in the repository) and commit them later on.

That's why i think no one can really answer this...

But i'm still hoping to see a decent answer that makes me go: "ahhhh... What was i thinking....". But if not, then i'm sure about my case that the BaseModel isn't a bad thing at all and that most bloggers are just a bunch of sheeps :-)

Vivendi
  • 20,047
  • 25
  • 121
  • 196
  • 1
    looks pretty [Propel](http://www.propelorm.org/)-ish – Alp Apr 23 '12 at 15:34
  • 2
    Can you give us a link to one of these blog posts? – webbiedave Apr 23 '12 at 16:19
  • 1
    @Alp the code example? Propel is just an ORM, im not going in that direction, because i like to write queries myself. i dont reaallhate ORMs. But i rather not use them either. Some 'magic' is ok, but not too much. But thats a whole other story. – Vivendi Apr 23 '12 at 16:22
  • Yes, does look like Propel - but then I'm biased, I love Propel! I can't imagine not having a base class for a row class - at least not until traits are commonplace in PHP development. – halfer Apr 23 '12 at 16:58

4 Answers4

2

It's not that the repo pattern decouples my application more then i'm doing now

Your application is tightly coupled to SQL database components (which are, in effect, acting as your mapper). However, despite this, your design is much more like a Repository than an Active Record approach (which is likely what most of these bloggers you refer to are griping about).

Active records encapsulate not only the data, but also the database access:

$user = new User();
$user->setUsername('jane');
$user->setEmail('jane@foo.bar');
$user->save();

It's nicer to have the record objects be unaware of the persistence layer (separation of concerns). Your "base" does just that by returning arrays of user data and when those arrays are modified, they must be passed back to the user "base" for saving. You could change your naming to:

class UserRepo extends BaseRepo
{
    // user-specific repo code...
}

$userRepo = $this->getRepo('User');
$user = $userRepo->getUserByName('jane');
$user['email'] = 'jane@new.email';
$userRepo->save($user);

There's nothing wrong with having a base repo.

webbiedave
  • 48,414
  • 8
  • 88
  • 101
  • I guess you're right. It does look like a Repo pattern in some way. But i'm not using any Entity classes or Value Objects. Like i also said in my post, that feels alot like rewriting the database scheme to 'objects'. --- My 'UserRepo' simply returns arrays directly taken from SQL queries. I don't see the use of Entities/VO. Because if i'd use Entities i'm basically saying, give me my results as an array from my query, map them to my Entity object and use that to get/set data. I don't see why i should waste time on that (Entities). Any thoughts on that...? – Vivendi Apr 23 '12 at 18:10
  • Mapping your records to objects allows them all the options of OOP should you desire them (a defined structure, interfaces, type hinting, etc...). Array based is faster, uses less resources and you're able to pass them to the native PHP array functions. It's a trade-off and it's totally your call. – webbiedave Apr 23 '12 at 18:28
1

If you are trying to learn good MVC practices from PHP frameworks, then you are doing it wrong. Even the best frameworks in PHP are riddled with design mistakes and flaws.

The frameworks what have "BaseModel" usually are implementing some sort of ORM. And the most popular pattern here is ActiveRecord. It is nice for simple tables, with no relations to others (basically - glorified getters/setters). But starts to break down, when dealing with more complex structures and queries. Usually causing extensive technical debt.

The other reason, why this approach causes problem,s is that your "model" in this case has too may responsibilities. Your business logic is tightly bound to the storage, and storage is welded to the logic. As the application grows, such "models" will accumulate hacks.

And no, the "bunch of bloggers" are not sheep. They just have read books about application architecture and object oriented programming. When was last time you read a book on this subject ?

tereško
  • 58,060
  • 25
  • 98
  • 150
  • I am reading lots of contradictory stuff :). But how would you do it so you don't accumulate so much in the model? It seems you either have fat models, fat controllers, a library somewhere, stored procedures, and so on. What do you do? I have to avoid the ActiveRecord ideas because of many complex queries. AR feels like a hack and become huge. I also like SQL, which then couples me tightly. Thanks. – johnny Aug 25 '14 at 14:46
  • @johnny I think your main problems comes from having bad info about what "model" actually is. Maybe [this post](http://stackoverflow.com/a/5864000/727208) helps out a bit. – tereško Aug 25 '14 at 15:02
0

The Model class should be abstract, only defining methods without implementing them. As for your User model, you can easily write an interface GettingUsers which would have all those functions, and implement that on the User model.

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
  • 2
    this is a very bookish answer and no statement is followed up with a decent explanation why that is. Besides, if the model class only defines the methods without any implementation logic, then it should be an interface, not abstract. like i said, i knoe i could "easily" separate it into models, abstract classes, interfaces. but *what* is the benefit opposed to just a BaseModel. It klooks like you didnt even try to answer that. – Vivendi Apr 23 '12 at 16:14
  • 1
    @Vivendi - interesting question, but please be civil. Truth has been around some while, as evidenced by the rep, and you're new here. – halfer Apr 23 '12 at 16:56
  • 1
    @halfer Sorry, i hope no one took any offence to my reply. I didn't mean to be rude in anyway. I should've put certain things in my comment in a different way. – Vivendi Apr 23 '12 at 18:13
0

I wouldn't use a base model at all as most of your models won't have a uniform interface that they should conform to. You could create a base class for a number of different types of models (which is just basic object oriented programming) if you wanted to.

Overall, I believe the models are supposed to be the "loose" components that you wire together with a controller and display with one or more views. They can't really have a uniform interface because they all would do different things: some may not even talk to a persistence store, some may not be persistent, and/or some may be composed of other models.

jmkeyes
  • 3,751
  • 17
  • 20