From 7b0e7d4ebf6a0d84075407428a66190fd989064e Mon Sep 17 00:00:00 2001 From: Hamid Date: Thu, 29 Nov 2018 16:49:16 +0330 Subject: [PATCH 1/2] use mongodb driver to check for dirtiness --- src/Jenssegers/Mongodb/Eloquent/Model.php | 19 ++++------- tests/ModelTest.php | 41 ++++++++++++++++++++++- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/Jenssegers/Mongodb/Eloquent/Model.php b/src/Jenssegers/Mongodb/Eloquent/Model.php index 6b931e468..4a68f9a7c 100644 --- a/src/Jenssegers/Mongodb/Eloquent/Model.php +++ b/src/Jenssegers/Mongodb/Eloquent/Model.php @@ -9,10 +9,12 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use Jenssegers\Mongodb\Query\Builder as QueryBuilder; +use function MongoDB\BSON\fromPHP; use MongoDB\BSON\ObjectID; use MongoDB\BSON\UTCDateTime; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Contracts\Queue\QueueableCollection; +use MongoDB\Driver\Exception\UnexpectedValueException; abstract class Model extends BaseModel { @@ -244,20 +246,11 @@ protected function originalIsEquivalent($key, $current) return false; } - if ($this->isDateAttribute($key)) { - $current = $current instanceof UTCDateTime ? $this->asDateTime($current) : $current; - $original = $original instanceof UTCDateTime ? $this->asDateTime($original) : $original; - - return $current == $original; - } - - if ($this->hasCast($key)) { - return $this->castAttribute($key, $current) === - $this->castAttribute($key, $original); + try { + return fromPHP([$current]) === fromPHP([$original]); + } catch (UnexpectedValueException $e) { + return false; } - - return is_numeric($current) && is_numeric($original) - && strcmp((string) $current, (string) $original) === 0; } /** diff --git a/tests/ModelTest.php b/tests/ModelTest.php index 4387d1231..9bfc5be83 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -528,13 +528,52 @@ public function testMultipleLevelDotNotation() public function testGetDirtyDates() { $user = new User(); - $user->setRawAttributes(['name' => 'John Doe', 'birthday' => new DateTime('19 august 1989')], true); + $user->name = 'John Doe'; + $user->birthday = new DateTime('19 august 1989'); + $user->syncOriginal(); $this->assertEmpty($user->getDirty()); $user->birthday = new DateTime('19 august 1989'); $this->assertEmpty($user->getDirty()); } + public function testGetDirty() + { + $ids = [ + new ObjectId(), + new ObjectId(), + ]; + $item = new Item([ + 'numbers' => [1, 2, 3], + 'number' => 4, + 'ids' => $ids, + 'nullable' => 'value', + 'fix' => 'fix', + ]); + $item->date = $item->fromDateTime(new DateTime('19 august 1989')); + $item->dates = [$item->fromDateTime(new DateTime('19 august 1989'))]; + $item->save(); + + $item = $item->fresh(); + + $item->numbers = [1, 2, '3']; + $item->nullable = null; + $item->new_val = 'new'; + $item->number = '4'; + $item->ids = [ + new ObjectId((string) $ids[0]), + new ObjectId((string) $ids[1]), + ]; + $item->date = $item->fromDateTime(new DateTime('19 august 1989')); + $item->dates = [$item->fromDateTime(new DateTime('19 august 1989'))]; + $this->assertEquals([ + 'numbers' => [1, 2, '3'], + 'number' => '4', + 'nullable' => null, + 'new_val' => 'new', + ], $item->getDirty()); + } + public function testChunkById() { User::create(['name' => 'fork', 'tags' => ['sharp', 'pointy']]); From 457307f1759245de75925a732367bb835d2789dc Mon Sep 17 00:00:00 2001 From: Hamid Alaei V Date: Sat, 1 Dec 2018 19:07:56 +0330 Subject: [PATCH 2/2] unset field --- src/Jenssegers/Mongodb/Eloquent/Model.php | 50 ++++++++++++++----- src/Jenssegers/Mongodb/Query/Builder.php | 13 ++++- src/Jenssegers/Mongodb/Query/UnsetField.php | 13 +++++ tests/ModelTest.php | 55 ++++++++++++++++++--- 4 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 src/Jenssegers/Mongodb/Query/UnsetField.php diff --git a/src/Jenssegers/Mongodb/Eloquent/Model.php b/src/Jenssegers/Mongodb/Eloquent/Model.php index 4a68f9a7c..8db0422af 100644 --- a/src/Jenssegers/Mongodb/Eloquent/Model.php +++ b/src/Jenssegers/Mongodb/Eloquent/Model.php @@ -9,6 +9,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use Jenssegers\Mongodb\Query\Builder as QueryBuilder; +use Jenssegers\Mongodb\Query\UnsetField; use function MongoDB\BSON\fromPHP; use MongoDB\BSON\ObjectID; use MongoDB\BSON\UTCDateTime; @@ -246,6 +247,10 @@ protected function originalIsEquivalent($key, $current) return false; } + if ($current instanceof UnsetField) { + return false; + } + try { return fromPHP([$current]) === fromPHP([$original]); } catch (UnexpectedValueException $e) { @@ -272,6 +277,38 @@ public function drop($columns) return $this->newQuery()->where($this->getKeyName(), $this->getKey())->unset($columns); } + /** + * Mark columns to be unset. + * + * @param string|string[] $columns + * + * @return $this + */ + public function unset($columns) + { + $columns = Arr::wrap($columns); + + // Mark attribute as unset + foreach ($columns as $column) { + $this->attributes[$column] = new UnsetField(); + } + + return $this; + } + + public function syncChanges() + { + $unset = array_filter($this->attributes, function ($value) { + return $value instanceof UnsetField; + }); + + foreach ($unset as $key => $value) { + unset($this->attributes[$key], $this->original[$key]); + } + + parent::syncChanges(); + } + /** * @inheritdoc */ @@ -467,17 +504,4 @@ protected function getRelationsWithoutParent() return $relations; } - - /** - * @inheritdoc - */ - public function __call($method, $parameters) - { - // Unset method - if ($method == 'unset') { - return call_user_func_array([$this, 'drop'], $parameters); - } - - return parent::__call($method, $parameters); - } } diff --git a/src/Jenssegers/Mongodb/Query/Builder.php b/src/Jenssegers/Mongodb/Query/Builder.php index a340976e3..ba16f355b 100644 --- a/src/Jenssegers/Mongodb/Query/Builder.php +++ b/src/Jenssegers/Mongodb/Query/Builder.php @@ -585,7 +585,18 @@ public function update(array $values, array $options = []) { // Use $set as default operator. if (!Str::startsWith(key($values), '$')) { - $values = ['$set' => $values]; + $changes = [ + '$set' => [], + '$unset' => [], + ]; + foreach ($values as $key => $value) { + if ($value instanceof UnsetField) { + $changes['$unset'][$key] = true; + } else { + $changes['$set'][$key] = $value; + } + } + $values = array_filter($changes); } return $this->performUpdate($values, $options); diff --git a/src/Jenssegers/Mongodb/Query/UnsetField.php b/src/Jenssegers/Mongodb/Query/UnsetField.php new file mode 100644 index 000000000..d27c0b164 --- /dev/null +++ b/src/Jenssegers/Mongodb/Query/UnsetField.php @@ -0,0 +1,13 @@ +assertInternalType('string', $array['_id']); } - public function testUnset() + public function testDrop() { $user1 = User::create(['name' => 'John Doe', 'note1' => 'ABC', 'note2' => 'DEF']); $user2 = User::create(['name' => 'Jane Doe', 'note1' => 'ABC', 'note2' => 'DEF']); - $user1->unset('note1'); + $user1->drop('note1'); - $this->assertObjectNotHasAttribute('note1', $user1); + $this->assertFalse(array_key_exists('note1', $user1->getAttributes())); $this->assertTrue(isset($user1->note2)); $this->assertTrue(isset($user2->note1)); $this->assertTrue(isset($user2->note2)); @@ -361,15 +362,57 @@ public function testUnset() $user1 = User::find($user1->_id); $user2 = User::find($user2->_id); - $this->assertObjectNotHasAttribute('note1', $user1); + $this->assertFalse(array_key_exists('note1', $user1->getAttributes())); $this->assertTrue(isset($user1->note2)); $this->assertTrue(isset($user2->note1)); $this->assertTrue(isset($user2->note2)); + $user2->drop(['note1', 'note2']); + + $this->assertFalse(array_key_exists('note1', $user2->getAttributes())); + $this->assertFalse(array_key_exists('note2', $user2->getAttributes())); + } + + public function testUnset() + { + $user1 = User::create(['name' => 'John Doe', 'note1' => 'ABC', 'note2' => 'DEF']); + $user2 = User::create(['name' => 'Jane Doe', 'note1' => 'ABC', 'note2' => 'DEF']); + + $user1->unset('note1'); + + $this->assertTrue(array_key_exists('note1', $user1->getOriginal())); + $this->assertInstanceOf(UnsetField::class, $user1->note1); + + $user1->save(); + + $this->assertFalse(array_key_exists('note1', $user1->getOriginal())); + $this->assertFalse(array_key_exists('note1', $user1->getAttributes())); + + // Re-fetch to be sure + $user1 = User::find($user1->_id); + + $this->assertFalse(array_key_exists('note1', $user1->getOriginal())); + $this->assertFalse(array_key_exists('note1', $user1->getAttributes())); + $user2->unset(['note1', 'note2']); - $this->assertObjectNotHasAttribute('note1', $user2); - $this->assertObjectNotHasAttribute('note2', $user2); + $this->assertTrue(array_key_exists('note1', $user2->getOriginal())); + $this->assertTrue(array_key_exists('note2', $user2->getOriginal())); + $this->assertFalse(array_key_exists('note3', $user2->getAttributes())); + + $this->assertInstanceOf(UnsetField::class, $user2->note1); + $this->assertInstanceOf(UnsetField::class, $user2->note2); + $this->assertFalse(array_key_exists('note3', $user2->getAttributes())); + + $user2->note3 = 'GHI'; + $user2->save(); + + $user2 = User::find($user2->_id); + $this->assertFalse(array_key_exists('note1', $user2->getAttributes())); + $this->assertFalse(array_key_exists('note2', $user2->getAttributes())); + $this->assertFalse(array_key_exists('note1', $user2->getOriginal())); + $this->assertFalse(array_key_exists('note2', $user2->getOriginal())); + $this->assertEquals('GHI', $user2->note3); } public function testDates()