Skip to content

Commit 5215bf0

Browse files
committed
fix(database): reload loaded relations when using refresh
Closes #1491
1 parent 02abd4a commit 5215bf0

File tree

2 files changed

+94
-7
lines changed

2 files changed

+94
-7
lines changed

packages/database/src/IsDatabaseModel.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,20 @@ public function refresh(): self
170170
throw Exceptions\ModelDidNotHavePrimaryColumn::neededForMethod($this, 'refresh');
171171
}
172172

173-
$primaryKeyProperty = $model->getPrimaryKeyProperty();
174-
$primaryKeyValue = $primaryKeyProperty->getValue($this);
175-
176-
$refreshed = self::find(id: $primaryKeyValue)->first();
173+
$relations = [];
177174

178-
foreach (new ClassReflector($refreshed)->getPublicProperties() as $property) {
179-
if ($property->hasAttribute(Virtual::class)) {
175+
foreach (new ClassReflector($this)->getPublicProperties() as $property) {
176+
if (! $property->getValue($this)) {
180177
continue;
181178
}
182179

183-
$property->setValue($this, $property->getValue($refreshed));
180+
if ($model->isRelation($property->getName())) {
181+
$relations[] = $property->getName();
182+
}
184183
}
185184

185+
$this->load(...$relations);
186+
186187
return $this;
187188
}
188189

tests/Integration/Database/ModelsWithoutIdTest.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,55 @@ public function test_refresh_works_for_models_with_id(): void
234234
$this->assertSame('data', $mixed->another_field);
235235
}
236236

237+
public function test_refresh_works_for_models_with_unloaded_relation(): void
238+
{
239+
$this->migrate(
240+
CreateMigrationsTable::class,
241+
CreateTestUserMigration::class,
242+
CreateTestProfileMigration::class,
243+
);
244+
245+
$user = query(TestUser::class)->create(
246+
name: 'Frieren',
247+
248+
);
249+
250+
query(TestProfile::class)->create(
251+
user: $user,
252+
bio: 'Ancient elf mage',
253+
age: 1000,
254+
);
255+
256+
// Get user without loading the profile relation
257+
$userWithoutProfile = query(TestUser::class)->findById($user->id);
258+
259+
$this->assertNull($userWithoutProfile->profile);
260+
261+
// Update the user's name in the database
262+
query(TestUser::class)
263+
->update(name: 'Frieren the Mage')
264+
->where('id', $user->id->value)
265+
->execute();
266+
267+
// Refresh should work even with unloaded relations
268+
$userWithoutProfile->refresh();
269+
270+
$this->assertSame('Frieren the Mage', $userWithoutProfile->name);
271+
$this->assertSame('[email protected]', $userWithoutProfile->email);
272+
$this->assertNull($userWithoutProfile->profile); // Relation should still be unloaded
273+
274+
// Load the relation
275+
$userWithoutProfile->load('profile');
276+
277+
$this->assertInstanceOf(TestProfile::class, $userWithoutProfile->profile);
278+
$this->assertSame('Ancient elf mage', $userWithoutProfile->profile->bio);
279+
$this->assertSame(1000, $userWithoutProfile->profile->age);
280+
281+
$userWithoutProfile->refresh();
282+
283+
$this->assertInstanceOf(TestProfile::class, $userWithoutProfile->profile);
284+
}
285+
237286
public function test_load_works_for_models_with_id(): void
238287
{
239288
$this->migrate(CreateMigrationsTable::class, CreateMixedModelMigration::class);
@@ -272,6 +321,43 @@ public function test_load_with_relation_works_for_models_with_id(): void
272321
$this->assertSame('Ancient elf mage who loves magic and collecting spells', $user->profile->bio);
273322
$this->assertSame(1000, $user->profile->age);
274323
}
324+
325+
// this may be a bug, but I'm adding a test just to be sure we don't break the behavior by mistake.
326+
// I believe ->load should just load the specified relations, but it also reloads all properties
327+
public function test_load_method_refreshes_all_properties_not_just_relations(): void
328+
{
329+
$this->migrate(
330+
CreateMigrationsTable::class,
331+
CreateTestUserMigration::class,
332+
CreateTestProfileMigration::class,
333+
);
334+
335+
$user = query(TestUser::class)->create(
336+
name: 'Frieren',
337+
338+
);
339+
340+
query(TestProfile::class)->create(
341+
user: $user,
342+
bio: 'Ancient elf mage',
343+
age: 1000,
344+
);
345+
346+
$userInstance = query(TestUser::class)->findById($user->id);
347+
$userInstance->name = 'Fern';
348+
349+
query(TestUser::class)
350+
->update(email: '[email protected]')
351+
->where('id', $user->id->value)
352+
->execute();
353+
354+
$userInstance->load('profile');
355+
356+
$this->assertSame('Frieren', $userInstance->name); // "Fern" was discarded here
357+
$this->assertSame('[email protected]', $userInstance->email);
358+
$this->assertInstanceOf(TestProfile::class, $userInstance->profile);
359+
$this->assertNotNull($userInstance->profile->bio);
360+
}
275361
}
276362

277363
final class LogEntry

0 commit comments

Comments
 (0)