Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Sturm's avatar
Level 5

putJson() results in "No query results for model"

Modifying a tutorial from Laravel Daily, I have two models, User and Vehicle, that share a many-to-many relationship through the user_vehicle table. This is done because it's possible that two (or more) users can be listed as drivers of the same vehicle. And, of course, they could be drivers of more than one vehicle.

I have a partial test built that creates one of each, attaches them to each other, and then attempts to call an endpoint to update the Vehicle. However, it never even hits the endpoint and, instead, I get a "No query results for model" error message in the response.

Here's the test in question. It doesn't assert anything just yet because I cannot even get to that point; I'm just logging out the content of the response:

    public function testUserCanUpdateTheirVehicle()
    {
        $user = User::factory()->create();
        $vehicle = Vehicle::factory()
            ->hasAttached($user)
            ->create();

        $response = $this->actingAs($user)->putJson('/api/v1/vehicles/' . $vehicle->id, [
            'plate_number' => 'AAA123',
        ]);

        var_dump($response->getContent());

The content of the response:

string(13771) "{
    "message": "No query results for model [App\Models\Vehicle] 1",
    "exception": "Symfony\Component\HttpKernel\Exception\NotFoundHttpException",
    "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
    "line": 408,
    "trace": [
[...]

The error seems to happen on the line where I am attempting to call the endpoint using a putJson() method while actingAs() the user. The endpoint in my API's router:

    Route::apiResource('vehicles', VehicleController::class);

There's no point in my posting the update() controller method in question because, as far as I can tell, the test never even goes into it.

Is my syntax wrong on that line of the test? Did I forget something?

0 likes
12 replies
Sturm's avatar
Level 5

Certainly. There's a bit more to it than just a Controller, so I'll post the relevant bits. The weird part is that it doesn't appear to even touch the update method because the var_dumps that I dropped in there never appear in phpunit's output.

Regardless, here's the update method in the controller:


    public function update(StoreVehicleRequest $request, Vehicle $vehicle)
    {
        var_dump("Vehicle Update");
        $vehicle->update($request->validated());
        var_dump("updated: ", $vehicle);

        return response()->json(VehicleResource::make($vehicle), Response::HTTP_ACCEPTED);
    }

If it helps, here is the StoreVehicleRequest:

class StoreVehicleRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'plate_number' => 'required',
            'description' => 'string|nullable'
        ];
    }

    public function authorize(): bool
    {
        return true;
    }
}

And the VehicleResource:

class VehicleResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'plate_number' => $this->plate_number,
            'description' => $this->description,
        ];
    }
}
PovilasKorop's avatar

Pleasure that you're trying out the tutorial from our LaravelDaily!

If the model is not found with route model binding, it doesn't even go to controller, that's why var dump doesn't show anything.

It's just that the database doesn't have the vehicle with $vehicle->id you're providing. Hard to tell why, factory create didn't work? Have you tried dd() after it?

Sturm's avatar
Level 5

@PovilasKorop Thanks for responding to this issue!

So, I had a similar thought and dumped out the results in the test method right after instantiating the $user and $vehicle, as well as to make sure the pivot table was attaching them, before the putJson() line.

        var_dump("vehicle id: ", $vehicle->id);
        var_dump("vehicle plate: ", $vehicle->plate_number);
        var_dump("vehicle desc: ", $vehicle->description);
        var_dump("vehicle first user: ", $vehicle->users()->first()->name);
        var_dump("user name: ", $user->name);

And, indeed, it was.

string(12) "vehicle id: "
int(1)
string(15) "vehicle plate: "
string(4) "H845"
string(14) "vehicle desc: "
string(42) "Iusto laboriosam molestiae et veniam sunt."
string(20) "vehicle first user: "
string(19) "Hershel Pollich III"
string(11) "user name: "
string(19) "Hershel Pollich III"
string(13771) "{
    "message": "No query results for model [App\Models\Vehicle] 1",
[...]
Sturm's avatar
Level 5

UPDATE:

After further testing with a colleague, we discovered that the Vehicle is being persisted to the database, but Eloquent, for whatever reason, cannot seem to find it. I added the following two lines to the test:

        var_dump("QueryBuilder vehicles: ", DB::table('vehicles')->get());
        var_dump("Eloquent vehicles: ", Vehicle::all());

And that resulted in:

string(23) "QueryBuilder vehicles: "
object(Illuminate\Support\Collection)#2638 (2) {
  ["items":protected]=>
  array(1) {
    [0]=>
    object(stdClass)#2667 (5) {
      ["id"]=>
      int(1)
      ["plate_number"]=>
      string(4) "A785"
      ["description"]=>
      string(41) "Nulla et molestiae recusandae dolorem et."
      ["created_at"]=>
      string(19) "2023-05-11 20:45:28"
      ["updated_at"]=>
      string(19) "2023-05-11 20:45:28"
    }
  }
  ["escapeWhenCastingToString":protected]=>
  bool(false)
}
string(19) "Eloquent vehicles: "
object(Illuminate\Database\Eloquent\Collection)#2623 (2) {
  ["items":protected]=>
  array(0) {
  }
  ["escapeWhenCastingToString":protected]=>
  bool(false)
}

What would cause Query Builder to find the DB entry, but Eloquent to fail?

As if that weren't enough, when I do the same thing for the User model, Eloquent succeeds.

My only guess is that might have something to do with the VehicleObserver, but I've tried removing that and got the same result.

Any other thoughts?

PovilasKorop's avatar

@Sturm very weird. I can try to help you debugging it if you put it on github and invite me, username PovilasKorop

Sturm's avatar
Level 5

@PovilasKorop Thank you for that extremely generous offer, Povilas; I have invited you. The user-vehicle branch contains the WIP changes making those two tables many-to-many and the testing frustrations it has caused.

PovilasKorop's avatar
Level 11

@Sturm found it. You forgot to change the Global scope, so it's trying to search for a vehicle with user_id field which isn't filled anymore:

app/Models/Vehicle.php:

class Vehicle extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope('user', function (Builder $builder) {
            $builder->where('user_id', auth()->id());
        });
    }

1 like
Sturm's avatar
Level 5

@PovilasKorop Thank you for finding that. I feel rather silly that I overlooked that global scope while I was going through the code to find the problem.

I'm probably going to feel even more silly when you suggest the proper way to change it because my first instinct of changing the where() clause to whereRelation() still gives 0 results in the Eloquent query:

static::addGlobalScope('user', function (Builder $builder) {
    $builder->whereRelation('users', 'users.id', auth()->id());
});

Should I just remove the scope altogether?

PovilasKorop's avatar

@Sturm I'm not sure if whereRelation works for many to many, I think you need to use whereHas here

Sturm's avatar
Level 5

@PovilasKorop The funny thing is, I tried that as well and got the same result.

static::addGlobalScope('user', function (Builder $builder) {
    $builder->whereHas('users', function (Builder $query) {
        $query->where('users.id', auth()->id());
    });
});

Unless, of course, I'm not using whereHas() correctly in this case.

Sturm's avatar
Level 5

Let me wipe this egg off my face…

So, the real reason why the Eloquent query was returning 0 results while the Query Builder was returning the correct result is because I was using the Eloquent query without a logged-in user context:

var_dump("Eloquent vehicles: ", Vehicle::all());

So, naturally, the global scope returned NULL for the user()->id() and, therefore, resulted in 0 vehicles.

Povilas's global scope catch was absolutely correct and was the only thing that needed to be edited. Also, as it turns out, both the whereHas() and the whereRelation() approaches work just fine. I'll use the latter for brevity.

Thanks again, @povilaskorop!

Please or to participate in this conversation.