-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[8.x] Add eloquent strict loading mode (#37363)
* add eloquent strict loading mode * stop throwing exceptions on trying to get the value of non loaded attributes * refactor * fix tests * change to public * fix tests * formatting and method naming Co-authored-by: Taylor Otwell <[email protected]>
- Loading branch information
1 parent
a1ff226
commit 12799b4
Showing
6 changed files
with
239 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
namespace Illuminate\Database; | ||
|
||
use RuntimeException; | ||
|
||
class LazyLoadingViolationException extends RuntimeException | ||
{ | ||
/** | ||
* The name of the affected Eloquent model. | ||
* | ||
* @var string | ||
*/ | ||
public $model; | ||
|
||
/** | ||
* The name of the relation. | ||
* | ||
* @var string | ||
*/ | ||
public $relation; | ||
|
||
/** | ||
* Create a new exception instance. | ||
* | ||
* @param object $model | ||
* @param string $relation | ||
* @return static | ||
*/ | ||
public function __construct($model, $relation) | ||
{ | ||
$class = get_class($model); | ||
|
||
parent::__construct("Attempted to lazy load [{$relation}] on model [{$class}] but lazy loading is disabled."); | ||
|
||
$this->model = $class; | ||
$this->relation = $relation; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
tests/Integration/Database/EloquentStrictLoadingTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?php | ||
|
||
namespace Illuminate\Tests\Integration\Database; | ||
|
||
use Illuminate\Database\Eloquent\Collection; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Database\LazyLoadingViolationException; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
/** | ||
* @group integration | ||
*/ | ||
class EloquentStrictLoadingTest extends DatabaseTestCase | ||
{ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
Schema::create('test_model1', function (Blueprint $table) { | ||
$table->increments('id'); | ||
$table->integer('number')->default(1); | ||
}); | ||
|
||
Schema::create('test_model2', function (Blueprint $table) { | ||
$table->increments('id'); | ||
$table->foreignId('model_1_id'); | ||
}); | ||
|
||
Schema::create('test_model3', function (Blueprint $table) { | ||
$table->increments('id'); | ||
$table->foreignId('model_2_id'); | ||
}); | ||
|
||
Model::preventLazyLoading(); | ||
} | ||
|
||
public function testStrictModeThrowsAnExceptionOnLazyLoading() | ||
{ | ||
$this->expectException(LazyLoadingViolationException::class); | ||
$this->expectExceptionMessage('Attempted to lazy load'); | ||
|
||
EloquentStrictLoadingTestModel1::create(); | ||
EloquentStrictLoadingTestModel1::create(); | ||
|
||
$models = EloquentStrictLoadingTestModel1::get(); | ||
|
||
$models[0]->modelTwos; | ||
} | ||
|
||
public function testStrictModeDoesntThrowAnExceptionOnAttributes() | ||
{ | ||
EloquentStrictLoadingTestModel1::create(); | ||
|
||
$models = EloquentStrictLoadingTestModel1::get(['id']); | ||
|
||
$this->assertNull($models[0]->number); | ||
} | ||
|
||
public function testStrictModeDoesntThrowAnExceptionOnEagerLoading() | ||
{ | ||
$this->app['config']->set('database.connections.testbench.zxc', false); | ||
|
||
EloquentStrictLoadingTestModel1::create(); | ||
EloquentStrictLoadingTestModel1::create(); | ||
|
||
$models = EloquentStrictLoadingTestModel1::with('modelTwos')->get(); | ||
|
||
$this->assertInstanceOf(Collection::class, $models[0]->modelTwos); | ||
} | ||
|
||
public function testStrictModeDoesntThrowAnExceptionOnLazyEagerLoading() | ||
{ | ||
EloquentStrictLoadingTestModel1::create(); | ||
EloquentStrictLoadingTestModel1::create(); | ||
|
||
$models = EloquentStrictLoadingTestModel1::get(); | ||
|
||
$models->load('modelTwos'); | ||
|
||
$this->assertInstanceOf(Collection::class, $models[0]->modelTwos); | ||
} | ||
|
||
public function testStrictModeDoesntThrowAnExceptionOnSingleModelLoading() | ||
{ | ||
$model = EloquentStrictLoadingTestModel1::create(); | ||
|
||
$this->assertInstanceOf(Collection::class, $model->modelTwos); | ||
} | ||
|
||
public function testStrictModeThrowsAnExceptionOnLazyLoadingInRelations() | ||
{ | ||
$this->expectException(LazyLoadingViolationException::class); | ||
$this->expectExceptionMessage('Attempted to lazy load'); | ||
|
||
$model1 = EloquentStrictLoadingTestModel1::create(); | ||
EloquentStrictLoadingTestModel2::create(['model_1_id' => $model1->id]); | ||
|
||
$models = EloquentStrictLoadingTestModel1::with('modelTwos')->get(); | ||
|
||
$models[0]->modelTwos[0]->modelThrees; | ||
} | ||
} | ||
|
||
class EloquentStrictLoadingTestModel1 extends Model | ||
{ | ||
public $table = 'test_model1'; | ||
public $timestamps = false; | ||
protected $guarded = []; | ||
|
||
public function modelTwos() | ||
{ | ||
return $this->hasMany(EloquentStrictLoadingTestModel2::class, 'model_1_id'); | ||
} | ||
} | ||
|
||
class EloquentStrictLoadingTestModel2 extends Model | ||
{ | ||
public $table = 'test_model2'; | ||
public $timestamps = false; | ||
protected $guarded = []; | ||
|
||
public function modelThrees() | ||
{ | ||
return $this->hasMany(EloquentStrictLoadingTestModel3::class, 'model_2_id'); | ||
} | ||
} | ||
|
||
class EloquentStrictLoadingTestModel3 extends Model | ||
{ | ||
public $table = 'test_model3'; | ||
public $timestamps = false; | ||
protected $guarded = []; | ||
} |