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

kgp43's avatar
Level 2

How to do relationship query of a model to a model

Hi,

I got 3 models : Configurator, Motor and MotorSize.

Motor can be added to Configurator using BelongsTo. MotorSize can be added to Motor using BelongsTo.

The relations above works nice (i have added some tables below).

The problem is: I need to get all motors that have a MotorSize property/column named "mounting" with a value of "B14" (not sure if the terminology is correct)

I have tried different things, but nothing works. This is my latest attempt:

$motor = Motor::query()
    ->whereHas('motor_size_id', function (Builder $query) {
        $query->where('mounting', 'like', '%B14');
    })->first();

I receive this error:

Call to undefined method App\Motor::motor_size_id()

Maybe these tables will help to understand what i'm trying to do :)

        Schema::create('configurators', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('motor_id');
            $table->string('gear_id');
            $table->timestamps();
        });

        Schema::create('motors', function (Blueprint $table) {
            $table->increments('id');
            ...... bla bla
            $table->string('motor_size_id');
            ..... bla bla
            $table->timestamps();
        });

        Schema::create('motor_sizes', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name')->unique();
            $table->string('framesize'); // E.g. 80
            $table->string('mounting'); // E.g. B14
            $table->timestamps();
        });

0 likes
7 replies
tykus's avatar
tykus
Best Answer
Level 104

You need to have defined a relationship between Motor and MotorSize, e.g.

public function motorSize()
{
    return $this->belongsTo(MotorSize::class, 'motor_size_id');
}

Now, using that relationship name in the whereHas method:

$motor = Motor::whereHas('motorSize', function (Builder $query) {
    $query->where('mounting', 'like', '%B14');
})->first();
1 like
mstrauss's avatar

Hi @kgp43

Try this:

$motor = Motor::whereHas('motor_size', function (Builder $query) {
        $query->where('mounting', 'like', '%B14');
    })->get();

The problem with your initial query was that you used motor_size_id in the whereHas method. And motor_size_id is not a valid model with a relationship to Motor. Also, because you want all instances I used the get method not the first method.

kgp43's avatar
Level 2

Hi @tykus ,

Thanks for the reply.

I already got this relationship in my Motor model:

    public function MotorSize()
    {
        return $this->belongsTo('App\MotorSize');
    }

What is the difference between this one and the one you posted?

tykus's avatar

There is no difference. You need to use the relationship name as the first argument to whereHas:

$motor = Motor::whereHas('MotorSize', function (Builder $query) {
    $query->where('mounting', 'like', '%B14');
})->first();
kgp43's avatar
Level 2

@tykus

I have tried to run your code, but receive this error:

Argument 1 passed to App\Http\Controllers\ConfiguratorController::App\Http\Controllers\{closure}() must be an instance of App\Http\Controllers\Builder, instance of Illuminate\Database\Eloquent\Builder given, called in /home

I modified my relationship in my Motor model, as suggested:

    public function MotorSize()
    {
        return $this->belongsTo(MotorSize::class, 'motor_size_id');
    }

Used Google and found this related to the error: https://stackoverflow.com/questions/45330626/laravel-argument-1-passed-to-hasoneormanysave-must-be-an-instance-of-model-a

They tell to pass an array objects to the method.

Not sure how to do that and if that will fix it.

tykus's avatar

You need to alias the Eloquent Builder in your Controller, because it is type-hinted in the Closure:

use Illuminate\Database\Eloquent\Builder;
kgp43's avatar
Level 2

Ahh... that was it! Works now :D

Thanks for your help!

Please or to participate in this conversation.