Inferred Foreign Keys

How Eloquent Infers Foreign Keys

Every relationship method takes optional key arguments, and Eloquent guesses each one you omit. The guess depends on which side of the key the model sits on, and mixing up the rules is the usual reason a relationship returns nothing:

Where Eloquent's default key names come from
Relationship Key guessed from Shop example
hasOne, hasMany declaring class + _id orders.customer_id
belongsTo method name + _id products.category_id
belongsToMany both classes, alphabetical pivot order_product

The local key is the primary key, id. Category meets both of the first two rules: parent() is a bare belongsTo(Category::class), since the method name yields parent_id, but children() is a hasMany that would guess category_id, so it passes 'parent_id'. Check a guess by compiling the relationship:

Asking relationships which columns they will useSQL
use App\Models\{Category, Order, Product};
$programming = Category::find(2);
echo $programming->parent()->toRawSql(), "\n", $programming->children()->toRawSql(), "\n";
echo $programming->hasMany(Category::class)->getForeignKeyName(), "\n";
echo Order::find(1)->belongsToMany(Product::class)->getTable(), "\n";
Output
select * from `categories` where `categories`.`id` = 1
select * from `categories` where `categories`.`parent_id` = 2 and `categories`.`parent_id` is
    not null
category_id
order_product

The last two lines are the defaults you would have got: a missing column and a pivot table that is really called order_items. belongsTo binds the child's own parent_id (1); hasMany binds the parent's id and skips rows whose key is NULL.