Search code examples
laravelentity-relationshipone-to-onehas-onedatabase-relations

One-to-one relations that only go one way in Laravel


Is it possible/right to have a a relation between tables that only goes one way? I have an invoices table that I need to reference in other tables likes commission_payments and membership_payments but the invoices table does not need a commission_payment_id or a membership_payment_id. In other words, there different types of transactions that can happen and they all may have a invoice attached, but the invoice does not need to reference these transaction tables.

invoices           commission_payments      membership_payments
---------------    ---------------------    ---------------------
-id                -id                      -id
...                -invoice_id              -invoice_id
                   ...                      ...

I have created Eloquent models for each table. I added a hasOne relation to invoices on the other two models.

class CommissionPayment extends Model{
    public function invoice(){
        return $this->hasOne('App\Models\Invoice');
    }
}

I then tried accessing the Comission Payment's attached invoice like this:

$com = CommissionPayment::first();
$com->invoice->id;

I then get this error:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 
'invoices.commission_payment_id' in 'where clause' (SQL: select * from `invoices` 
where `invoices`.`commission_payment_id` = 15 and `invoices`.`commission_payment_id` is not
null limit 1) 

Why is it looking for commission_payment_id field in the invoices table? I would expect a query sort of like this:

SELECT * FROM `invoices` WHERE `id` = 23 
/* id is fetched from the `invoice_id` field in the `commission_payments` table */

Do I HAVE to add a column for each table that will reference invoice_id? At the moment it's two but this could grow. Also, when an invoice was generated for a commission payment, it won't need the membership payment field so I don't think it should go there.


Solution

  • A one-to-one relationship is setup using either the hasOne or belongsTo relationship. The hasOne side of the relationship assumes the foreign key is stored on the other table. The belongsTo side of the relationship has the foreign key.

    Therefore, since your foreign key to the invoices are stored on the commission_payments and membership_payments tables, those models are said to belong to the invoices table.

    Change your relationship from hasOne to belongsTo and you should be good to go:

    class CommissionPayment extends Model{
        public function invoice() {
            return $this->belongsTo('App\Models\Invoice');
        }
    }