views:

148

answers:

3

Hey,
I have been designing a site locally in PHP 5, but have come across a few design issues I'd like advice now.

Currently there are three features of the site and each feature has a class . These features are as follows :

  • a blog
  • a friends list
  • a set of images

I have a class for each but in each class I basically define a similar method that gets all [blogs | Friends | images]. I was wondering if any of you know how I could reduce these classes to be much thinner and probably have one class that is generic between all three features for all methods that are the same for each feature. (i.e getAllById($feature, $id)).

An example function for my existing blog class is as follows:

function getBlogsByUserId($userId) {
    global $db;
    $blogs = array();
    $db->where(array("userId"=>$userId));
    $rows = $db->get("blog")->fetch(0);
    foreach($rows as $row) {
 $blog = new Blog();
 $blog->id = $row['id'];
 $blog->userId = $row['userId'];
 $blog->content = $row['content'];
 $blogs[] = $blog;
    }
return $blogs;
}

Note: I have defined my own class for the DB stuff so don't worry about that.

I've looked at the gateway design pattern but haven't yet found a solution. I also want this to be reusable so if I increase the features to seven or more then I won't have to change much of the class.

Thanks, Matt

+1  A: 

Maybe you should have a look at some ORM systems like Doctrine or Propel. This will help you a lot with your database <-> object mapping.

And I know that at least Doctrine supports inheritances of tables and of course maps this structure also to a class hierarchy (which enables you to implement common methods in the parent class).

Felix Kling
A: 

You could create a parameterizeable Factory object/function. It would aggregate a 'row_to_object' function and a 'query' object:

function row_to_blog( $row ) {
    return new Blog( $row["id"], $row["title"] );
}

function create_from_query( $query, $row_to_object ) {
    $objects=array();
    foreach( $row as $db->fetch( $query ) ) {
       $objects[]=$row_to_object( $row );
    }
    return $objects;
}

$query=new Query( "blogs", new Where("userid",$id) );
$blogs=create_from_query( $query, row_to_blog );
xtofl
+1  A: 

You could create a parent class called, say, Model, like so:

abstract class Model {
  protected static $_featureTable;

  static public function getAllById($id) {
    global $db;
    $items = array();
    $db->where(array("userId"=>$userId));
    $rows = $db->get(self::$_featureTable)->fetch(0);
    foreach($rows as $row) {
      $item = self::getInstance();
      $item->setValues($row);
      $items[] = $item;
    }
    return $items;
  }

  abstract static protected function getInstance();
  abstract protected function setValues($row);
}

class Blog extends Model {
  protected static $_featureTable = 'blogs';

  protected static function getInstance() {
    $self = __CLASS__;
    return new $self();
  }

  protected function setValues($row) {
    $this->content = $row['content'];
    // etc.
  }
}

Then, to get a list of blogs:

$blogs = Blog::getAllById($id);
Lucas Oman
the only issue i have here is that for the $item->content = $row['content'] stuff, these will be different for all features, for example the image class will have a filename where as the blog will have content. Any suggestions here? Other than that, its all good thanks!
phpNutt
@Matt: updated code in response to your comment. Note the addition of the setValues() method.
Lucas Oman
Thanks Lucas! :-)
phpNutt
Hi Lucas, i have emailed you about this code you posted here, could you respond when you have a min please
phpNutt