Page 2 of 2

Posted: Wed Dec 19, 2007 2:55 am
by Maugrim_The_Reaper
Damn, you're reading my code! :)

Yeah, it's the same idea. I use those classes in relatively small projects where one or two Singletons won't break the bank. For larger systems breaking the Model class free of any Singleton reference is preferable. Doesn't matter in the Quantum_* classes since there's nothing more complicated than ActiveRecord style object->row mappings.

There are probably a million ways of handling data access. When you're more comfortable with OO and it all starts slotting together look up the Design Patterns like Data Mapper, Active Record, Row Data Gateway, etc. Active Record by itself isn't the end of the story.

Posted: Wed Dec 19, 2007 8:11 am
by matthijs
Maugrim_The_Reaper wrote:Damn, you're reading my code! :)
Of course, [s]stealing[/s] learning from the best :)
Maugrim_The_Reaper wrote: There are probably a million ways of handling data access. When you're more comfortable with OO and it all starts slotting together look up the Design Patterns like Data Mapper, Active Record, Row Data Gateway, etc. Active Record by itself isn't the end of the story.
Yes, indeed. I have read about them all, but something else I discovered is that they only start making sense when you need them for real, coding something.

Posted: Sat Dec 22, 2007 10:26 am
by matthijs
Ok, I'm still getting brain damage trying to figure out how to do this. To explain the problem, take a look at my original example:

Code: Select all

class BlogPostModel{
  function save(){
    $transaction = new pdotransaction();
    $transaction->execute('insert into autors (name) values ("henrik")');
    $transaction->execute('insert into posts (name, date) values ("some new post", "12/23/2007")');
    $transaction->execute('insert into cats (name) values ("php")');
    $transaction->commit();
  }
} 
// jcarts way
class BlogPostModel{
   function save() {
      $author = new AuthorModel('firstname', 'lastname', 'username');
      $post = new PostModel('title', 'content');
      $cat = new CatModel('4'); 

      $transaction = new pdotransaction();
      $transaction->attach($author);
      $transaction->attach($post);
      $transaction->attach($cat);

      $transaction->commit();
    }
}
However, the problem is, that it's not as simple as this. There should be quite some logic inside and between the 3 transactions. In pseudo code I need to do this:

Code: Select all

class BlogPostModel{
  function save(){
    $transaction = new pdotransaction();
    //check in author table if henrik already exists
    ....
        //if autor with name henrik does not exist yet
          $transaction->execute('insert into autors (name) values ("henrik")');
          //get autor id

        //else autor already exist
           //get autor_id

    //check in table cats if category php already exists
      //if cat already exists, 
        //get cat_id from db

      //else insert cat in db
         $transaction->execute('insert into cats (name) values ("php")');   
         //get cat_id from inserted cat

    //Now finally we're ready to insert everything in the posts table, including the ID's referencing the author and cat tables
    $transaction->execute('insert into posts (name, date, authorid, catid) values ("some new post", "12/23/2007", "3", "6")');
    // now commit every query?
    $transaction->commit();
  }
}
Of course, programming all this isn't too difficult. But I just wonder were and how I should tackle this. Seems like the BlogPostModel is more of a controller class then a model class now.

Posted: Tue Jan 01, 2008 9:05 pm
by champ
matthijs wrote:Of course, programming all this isn't too difficult. But I just wonder were and how I should tackle this. Seems like the BlogPostModel is more of a controller class then a model class now.
Although this post is several days old I'm interested in where it was going.

I've seen questions like these often and they tend to veer into the void with no reassuring answer.

As matthijs pointed out, there doesn't appear to be a clean way (excluding ORM) of dealing with multi-table inserts, updates, and deletes.

Passing independent model objects into a super save object conflicts with reality. The blog post scenario mentioned in the first post assumes that one post will have one author that will be filed under one category. The insert statements reflect this single insert per model structure. But what happens when when a blog post has several authors? What happens when a blog post needs to be inserted into more than one category? This throws join tables into the mix.

I'd like to read how folks have dealt with these more elaborate operations.

Posted: Tue Jan 01, 2008 10:19 pm
by Christopher
I think the reason this does not get neatly resolved is that the solution is to build a custom Model that deals with the specific, complex needs. As has been mentioned in the past, trying to create an ever more complex, generalized solution (like OR/M libraries) quickly runs up against the law of diminishing returns. Building a custom Model is just so much simpler that it ends up being the direction to go.

