Home > Software design >  How to correctly use relationships with() in Laravel?
How to correctly use relationships with() in Laravel?

Time:03-30

I just wanted to clarify using the relationship in tables. Right now, I wanted to fetch records of designation names from designation_id in employees table.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\{
    Designations,
    Positions
};

class Employees extends Model
{
    use HasFactory;

    protected $table = 'employees';

    protected $primaryKey = 'id';

    public $timestamps = true;
    
    protected $casts = [
        'designation_id' => 'array',
        'position_id' => 'array',
        'basic_pay' => 'decimal:2',
    ];

    protected $dates = ['created_at', 'updated_at'];

    protected $fillable = [
        'first_name', 
        'last_name',
        'designation_id',
        'position_id',
        'basic_pay',
    ];

    public function designations()
    {
        return $this->hasMany(Designations::class, 'id', 'designation_id');
    }

    public function positions()
    {
        return $this->hasMany(Positions::class, 'id', 'position_id');
    }
}

Here's my designation model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Employees;

class Designations extends Model
{
    use HasFactory;

    protected $table = 'designations';

    protected $primaryKey = 'id';

    public $timestamps = true;
    
    protected $dates = ['created_at', 'updated_at'];
    
    protected $fillable = [
        'name',
        'description'
    ];

    public function employees()
    {
        return $this->belongsTo(Employees::class, 'designation_id');
    }
}

Here's my EmployeeController.php:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\{
    Employees,
    Designations
};

class EmployeesController extends Controller
{
    public function index()
    { 
        $employees = Employees::with('designations', 'positions')->get();
        return array_reverse($employees);     
    }
}

I checked my api url, http://localhost:8000/api/employees and got this error:

SQLSTATE[HY093]: Invalid parameter number (SQL: select * from designationswheredesignations.id in (52))

CodePudding user response:

I would recommend you to install phpstorm, it gives you hints of function parameters and you won't have this kind of issues anymore.

correct format is:

return $this->hasMany('App\Comment', 'foreign_key', 'local_key');

in your designations model:

public function DesignationNames()
    {
        return $this->hasMany(\App\Models\Employees::class, 'designation_id', 'id');
    }

When you retrieve them in your controller you need to use the with() method as:

Designations::with('DesignationNames')->get();

And then to access properties in the related employee collection you would need to:

$designation->DesignationNames->DesignationProperty

CodePudding user response:

Your relationships parameters are wrong. It's

hasMany(class, foreignKey, relatedPrimaryKey)
# Employee
public function designations()
{
    return $this->hasMany(Designations::class, 'employee_id', 'id');
}

public function positions()
{
    return $this->hasMany(Positions::class, 'employee_id', 'id');
}

If you're eager loading more than 1 relationship, use array notation.

Also, $employees will be an instance of a Collection, so you can't use it as an argument to array_reverse.

You can either use collection methods to achieve the same result, or use $employees->all() to get the underlying array.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Employees;

class EmployeesController extends Controller
{
    public function index()
    { 
        $employees = Employees::with(['designations', 'positions'])->get();

        return $employees->reverse()->values()->all();
        // OR
        return array_reverse($employees->all());
    }
}

This is assuming your tables have a structure like this:

Schema::create('employees', function (Blueprint $table) {
    $table->id();
    ...    
});

Schema::create('designations', function (Blueprint $table) {
    $table->id();
    $table->foreignId('employee_id')->constained('employees');
    ...
});

Schema::create('positions', function (Blueprint $table){
    $table->id();
    $table->foreignId('employee_id')->constained('employees');
    ...
});

Since you're using increments instead of id(), the code has to be a little different.

Schema::create('employees', function (Blueprint $table) {
    $table->increments('id')->unique();
    ...    
});

Schema::create('designations', function (Blueprint $table) {
    $table->increments('id')->unique();
    $table->unsignedInteger('employee_id');
    $table->foreign('employee_id')->references('id')->on('employees');
    ...
});

Schema::create('positions', function (Blueprint $table){
    $table->increments('id')->unique();
    $table->unsignedInteger('employee_id');
    $table->foreign('employee_id')->references('id')->on('employees');
    ...
});
  • Related