colinmollenhour / mongodb-php-odm

A simple but powerful set of wrappers for using MongoDb in PHP (also a Kohana 3 module)
BSD 3-Clause "New" or "Revised" License
208 stars 50 forks source link

Lazy Loading and Updates? #1

Closed garyrichardson closed 14 years ago

garyrichardson commented 14 years ago

Hi,

I think I've found an issue with lazy loading. I have the following code:

#!/usr/bin/php
<?

require_once 'mongodb-php-odm/classes/json.php';
require_once 'mongodb-php-odm/classes/mongo/database.php';
require_once 'mongodb-php-odm/classes/mongo/collection.php';
require_once 'mongodb-php-odm/classes/mongo/document.php';

/*
 * Extension classes
 */

class Model_Example_Collection extends Mongo_Collection
{
    protected $name = 'examples';
    protected $db   = 'exampledb';
}

class Model_Example extends Mongo_Document
{
    protected function before_save($state)
    {
        error_log("**** At start of before_save");
        var_dump($this->_changed);

        $this->modifiedTime = time();

        error_log("**** After adding modifiedTime");
        var_dump($this->_changed);

        if(null == $this->createTime)
        {

            $this->createTime = time();
        }

        error_log("**** After checking createTime");
        var_dump($this->_changed);
    }
}

/*
 * test code
 */
$db = Mongo_Database::instance('exampledb', Array('database' => 'exampledb'));

// create a new object
error_log("*** Creating");
$newObj = new Model_Example();
$newObj->exampleName = "FooBar";
$newObj->save();
$objId = $newObj->id;
$newObj = null;

// reload it
error_log("*** Reloading with lazy load");
$reloadedObj = new Model_Example($objId);
$reloadedObj->exampleName = "Modified!";
$reloadedObj->save();
$reloadedObj = null;

// reload it
error_log("*** Reloading with forced load");
$reloadedObj = new Model_Example($objId);
$reloadedObj->load();
$reloadedObj->exampleName = "Modified! Forced Load!";
$reloadedObj->save();

And I get the following output:

*** Creating
**** At start of before_save
array(1) {
  ["exampleName"]=>
  bool(true)
}
**** After adding modifiedTime
array(2) {
  ["exampleName"]=>
  bool(true)
  ["modifiedTime"]=>
  bool(true)
}
**** After checking createTime
array(3) {
  ["exampleName"]=>
  bool(true)
  ["modifiedTime"]=>
  bool(true)
  ["createTime"]=>
  bool(true)
}
*** Reloading with lazy load
**** At start of before_save
array(1) {
  ["exampleName"]=>
  bool(true)
}
**** After adding modifiedTime
array(2) {
  ["exampleName"]=>
  bool(true)
  ["modifiedTime"]=>
  bool(true)
}
**** After checking createTime
array(0) {
}
*** Reloading with forced load
**** At start of before_save
array(1) {
  ["exampleName"]=>
  bool(true)
}
**** After adding modifiedTime
array(1) {
  ["exampleName"]=>
  bool(true)
}
**** After checking createTime
array(1) {
  ["exampleName"]=>
  bool(true)
}

So to recap:

Thanks!

colinmollenhour commented 14 years ago

I see the dilemma. However, loading an object after changes have been made without wiping out those changes could cause other problems. If you changed your before_save code to use if('insert' == $state) rather than if(null == $this->createTime) then everything should work as you intended. I don't really see a better solution, perhaps an exception should be thrown if lazy loading is triggered while unsaved changes exist to prevent this kind of confusion? Thanks for the issue report.

colinmollenhour commented 14 years ago

Closing