Posted: Tue Jan 01, 2008 10:46 pm
by Kieran Huggins
ORMs are fascinating. And very poorly done, thus far. I smell my next project! Something lightweight and a little wacky maybe.

Posted: Fri Jan 04, 2008 10:31 am
by matthijs
arborint wrote:I think the reason this does not get neatly resolved is that the solution is to build a custom Model that deals with the specific, complex needs. As has been mentioned in the past, trying to create an ever more complex, generalized solution (like OR/M libraries) quickly runs up against the law of diminishing returns. Building a custom Model is just so much simpler that it ends up being the direction to go.
Interesting. I think I understand what you mean.

Loosely translated to my example: I would better build a custom BlogPost model then trying to build a "cleaner" solution. I should just accept that there's some (or a lot of) logic in the methods of that BlogPost model.

So the best I can do (besides some mega-complicated ORM solution) is try to create some loosely coupled, clean models for the separate entities (author, post, category, etc), and then just accept that some other models (like the BlogPostModel) will have logic in them, will be tightly coupled to the other models, have some duplication, etc?

A related question then is how much to put in those "model" classes, and how much in the controllers. You'd say that logic goes in a controller. But on the other side, I'd like to keep my controller classes clean, without any db queries.

Posted: Fri Jan 04, 2008 2:21 pm
by Kieran Huggins
Check out some of the usage examples on http://datamapper.org - you should be able to get a feel for what logic goes in the model and what stays in the controller there.

Posted: Fri Jan 04, 2008 3:06 pm
by Christopher
I think one thing that gets forgotten is the problem that OR/M was originally meant to solve -- which is to reduce the dependency between object properties and the database schema. A lot of water has gone under the bridge in the meantime. To me, the two significant events between then and now (especially as it relates to PHP programmers) are Hibernate in Java and Ruby on Rails. Hibernate raised the feature bar to include much more database functionality that just mapping. In a reaction, RoR linked OR/M with ActiveRecord to add a convention-based RAD simplification that Hibernate had destroyed with featuritis.

Is whether either direction is exactly appropriate for the request oriented, share-everything architecture of PHP? There is a whirlwind of problems and pattern solutions here. So the real design question might be: What is the actual problem?

Posted: Fri Jan 04, 2008 4:40 pm
by Kieran Huggins
I think the problem is threefold: de-coupling from the DB back-end, managing model associations in a sane way, and giving the model intelligent validation.

Posted: Sat Jan 05, 2008 2:20 am
by matthijs
The problem is: you have a couple of tables. Writing models 1:1 for those tables and keeping the database interaction cleanly separated from the rest is easy. You don't have sql queries all over the place. But now, you have many tables and almost any query needs to get/insert data in many of them. And with some logic in the process. See my examples. Now, how do you still keep your code free of queries? Or, the other way around, how do you keep your models free from logic? If I end up with one big pile of classes so tightly coupled I might as well start procedural scripts again.

Reading Kierans response I think I'm pointing to de-coupling from the DB backend and managing associations in a sane way.

Posted: Sat Jan 05, 2008 2:39 am
by Christopher
matthijs wrote:Reading Kierans response I think I'm pointing to de-coupling from the DB backend and managing associations in a sane way.
A couple things from your post. First I think Models, whether they use OR/M or not, are still Models. That is where both the domain logic and the SQL should reside. If you find either leaking out into your Controllers or Views then you need to be aware of that. I am not saying that you can't implement Transaction Scripts that mix both -- they can be simple and handy solutions in PHP. But you need to stay aware of when things stop being simple and you need to move to clearer separations.

Second, coupling/dependency is not bad thing. In fact it is a necessity. If you are getting to "one big pile of classes so tightly coupled" then the problem is may not be solved by adding or removing OR/M. I would say take a good look at the dependencies; try to make them all one directional if possible; simplify, simplify, simplify; and if you have messy dependencies and have really thought about the problem and think the mess is probably the best solution -- then learn to love it and document clearly what other programmers will need to be aware of in dealing with this code.

Code that solves real problems is often quite horrific from an elegance point-of-view. But if it is stable and performant, and you can come back to it in a year and make changes because it follows a consistent design and there are comments for the weird parts, then it still qualifies as good code.

Posted: Mon Jan 07, 2008 9:35 am
by sike
a good pattern to solve your problem might be the unit of work (http://martinfowler.com/eaaCatalog/unitOfWork.html) which is the oop counterpart of a sql transaction.

cheers
Chris

Posted: Mon Jan 07, 2008 12:27 pm
by matthijs
I've heard that term before but not yet studied it. Will have a look.