Skip to content

Commit f06f7b3

Browse files
authored
Merge pull request #2582 from GromNaN/unset-dot
Fix `Model::unset` with dot field name
2 parents e652b0c + 58e2e28 commit f06f7b3

File tree

2 files changed

+83
-5
lines changed

2 files changed

+83
-5
lines changed

src/Eloquent/Model.php

+10-5
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,16 @@ public function originalIsEquivalent($key)
315315
*/
316316
public function offsetUnset($offset): void
317317
{
318-
parent::offsetUnset($offset);
319-
320-
// Force unsetting even if the attribute is not set.
321-
// End user can optimize DB calls by checking if the attribute is set before unsetting it.
322-
$this->unset[$offset] = true;
318+
if (str_contains($offset, '.')) {
319+
// Update the field in the subdocument
320+
Arr::forget($this->attributes, $offset);
321+
} else {
322+
parent::offsetUnset($offset);
323+
324+
// Force unsetting even if the attribute is not set.
325+
// End user can optimize DB calls by checking if the attribute is set before unsetting it.
326+
$this->unset[$offset] = true;
327+
}
323328
}
324329

325330
/**

tests/ModelTest.php

+73
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,79 @@ public function testUnsetAndSet(): void
548548
$this->assertFalse($user->isDirty());
549549
}
550550

551+
public function testUnsetDotAttributes(): void
552+
{
553+
$user = User::create(['name' => 'John Doe', 'notes' => ['note1' => 'ABC', 'note2' => 'DEF']]);
554+
555+
$user->unset('notes.note1');
556+
557+
$this->assertFalse(isset($user->notes['note1']));
558+
$this->assertTrue(isset($user->notes['note2']));
559+
$this->assertTrue($user->isDirty());
560+
$dirty = $user->getDirty();
561+
$this->assertArrayHasKey('notes', $dirty);
562+
$this->assertArrayNotHasKey('$unset', $dirty);
563+
564+
$user->save();
565+
566+
$this->assertFalse(isset($user->notes['note1']));
567+
$this->assertTrue(isset($user->notes['note2']));
568+
569+
// Re-fetch to be sure
570+
$user = User::find($user->_id);
571+
572+
$this->assertFalse(isset($user->notes['note1']));
573+
$this->assertTrue(isset($user->notes['note2']));
574+
575+
// Unset the parent key
576+
$user->unset('notes');
577+
578+
$this->assertFalse(isset($user->notes['note1']));
579+
$this->assertFalse(isset($user->notes['note2']));
580+
$this->assertFalse(isset($user->notes));
581+
582+
$user->save();
583+
584+
$this->assertFalse(isset($user->notes));
585+
586+
// Re-fetch to be sure
587+
$user = User::find($user->_id);
588+
589+
$this->assertFalse(isset($user->notes));
590+
}
591+
592+
public function testUnsetDotAttributesAndSet(): void
593+
{
594+
$user = User::create(['name' => 'John Doe', 'notes' => ['note1' => 'ABC', 'note2' => 'DEF']]);
595+
596+
// notes.note2 is the last attribute of the document
597+
$user->unset('notes.note2');
598+
$this->assertTrue($user->isDirty());
599+
$this->assertSame(['note1' => 'ABC'], $user->notes);
600+
601+
$user->setAttribute('notes.note2', 'DEF');
602+
$this->assertFalse($user->isDirty());
603+
$this->assertSame(['note1' => 'ABC', 'note2' => 'DEF'], $user->notes);
604+
605+
// Unsetting and resetting the 1st attribute of the document will change the order of the attributes
606+
$user->unset('notes.note1');
607+
$this->assertSame(['note2' => 'DEF'], $user->notes);
608+
$this->assertTrue($user->isDirty());
609+
610+
$user->setAttribute('notes.note1', 'ABC');
611+
$this->assertSame(['note2' => 'DEF', 'note1' => 'ABC'], $user->notes);
612+
$this->assertTrue($user->isDirty());
613+
$this->assertSame(['notes' => ['note2' => 'DEF', 'note1' => 'ABC']], $user->getDirty());
614+
615+
$user->save();
616+
$this->assertSame(['note2' => 'DEF', 'note1' => 'ABC'], $user->notes);
617+
618+
// Re-fetch to be sure
619+
$user = User::find($user->_id);
620+
621+
$this->assertSame(['note2' => 'DEF', 'note1' => 'ABC'], $user->notes);
622+
}
623+
551624
public function testDates(): void
552625
{
553626
$user = User::create(['name' => 'John Doe', 'birthday' => new DateTime('1965/1/1')]);

0 commit comments

Comments
 (0)