Closed
Description
Laravel Version
11.22.0
PHP Version
8.3.8
Database Driver & Version
No response
Description
Method \Illuminate\Database\Eloquent\Concerns\PreventsCircularRecursion::withoutRecursion()
will crash if it is invoked from eval.
Method definition
That happens because \Illuminate\Support\Onceable::tryFromTrace()
will return null
when the second frame in the trace stack is eval
.
A more appropriate example is when the \Illuminate\Database\Eloquent\Model::toArray()
method is called on a model mocked by mockery/mockery
.
Real-world example.
Stack:
- Laravel v11.22.0
- Inertia
- Pest/PHPUnit
Our feature test:
- Arrange a mocked user and use it for authentication.
- Make an HTTP request.
- Assert
- that a method on the model is called (in our case, one of Laravel cashier's methods).
- that the server responds with an inertia component.
The exception happens when Ineria middleware tries to pass the mocked user model to the front end.
Steps To Reproduce
I prepared two Pest tests that demonstrate this bug:
test('that `Model::withoutRecursion()` method can be called using eval', function () {
$model = new class extends \Illuminate\Database\Eloquent\Model
{
public function toArray(): array
{
// Added to prevent IDE to complain about "Undefined variable '$value'" on line 25.
$result = [];
eval(<<<'EVAL'
$result = $this->withoutRecursion(
fn () => array_merge($this->attributesToArray(), $this->relationsToArray()),
fn () => $this->attributesToArray(),
);
EVAL
);
return $result;
}
};
expect($model->toArray())->toEqual([]);
});
test('that `Model::toArray()` method work on mocked models', function () {
$model = Mockery::mock(\App\Models\User::class)->makePartial();
expect($model->toArray())->toEqual([]);
});
Repo: https://github.com/sanfair/laravel-prevent-circular-recursion-bug
Commit with tests: sanfair/laravel-prevent-circular-recursion-bug@89b173c