Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Feature/save only changes #41

Merged
merged 3 commits into from

2 participants

@chrsm

Hello, good tidings, and all that fun stuff!

I apologize in advance for borking the commits (merge into master from ... yadda), I tried to squash them into one and apparently I am not more of a git than git expects. But I digress.

Prior to now, Object::save() called Storage::save(), which ended up calling insert() no matter what.

I added functionality to update, as well as changed the Object::__getData method to accept a param that only returns 'new' or 'dirty' data.

When Storage::update() is called, it gets all the new or changed data, and sends it off to MongoDB using $set.

The unfortunate side effect of this is that embedded documents do not use $push or $pull. I will be working on that in the future.

chrsm added some commits
chrsm [FEATURE] $set - Saving only changes.
This needs a little bit of work - Embedded data will update the
whole property and not just $push or $pull - I will work something
out for this.

Changes:
	Object::__getData - new param, $whereNew. Tells __getData
	to only return properties that have changed or are new.
	Unfortunately, for collections (composeMany, etc) anything
	added will cause the whole collection to be updated
	as well, which is something I need to work on.

	Storage::update - Not just an alias for insert() now.
	Gets all changed or new data from an object and sends it to
	MongoDB over $set.
2e24a7b
chrsm [FEATURE] Save only changes on update using 34ac11d
chrsm Merge branches 'master' and 'feature/save-only-changes' 18cf4e2
@a-musing-moose

Hi Chris,

Thanks for the pull request. I am not sure if these changes are necessary. The save function in storage kinda does it already. It checks the status and then either inserts, update, or if the status is clean it does nothing.

What this feature really is asking for is the ability to only update those properties of an object that have changed since it was retrieved form the db.

e.g.

start with: {_id: 123, 'a': 'a', 'b': 'b'}
end with: {_id: 123, 'a': 'c', 'b': 'b'}

This would eventually product a update such as:

{ $set : { 'a' : 'c' } }

i.e. only the fields which have changed get pushed.

I think this means that we would need to move the status to a per-property thing and then the _getData() function would have a flag similar to what you have done.

e.g.

public function _getData($changedOnly=false)

This should return an associate array containing only those properties which have changed.

Thanks again for your interesting in Morph,
Jon

@chrsm

That's actually exactly what this does. It only saves the fields that have been changed after the retrieval of an object. It only uses $set if an object has an id (i.e., has been saved).

The status is on a per-property basis, as each property is checked for whether or not it is dirty or new. Perhaps I'm missing something here, or I messed up the commits a bit too much trying to squash them.

@a-musing-moose
@chrsm

No problemo at all.

Unfortunately, I cannot re-open this pull request, but I can submit another if you'd like. Ideally, I'd figure out how to squash these commits properly, but apparently git does not like me.

@a-musing-moose

Huzzah! Apparently I can reopen it. So thanks for the pull request and for correcting me :)

Cheers Chris.

@a-musing-moose a-musing-moose merged commit f464e83 into a-musing-moose:master
@chrsm chrsm deleted the chrsm:feature/save-only-changes branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 11, 2012
  1. [FEATURE] $set - Saving only changes.

    chrsm authored
    This needs a little bit of work - Embedded data will update the
    whole property and not just $push or $pull - I will work something
    out for this.
    
    Changes:
    	Object::__getData - new param, $whereNew. Tells __getData
    	to only return properties that have changed or are new.
    	Unfortunately, for collections (composeMany, etc) anything
    	added will cause the whole collection to be updated
    	as well, which is something I need to work on.
    
    	Storage::update - Not just an alias for insert() now.
    	Gets all changed or new data from an object and sends it to
    	MongoDB over $set.
  2. [FEATURE] Save only changes on update using

    chrsm authored
