Laravel Eloquent whereHas() Condition

- LAST UPDATED

Laravel Eloquent relationship is one of the best and easy ways to load relational data when using Laravel for applications. It helps us to reduce the code and get data without using multiple queries without using join queries. When we use join queries, it also gives us the flexibility to query data from the joined table. When using the join queries, it usually gives us a single object as output, which will kill the coolness of separate objects for each related model. 

Laravel eloquent whereHas() query is the best solution to fix this problem. The current tutorial only discusses the application of the whereHas condition for belongsTo and hasOne relationships.

Laravel Eloquent whereHas() 

Example Laravel whereHas for belongsTo() Relationship

Let's see an example of Laravel whereHas statement where we will fetch users' posts with a particular keyword. Let's have a look at the example.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;
use Illuminate\Database\Eloquent\Builder;

class IndexController extends Controller
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function __invoke(Request $request)
    {
        $q = $request->get('q');
        return Post::with('user')
        ->whereHas('user', function (Builder $query) use ($q) {
            $query->where('name', 'like', '%'.$q.'%');
        })
        ->get();
    }
}

The above example is querying related model users based on the query parameter. Let's look at the post model used for the same. So the posts table has a user id and a belongsTo relationship with the "users" table using the user() relationship.

It is not necessary to use with('user') if we don't need to fetch user details along with posts.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'slug',
        'heading',
        'description',
        'user_id'
    ];
    /**
     * User relationship
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

So when using Laravel whereHas, it automatically queries the user table based on the given condition.

And whereHas generated as exists query to fetch related table.

Example Laravel whereHas for hasOne() Relationship

Lets create a new table called accounts using this migration.

Schema::create('accounts', function (Blueprint $table) {
            $table->id();
            $table->string('company');
            $table->bigInteger('user_id');
            $table->timestamps();
});
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Account extends Model
{
    use HasFactory;
}

And let's add a relationship in the User model to the Account model using hasOne relationship.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    /**
     * Get account
     */
    public function account()
    {
        return $this->hasOne(Account::class);
    }
}

Example query using hasOne relationship

$q = $request->get('q');
$users = User::whereHas('account', function (Builder $query) use ($q) {
    $query->where('company', 'like', '%'.$q.'%');
})
->get();

So the above query will fetch users based on the company field in the accounts table using the whereHas condition.