Skip to content

Commit a039725

Browse files
[12.x] Preserve "previous" model state (#55729)
* Preserve previous model state Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * Update EloquentModelRefreshTest.php * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * Update HasAttributes.php * Update HasAttributes.php --------- Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 1badc12 commit a039725

File tree

4 files changed

+88
-5
lines changed

4 files changed

+88
-5
lines changed

src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ trait HasAttributes
6868
*/
6969
protected $changes = [];
7070

71+
/**
72+
* The previous state of the changed model attributes.
73+
*
74+
* @var array
75+
*/
76+
protected $previous = [];
77+
7178
/**
7279
* The attributes that should be cast.
7380
*
@@ -2082,6 +2089,7 @@ public function syncOriginalAttributes($attributes)
20822089
public function syncChanges()
20832090
{
20842091
$this->changes = $this->getDirty();
2092+
$this->previous = array_intersect_key($this->getRawOriginal(), $this->changes);
20852093

20862094
return $this;
20872095
}
@@ -2117,7 +2125,7 @@ public function isClean($attributes = null)
21172125
*/
21182126
public function discardChanges()
21192127
{
2120-
[$this->attributes, $this->changes] = [$this->original, []];
2128+
[$this->attributes, $this->changes, $this->previous] = [$this->original, [], []];
21212129

21222130
return $this;
21232131
}
@@ -2201,6 +2209,16 @@ public function getChanges()
22012209
return $this->changes;
22022210
}
22032211

2212+
/**
2213+
* Get the attributes that were previously original before the model was last saved.
2214+
*
2215+
* @return array
2216+
*/
2217+
public function getPrevious()
2218+
{
2219+
return $this->previous;
2220+
}
2221+
22042222
/**
22052223
* Determine if the new and old values for a given key are equivalent.
22062224
*

tests/Integration/Database/EloquentModelRefreshTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ public function testItSyncsOriginalOnRefresh()
5454
$this->assertSame('patrick', $post->getOriginal('title'));
5555
}
5656

57+
public function testItDoesNotSyncPreviousOnRefresh()
58+
{
59+
$post = Post::create(['title' => 'pat']);
60+
61+
Post::find($post->id)->update(['title' => 'patrick']);
62+
63+
$post->refresh();
64+
65+
$this->assertEmpty($post->getDirty());
66+
$this->assertEmpty($post->getPrevious());
67+
}
68+
5769
public function testAsPivot()
5870
{
5971
Schema::create('post_posts', function (Blueprint $table) {

tests/Integration/Database/EloquentModelTest.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,28 @@ public function testUserCanUpdateNullableDate()
4242
public function testAttributeChanges()
4343
{
4444
$user = TestModel2::create([
45-
'name' => Str::random(), 'title' => Str::random(),
45+
'name' => $originalName = Str::random(), 'title' => Str::random(),
4646
]);
4747

4848
$this->assertEmpty($user->getDirty());
4949
$this->assertEmpty($user->getChanges());
50+
$this->assertEmpty($user->getPrevious());
5051
$this->assertFalse($user->isDirty());
5152
$this->assertFalse($user->wasChanged());
5253

53-
$user->name = $name = Str::random();
54+
$user->name = $overrideName = Str::random();
5455

55-
$this->assertEquals(['name' => $name], $user->getDirty());
56+
$this->assertEquals(['name' => $overrideName], $user->getDirty());
5657
$this->assertEmpty($user->getChanges());
58+
$this->assertEmpty($user->getPrevious());
5759
$this->assertTrue($user->isDirty());
5860
$this->assertFalse($user->wasChanged());
5961

6062
$user->save();
6163

6264
$this->assertEmpty($user->getDirty());
63-
$this->assertEquals(['name' => $name], $user->getChanges());
65+
$this->assertEquals(['name' => $overrideName], $user->getChanges());
66+
$this->assertEquals(['name' => $originalName], $user->getPrevious());
6467
$this->assertTrue($user->wasChanged());
6568
$this->assertTrue($user->wasChanged('name'));
6669
}
@@ -73,13 +76,15 @@ public function testDiscardChanges()
7376

7477
$this->assertEmpty($user->getDirty());
7578
$this->assertEmpty($user->getChanges());
79+
$this->assertEmpty($user->getPrevious());
7680
$this->assertFalse($user->isDirty());
7781
$this->assertFalse($user->wasChanged());
7882

7983
$user->name = $overrideName = Str::random();
8084

8185
$this->assertEquals(['name' => $overrideName], $user->getDirty());
8286
$this->assertEmpty($user->getChanges());
87+
$this->assertEmpty($user->getPrevious());
8388
$this->assertTrue($user->isDirty());
8489
$this->assertFalse($user->wasChanged());
8590
$this->assertSame($originalName, $user->getOriginal('name'));
@@ -88,11 +93,15 @@ public function testDiscardChanges()
8893
$user->discardChanges();
8994

9095
$this->assertEmpty($user->getDirty());
96+
$this->assertEmpty($user->getChanges());
97+
$this->assertEmpty($user->getPrevious());
9198
$this->assertSame($originalName, $user->getOriginal('name'));
9299
$this->assertSame($originalName, $user->getAttribute('name'));
93100

94101
$user->save();
95102
$this->assertFalse($user->wasChanged());
103+
$this->assertEmpty($user->getChanges());
104+
$this->assertEmpty($user->getPrevious());
96105
}
97106

98107
public function testInsertRecordWithReservedWordFieldName()

tests/Integration/Database/EloquentUpdateTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,50 @@ public function testIncrementOrDecrementIgnoresGlobalScopes()
136136
$deletedModel->decrement('counter');
137137
$this->assertEquals(0, $deletedModel->fresh()->counter);
138138
}
139+
140+
public function testUpdateSyncsPrevious()
141+
{
142+
$model = TestUpdateModel1::create([
143+
'name' => Str::random(),
144+
'title' => 'Ms.',
145+
]);
146+
147+
$model->update(['title' => 'Dr.']);
148+
149+
$this->assertSame('Dr.', $model->title);
150+
$this->assertSame('Dr.', $model->getOriginal('title'));
151+
$this->assertSame(['title' => 'Dr.'], $model->getChanges());
152+
$this->assertSame(['title' => 'Ms.'], $model->getPrevious());
153+
}
154+
155+
public function testSaveSyncsPrevious()
156+
{
157+
$model = TestUpdateModel1::create([
158+
'name' => Str::random(),
159+
'title' => 'Ms.',
160+
]);
161+
162+
$model->title = 'Dr.';
163+
$model->save();
164+
165+
$this->assertSame('Dr.', $model->title);
166+
$this->assertSame('Dr.', $model->getOriginal('title'));
167+
$this->assertSame(['title' => 'Dr.'], $model->getChanges());
168+
$this->assertSame(['title' => 'Ms.'], $model->getPrevious());
169+
}
170+
171+
public function testIncrementSyncsPrevious()
172+
{
173+
$model = TestUpdateModel3::create([
174+
'counter' => 0,
175+
]);
176+
177+
$model->increment('counter');
178+
179+
$this->assertEquals(1, $model->counter);
180+
$this->assertSame(['counter' => 1], $model->getChanges());
181+
$this->assertSame(['counter' => 0], $model->getPrevious());
182+
}
139183
}
140184

141185
class TestUpdateModel1 extends Model

0 commit comments

Comments
 (0)