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

spamboy's avatar

How to correctly name a method in a model?

I'm a beginner. I'm trying to understand the BD relationships . I always learned by experimental modeling the code. This is a my sample model code:

namespace App;
use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{

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

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

    public function categories()
    {
        return $this->belongsToMany('App\Category')->withTimestamps();
    }

    public function test2()
    {
        return $this->belongsToMany('App\Category')->withTimestamps();
    }
}

I have properly defined fields in the migration files. But when I use Artisan Tinker... i get results, that I do not understand.

Metod user() and test() is the same. Metod categories() and test()2 is the same.

$sample = App\MyModel::find(1);
$sample -> categories() ->get();

That above, gives me correct results. It's OK.

$sample = App\MyModel::find(1);
$sample -> test2() ->get();

That above, gives me correct results. It's OK.

This means that I can freely named the method. That's great! Until then, everything is understandable and clear. Name of method does not matter. Probably in this case, only a code inside the method is crucial.

Now I'm trying to do it with the other couple:

$sample = App\MyModel::find(1);
$sample -> user() ->get();

That above, gives me correct results. It's OK. But when I use this:

$sample = App\MyModel::find(1);
$sample -> test() ->get();

I receive an empty(?) result:

=> Illuminate\Database\Eloquent\Collection {#713
     all: [],
}

Why? I don't understand why the method name cannot be any, in this case.

0 likes
9 replies
ChristophHarms's avatar

That shouldn't be a problem, AFAIK. There must be something else wrong.

spamboy's avatar

Laravel Framework 5.4.32

See my code above. I'm trying to call exactly the same function, with just another name. This is copy paste.

There are no typos/misspelled.

This is my User cotroller:

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];


    /**
     *  User relation
     */
    public function moja_tabelas()
    {
        return $this->hasMany('App\My_table');
    }

}
Snapey's avatar

can you capture the SQL executed in both cases? it might give us a clue what is going on?

1 like
spamboy's avatar

@Snapey

> DB::enableQueryLog();
null


> $sample = App\My_tabela::find(1);
App\My_tabela {#711
    id: "1",
    user_id: "1",
    title: "Lorem Ipsum dolor",
    created_at: null,
    updated_at: null, 
}



> $sample -> user() ->get();
Illuminate\Database\Eloquent\Collection {#710
all: [
    App\User {#695
    id: "1",
    name: "Michal",
    created_at: null,
    updated_at: null, 
    },
],
}


> $sample -> test() ->get();
Illuminate\Database\Eloquent\Collection {#700
all: [], 
}


> DB::getQueryLog();
[
[ 
"query" => "select * from "my_tabela" where "my_tabela"."id" = ? limit 1",
"bindings" => [1,],
"time" => 3.61, ],
[ 
"query" => "select * from "users" where "users"."id" = ?",
"bindings" => ["1",],
"time" => 0.18, ],
[ 
"query" => "select * from "users" where "users"."id" is null",
"bindings" => [],
"time" => 0.22, ],
]                                                                                                  

I see the difference in the query, but I do not understand why. After all, a method with the same content is called:

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

public function test()
{
    return $this-> belongsTo('App\User');
}
Snapey's avatar

I have replicated the setup and get the same result.

I expect Laravel to take the column required for the relationship from the name of the class, i.e. User class in the relationship means use user_id for the foreign key name (which it does)

But it seems to get in a mess binding the value if the name of the relationship does not match.

This works;

    public function test()
    {
      return $this-> belongsTo('App\User','user_id');   
    }

But in my view should not be necessary, and is inconsistent with belongsToMany as you have found.

Do you want to raise this as an issue with eloquent, or shall I ?

Snapey's avatar

The issue is being shutdown here;

https://github.com/laravel/internals/issues/531

The people rejecting the idea don't seem to grasp the issue that the relationship name should not matter, and in other cases does not matter.

The argument is that if the relationship is test() then the column name should be test_id and not user_id

36864's avatar

The argument is that if the relationship is test() then the column name should be test_id and not user_id

By default. As you showed, you can still declare the column name to be whatever you want. The alternative would be to somehow infer the column name from the related model, which would cause more problems when you have a model with two relations to another model, such as this:

class Person extends Model
{
    public function father()
    {
        return $this->belongsTo(Person::class);
    }

    public function mother()
    {
        return $this->belongsTo(Person::class);
    }

    public function children()
    {
        $column = $this->gender === 'male' ? 'father_id' : 'mother_id;
        return $this->hasMany(Person::class, $column);
    }
}

In my (admittedly limited) experience with eloquent, I've found more cases where I take advantage of the default column names as they are (function name for belongsTo, class names for belongsToMany) than cases where I have to override column names. This is likely something that will vary greatly from case to case/person to person and either method for choosing default column names will find supporters and opponents in similar numbers.

As for consistency with belongsToMany, I'm not really bothered. I thought I cared, but the more I think it over, the more I like the current system.

Changing the way the defaults are set now would probably cause a lot of BC breaks and in the end you'd probably please about as many people as you'd piss off, so changing it doesn't sound like a good idea.

Snapey's avatar

I suppose my issue is with something like

User Model with regular users table

Post Model with posts table and user_id as FK to users.id

I cannot create a relationship on Post called author() and have it work with the defaults.

public function author()
{
    return $this->belongsTo('App\User');   // no !
}

even though the default column is user_id, and that is what I have in the table

Suddenly the name of the relationship matters

public function author()
{
    return $this->belongsTo('App\User','user_id'); // yes !
}

I'm sure it must catch a lot out that try it and then end up adding the column and then do that always, everywhere.

There is an argument that the FK column on the posts table should be author_id but that seems janky to me as I would be looking for an author model and authors table.

There is a recent discussion on 20 percent time about using a single table for multiple models and so there could actually be an Author model that points to the users table, but I'm getting a bit off the OP's original thread

Please or to participate in this conversation.