Laravel: получение данных из таблиц variouos на основе необязательных условий

#laravel #eloquent

#laravel #eloquent

Вопрос:

Я хочу написать запрос на основе необязательного условия, который будет извлекать данные из разных таблиц. Моя схема выглядит так

Таблица myboxes

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

таблица mybox_access

  id
 mybox_id   -> foreign key to myboxes table
 email
  

box_type таблица

 id
type_name
  

И вот мои модели
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 имеет следующие отношения корабль

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

И MyBoxAccess.php имеет следующие отношения

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

Теперь я хочу получить на основе следующего условия
У меня есть email в качестве требуемого параметра, а postal_code и po_box — в качестве необязательных параметров (но один из них будет обязательным, и оба также могут присутствовать).

Итак, я хочу получить данные всех my_boxes, которые имеют type_id 3, ИЛИ всех myboxes, идентификатор которых соответствует электронной почте в таблице mybox_access, А postal_code или po_box соответствуют параметрам в таблице myboxes

Для простого сопоставления параметров почтовый индекс и po_box я могу написать что-то вроде

  $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();
  

Но я не знаю, как получить данные для вышеупомянутого условия. Когда я пытаюсь сделать, используя with() like

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

Я получаю

 `Argument 1 Passed to {closure} () must be an instance of IlluminatDatabaseQueryBuilder, instance of IlluminateDatabaaseEloquentRelationHasOne given`
  

Может ли какое-либо тело сообщить мне, как я могу получить данные на основе вышеупомянутого условия

Ответ №1:

$query это отношение, а не экземпляр builder .

Так что это не должно вызывать никаких исключений.

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

Но я не думаю, что это решило бы вашу проблему, потому что ваше отношение Box <=> Access неверно. Это должно быть много.

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

Затем в вашем контроллере вы могли бы это сделать.

 // $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();
  

И если вы хотите объединить все условия:

 $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();
  

Я всегда использую request() фасад при использовании в замыканиях, он кажется мне более чистым.

Комментарии:

1. Буду ли я использовать ->get() три раза?

2. Ну, это зависит. Вы запросили 3 разных вида результатов (на основе type_id ИЛИ email ИЛИ postal_code / po_box). Вы, конечно, могли бы использовать только 1 ->get() .

3. @SimponDepelchin ну, как я могу объединить их в одно ->get() , например, каждый раз, когда будет обязательное условие типа id и emaill и одно из post_code или po_box? например, где (type_id = 3 или email = myemail) и (post_code = 12 или po_box = 12)?

4. @AwaisQarni Я отредактировал свой пост, добавил пример объединения всех условий. Не стесняйтесь изменять условия (if/elseif/else) по мере необходимости.

Ответ №2:

Попробуйте выполнить этот запрос:

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

Комментарии:

1. И это решит все мои вопросы, которые я задал в quesiton?