This page is out of date. Refresh to see the latest.
View
27 src/morph/Object.php
@@ -129,24 +129,37 @@ public function __setData(array $data, $state = Enum::STATE_DIRTY)
/**
* Gets the property data for this object
*
+ * @param boolean $whereNew Whether or not to only get dirty/new properties.
* @return array
*/
- public function __getData()
+ public function __getData($whereNew = false)
{
$data = array();
if (!is_null($this->id)) {
$data['_id'] = $this->id;
}
$data['_ns'] = \get_class($this);
- foreach($this->propertySet as $property) {
- $storageName = $this->propertySet->getStorageName($property->getName());
- $data[$storageName] = $property->__getRawValue();
+ foreach ($this->propertySet as $property) {
+ $storageName = $this->propertySet->getStorageName($property->getName());
+
+ if (!$whereNew) {
+ $data[$storageName] = $property->__getRawValue();
+ } else {
+ $state = $property->getState();
+
+ if ($state === \morph\Enum::STATE_DIRTY || $state === \morph\Enum::STATE_NEW) {
+ $data[$storageName] = $property->__getRawValue();
+ }
+ }
}
+
return $data;
}
/**
- * @return \morph\PropertSet
+ * Returns the PropertySet for this object
+ *
+ * @return \morph\PropertySet
*/
public function __getPropertySet()
{
@@ -158,6 +171,8 @@ public function __getPropertySet()
// ********************** //
/**
+ * Gets a property by name if it exists. Issues an E_USER_WARNING if it does not exist.
+ *
* @param $propertyName
* @return mixed
*/
@@ -173,6 +188,8 @@ public function __get($propertyName)
}
/**
+ * Sets a property by name and value
+ *
* @param string $propertyName
* @param string $propertyValue
* @return \morph\Object
View
13 src/morph/PropertySet.php
@@ -77,7 +77,12 @@ public function __setRawPropertyValue($name, $value, $state = null)
}
$this[$name]->__setRawValue($value, $state);
}
-
+
+ /**
+ * Gets the current state for the entire property set
+ *
+ * @return string A string that matches to a constant in \Morph\Enum
+ */
public function getState()
{
$state = \morph\Enum::STATE_NEW;
@@ -104,7 +109,7 @@ public function getState()
return $state;
}
-
+
/**
* Sets a storage alias for the named property
*
@@ -156,7 +161,7 @@ private function reverseStorageName($storageName)
*/
public function append($object)
{
- throw new \RuntimeException("Appending to PropertySet is not supported");
+ throw new \RuntimeException("Appending to morph\\PropertySet is not supported");
}
/**
@@ -184,7 +189,7 @@ public function offsetSet($offset, $object)
private function checkType($object)
{
if (!\is_object($object)) {
- throw new \InvalidArgumentException('value if not and object that extends Morph_Property_Generic');
+ throw new \InvalidArgumentException('value if not and object that extends morph\\property\\Generic');
}
if(!($object instanceof \morph\property\Generic)){
View
43 src/morph/Storage.php
@@ -160,8 +160,8 @@ public function save(Object $object)
/**
* Inserts a new object into the database
*
- * @param \morph\Object $object
- * @param array $options
+ * @param \morph\Object $object
+ * @param array $options
* @return \morph\Object
*/
private function insert(Object $object, array $options = array())
@@ -174,7 +174,9 @@ private function insert(Object $object, array $options = array())
'_id' => new \MongoId()
);
$data = \array_merge($id, $data);
- }
+ } else {
+ throw new \InvalidArgumentException('Cannot insert an object with an id already');
+ }
$options = array_merge(array('safe'=>$this->useSafe), $options);
@@ -188,18 +190,41 @@ private function insert(Object $object, array $options = array())
/**
* Updates object in the database
*
- * @param Morph_Object $object
- * @return Morph_Object
+ * @param morph\Object $object
+ * @param array $options
+ * @return morph\Object
*/
- private function update(Object $object)
+ private function update(Object $object, array $options = array())
{
- return $this->insert($object);
+ // get "dirty" or "new" data
+ $data = $object->__getData(TRUE);
+
+ // make sure we have an id
+ if(is_null($object->id())) {
+ throw new \InvalidArgumentException("Cannot update an object that has yet to be inserted");
+ } else {
+ // remove the id from the $set process
+ unset($data['_id']);
+ }
+
+ // criteria can generally be the id of the document
+ $query = array('_id' => $object->id());
+
+ $options = array_merge(array('safe' => $this->useSafe, 'multiple' => false), $options);
+
+ $data = array('$set' => $data);
+
+ $savedOk = $this->db->selectCollection($object->collection())->update($query, $data, $options);
+ if($savedOk) {
+ $object->__setData($data, Enum::STATE_CLEAN);
+ }
+ return $object;
}
/**
* Deletes the object passed in from the database
- * @param Morph_Object $object
+ * @param morph\Object $object
* @return boolean
*/
public function delete(Object $object)
@@ -215,7 +240,7 @@ public function delete(Object $object)
*
* @param Object $object Required to determine the correct collection query against
* @param IQuery $query
- * @param bool $safe
+ * @param bool $safe
* @return bool
*/
public function deleteByQuery(Object $object, IQuery $query = null, $safe = null)
Something went wrong with that request. Please try again.