tags:

views:

38

answers:

3

So, lets say I have a record:

$record = new Record();

and lets say I assign some data to that record:

$record->setName("SomeBobJoePerson");

How do I get that into the database. Do I.....

A) Have the module do it.

class Record{
    public function __construct(DatabaseConnection $database)
    {
        $this->database = $database;
    }
    public function setName($name)
    {
        $this->database->query("query stuff here");
        $this->name = $name;
    }
}

B) Run through the modules at the end of the script

class Record{
    private $changed = false;
    public function __construct(array $data=array())
    {
        $this->data = $data;
    }
    public function setName($name)
    {
        $this->data['name'] = $name;
        $this->changed = true;
    }
    public function isChanged()
    {
        return $this->changed;
    }
    public function toArray()
    {
        return $this->array;
    }
}
class Updater
{
    public function update(array $records)
    {
         foreach($records as $record)
         {
             if($record->isChanged())
             {
                 $this->updateRecord($record->toArray());
             }

         }
    }
    public function updateRecord(){ // updates stuff
    }


 }
A: 

It depends on how you plan to implement... Doing all the writes at a single point (at the end of a request) is nice because it allows you to optimize your operations by consolidating queries where possible. But to do that you have to create something similar to a UnitOfWork to keep track of whats a delete/update/insert which can open a whole other can of worms.

On the other hand if you do it directly when you call the persistence method on the entity then you dont have to worry about that quite as much.

Both approaches though mean you have to have some way to make sure you always have the current data in your object but the work required to implementation that varies in complexity with he approach you choose.

prodigitalson
A: 

Example A updates the database whenever setName is called. This function looks like a simple write accessor but it performs expensive actions when called (connecting to the database, executing a query, etc). These unintended site-effects make Example B far more appealing.

As a further example: Later on you might need a Validator class that examines a Record and ensures that the Record is in a valid state. But in order to examine the Record you must define it first by setting a name - so the Record will be persisted before you can validate it's state. Defining object state is not the same as persisting object state.

A data model approach might work better instead of a record-based approach. For instance:

class Model {

        protected $_props= array();

        public $changed= false;

        static public $models= array();

        function __set($name, $value) {
            $this->changed= true;
            $this->_props[$name]= $value;
        }

        function __construct() {
            Model::$models[]= $this;
        }

        public function save() {
            // Execute database query for saving the current Model
        }

        static public function update() {
            foreach (Model::$models as $model) {
                if ($model->changed) {
                    $model->save();
                }
            }
        }
}

A model-based solution really shines when it comes to creating different Model types. For instance:

class Person extends Model {
        public function save() {
            // Execute person-specific write operations
        }    
}

class Doctor extends Person {
        public function save() {
            // Execute all Person write operations
            parent::save();
            // Save the extra bits that belong to a doctor
        }
} 

$person1= new Person();
$person->firstname= 'Jon';
$person->lastname= 'Skeet';

$doctor1= new Doctor();
$doctor1->firstname= 'House';
$doctor1->lastname= 'MD';

// Save all modified models
Model::update();

Though I rarely find use for these kind of mass update mechanisms. Write conditions are usually more specific.

pygorex1
+1  A: 

A question you could ask yourslef is whether you want to reinvent the wheel or not. ORM layers like Propel or Doctrine already implement object to (R)DBMS mapping, so you might look at their implementation details.

Propel will use your second approach, they even keep flags on a field level to create just one update statement (which will keep database interaction at a minimum). You'll learn a lot if you study their source (or better yet, stop wasting your time and use their implementation - you won't regret it :p).

wimvds