Awais Qarni
Awais Qarni

Reputation: 18016

Laravel: get data from variouos tables based on optional conditions

I want to write a query based on optional condition that will fetch data from different tables. My schema looks like

myboxes Table

 id,
 type_id    --> foreign key to box_type table
 postal_code  
 po_box
 created_at
 updated_at

mybox_access table

 id
 mybox_id   -> foreign key to myboxes table
 email

box_type table

id
type_name

And here are my models MyBox.php

class MyBox extends Model {
    public function type() {
        return this->hasOne(BoxType::class, 'id', 'type_id');
    }

    public function access() id
        return this->hasOne(MyBoxAccess::class, 'mybox_id', 'type_id');
    }
}

MyBoxType.php has following relation ship

  public function mybox() {
        return this->hasOne(MyBox::class, 'id', 'type_id');
    }

And MyBoxAccess.php has following relationship

  public function vbox() {
      return $this->belongsTo(MyBox::class, 'id', 'mybox_id');
  }

Now I want to get based on following condition I have email as required param and postal_code and po_box as optional params (but one of them will be must and both can also be present).

So I want to get data of all my_boxes that have type_id 3 OR all myboxes whoes id matches to email in mybox_access table AND postal_code or po_box matches to params in myboxes table

For simple match of params postal code and po_box I can write some thing like

 $result = new MyBox();
 if(!empty($request['postal_code'])) {
     $result->where('postal_code', like, '%'.$request['postal_code']);
 }
 if(!empty($request['po_box'])) {
     $result->where('po_box', like, '%'.$request['po_box']);
 }
 $result = $result->get();

But I don't know how to get data for above mentioned condition. When I try to do using with() like

MyBox::with(['access' => function(Builder $query) use ($request){
     $query->where('mybox_id',$request['id']);
}])->get();

I get

`Argument 1 Passed to {closure} () must be an instance of Illuminat\Database\Query\Builder, instance of Illuminate\Databaase\Eloquent\Relation\HasOne given`

Can any body please let me know how can I get data based on above mentioned condition

Upvotes: 2

Views: 289

Answers (2)

SimonDepelchin
SimonDepelchin

Reputation: 2080

$query is a relationship, not a builder instance.

So this should not throw any Exception.

MyBox::with(['access' => function ($query) {
    $query->where('mybox_id', $request['id']);
}])->get();

But I don't think it'd resole your issue because your Box <=> Access relationship is not right. It should be HasMany.

// MyBox.php
public function type()
{
    return $this->hasOne(BoxType::class, 'id', 'type_id');
}
public function access()
{
    return $this->hasMany(MyBoxAccess::class, 'mybox_id', 'id');
}

Then in your Controller you could do this.

// $results where type_id is 3
$results = MyBox::where('type_id', 3)->get();

// List of boxes accessible by email
$results = MyBox::whereHas('access', function ($query) {
    $query->where('email', request()->input('email'));
})->get();

// Results where postal_code and po_box matches the request
$results = MyBox::with('access')->where(function ($query) {
    if (request()->has('postal_code')) {
        $query->where('postal_code', 'like', '%' . request()->input('postal_code'));
    }
    if (request()->has('po_box')) {
        $query->where('po_box', 'like', '%' . request()->input('po_box'));
    }
})->get();

And if you want to merge all conditions:

$results = MyBox::where(function ($query) {
    if (request()->has('type_id')) {
        $query->where('type_id', request()->input('type_id'));
    }
    if (request()->has('email')) {
        $query->whereHas('access', function ($query) {
            $query->where('email', request()->input('email'));
        });
    }
    if (request()->has('postal_code')) {
        $query->where('postal_code', 'like', '%' . request()->input('postal_code'));
    }
    if (request()->has('po_box')) {
        $query->where('po_box', 'like', '%' . request()->input('po_box'));
    }
})->get();

I always use the request() facade when using in closures, it feels cleaner to me.

Upvotes: 1

smartrahat
smartrahat

Reputation: 5659

Try this query:

MyBox::with('access')->get();

Upvotes: 0

Related Questions