views:

727

answers:

9

I'm creating an ORM in PHP, and I've got a class 'ORM' which basically creates an object corresponding to a database table (I'm aiming for similar to/same functionality as an ActiveRecord pattern.) ORM itself extends 'Database', which sets up the database connection.

So, I can call:

$c = new Customer();
$c->name = 'John Smith';
$c->save();

The ORM class provides this functionality (sets up the class properties, provides save(), find(), findAll() etc. methods), and Customer extends ORM. However, in the future I may be wanting to add extra public methods to Customer (or any other model I create), so should this be extending ORM or not?

I know I haven't provided much information here, but hopefully this is understandable on a vague explanation, as opposed to posting up 300+ lines of code.

+1  A: 

Yes, place your business logic in a descendant class. This is a very common pattern seen in most Data Access Layers generation frameworks.

petr k.
+2  A: 

You're certainly thinking correctly to put your business logic in a new class outside your 'ORM'. For me, instead simply extending the ORM-class, I'd rather encapsulate it with a new, value object class to provide an additional degree of freedom from your database design to free you up to think of the class as a pure business object.

Tim Mooney
A: 

You should absolutely extend the ORM class. Different things should be objects of different classes. Customers are very different from Products, and to support both in a single ORM class would be unneeded bloat and completely defeat the purpose of OOP.

Another nice thing to do is to add hooks for before save, after save, etc. These give you more flexibility as your ORM extending classes become more diverse.

Lucas Oman
A: 

Given my limited knowledge of PHP I'm not sure if this is related, but if you're trying to create many business objects this might be an incredibly time consuming process. Perhaps you should consider frameworks such as CakePHP and others like it. This is nice if you're still in the process of creating your business logic.

Russell Myers
+2  A: 

I agree with the other answers here - put the additional methods into a descendant class. I'd also add an asterisk to that though: each time you extend the class with extra methods, think about what you are trying to achieve with the extension, and think about whether or not it can be generalised and worked back into the parent class. For example:

// Customer.class.php
function getByName($name) {
    // SELECT * FROM `customer` WHERE `name` = $name
}

// ** this could instead be written as: **
// ORM.class.php
function getByField($field, $value) {
    // SELECT * FROM `$this->table` WHERE `$field` = $value
}
nickf
A: 

Nope. You should use composition instead of inheritance. See the following example:

class Customer {
    public $name;
    public function save() {
        $orm = new ORM('customers', 'id'); // table name and primary key
        $orm->name = $this->name;
        $orm->save();
    }
}

And ORM class should not extend Database. Composition again is best suited in this use case.

Michał Rudnicki
Composition is a huge no, no in OO-design.
Till
do you have any more information about why this is better than inheritance?
nickf
Inheritance is a "is" relation, whereas composition is "has" relation. Therefore it is false to state that "ORM is a Database connection". Instead "ORM has a Database connection" should be stated.
Michał Rudnicki
The example above outlines DAO pattern, which is generally more robust than Active Record. It also keeps business logic separated from persistence logic.
Michał Rudnicki
A: 

I have solved it like this in my Pork.dbObject. Make sure to check it out and snag some of the braincrunching i already did :P

class Poll extends dbObject // dbObject is my ORM. Poll can extend it so it gets all properties.
{
     function __construct($ID=false)
     {
      $this->__setupDatabase('polls', // db table
       array('ID_Poll' => 'ID', // db field => object property
         'strPollQuestion' => 'strpollquestion', 
         'datPublished' => 'datpublished', 
         'datCloseDate' => 'datclosedate', 
         'enmClosed' => 'enmclosed', 
         'enmGoedgekeurd' => 'enmgoedgekeurd'),
         'ID_Poll', // primary db key 
         $ID); // primary key value
  $this->addRelation('Pollitem'); //Connect PollItem to Poll 1;1
  $this->addRelation('Pollvote', 'PollUser'); // connect pollVote via PollUser (many:many)


     }

function Display()
{

 // do your displayíng for poll here:
    $pollItems = $this->Find("PollItem"); // find all poll items
    $alreadyvoted = $this->Find("PollVote", array("IP"=>$_SERVER['REMOTE_ADDR'])); // find all votes for current ip
}

Note that this way, any database or ORM functinoality is abstracted away from the Poll object. It doesn't need to know. Just the setupdatabase to hook up the fields / mappings. and the addRelation to hook up the relations to other dbObjects.

Also, even the dbObject class doesn't know much about SQL. Select / join queries are built by a special QueryBuilder object.

SchizoDuckie
A: 

Use PHPDoctrine :)

A: 

You're definitely thinking along the right lines with inheritance here.

If you're building an ORM just for the sake of building one (or because you don't like the way others handle things) than go for it, otherwise you might look at a prebuilt ORM that can generate most of your code straight from your database schema. It'll save you boatloads of time. CoughPHP is currently my favorite.

Bob Somers