Laravel MySQL, в котором закрытие работает не так, как ожидалось

#php #mysql #laravel

#php #MySQL #laravel

Вопрос:

Кто-нибудь может помочь объяснить, почему один из следующих запросов Laravel работает, а другой нет?

Первое, что работает:

 $array = ( 1, 2, 3 ,4 );
$query->whereIn( 'status_id', $array );
  

Это работает так, как ожидалось. Однако, когда я пытаюсь передать функцию для построения моего массива:

 $query->whereIn( 'status_id', function() use ( $statuses ){
    $status_array = array();
    foreach( $statuses as $status ){
         $status_array[] = $status->status_id;
    }

    return $status_array;
});
  

Я получаю следующую ошибку:

Общая ошибка: 1096 Таблицы не используются (SQL: выберите * jobs откуда status_id в (выберите *))

Я проверил, чтобы увидеть, что массив, который я создаю в закрытии, совпадает с работающим массивом, и это так. Я упускаю что-то фундаментальное относительно Where() и его функций закрытия? Могу ли я даже передать закрытие Where() ?

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

1. Что произойдет, если вы выполните «return array(1, 2, 3, 4)» из функции — работает ли это?

Ответ №1:

Когда вы используете закрытие в whereIn() , Laravel подумает, что вы будете выполнять вспомогательный запрос. Следовательно, вы видите другое select in внутри вашего сообщения об ошибке.

Вам нужно будет проанализировать ваш массив значений, прежде чем переходить к whereIn()

 foreach ($statuses as $status) {
     $status_array[] = $status->status_id;
}

$query->whereIn('status_id', $status_array);
  

Дополнительно: см. Ссылку на исходный код Laravel.

Illuminate Database Query Builder:

 public function whereIn($column, $values, $boolean = 'and', $not = false)
{
    ...

    if ($values instanceof Closure)
    {
        return $this->whereInSub($column, $values, $boolean, $not);
    }
}
  

который вызывает whereInSub() :

 protected function whereInSub($column, Closure $callback, $boolean, $not)
{
    $type = $not ? 'NotInSub' : 'InSub';

    // To create the exists sub-select, we will actually create a query and call the
    // provided callback with the query so the developer may set any of the query
    // conditions they want for the in clause, then we'll put it in this array.
    call_user_func($callback, $query = $this->newQuery());

    $this->wheres[] = compact('type', 'column', 'query', 'boolean');

    $this->mergeBindings($query);

    return $this;
}
  

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

1. Это то, что я в итоге сделал, используя комбинацию из ответа Shift Exchange выше. Принял этот ответ, поскольку вы также дали мне хорошее объяснение, почему все получилось не так, как я ожидал. Спасибо 🙂

Ответ №2:

В качестве связанного ответа, вместо запуска цикла для создания вашего списка — просто попросите Laravel сделать это за вас

  $status_array= DB::table('status')->lists('status_id');
  

затем используйте его

  $query->whereIn( 'status_id', $status_array );
  

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

1. Спасибо, это прекрасная маленькая функция и экономит дополнительный foreach 🙂

Ответ №3:

Я думаю, что ваша функция возвращает массив, подобный этому:

 [ 0 => status_id_value_0,
  1 => status_id_value_1, 
  ...
] 
  

Попробуйте вернуть an array_values($status_array) , чтобы проверить это.

В любом случае, попробуйте и это:

 $query->whereIn( 'status_id', 
                 array_values(
                     array_map(
                         function($pos){return $pos->status_id;},
                         $statuses
                     )
                 )
               ); 
  

Я надеюсь, что у вас все работает нормально.

Ответ №4:

Вам необходимо преобразовать значение, разделенное запятыми, в массив, прежде чем переходить к Where.

и это также хорошо для любого динамического контента

     foreach ($statuses as $status) {
         $status_array[] = $status->status_id;
    }
    $query->whereIn('status_id', $status_array);