Laravel как получить запрос с привязками?

У меня есть некоторый запрос, который мне нужно передать другому запросу с помощью построителя запросов

$query = DB::table('table')->whereIn('some_field', [1,2,30])->toSql();

Model::join(DB::raw("({$query}) as table"), function($join) {
    $join->on('model.id', '=', 'table.id');
})

что должно

Select * from model join (select * from table where some_field in (1,2,30)) as table on model.id = table.id

но привязки не передаются, что заставляет меня делать

   $query = DB::table('table')->whereRaw('some_field in ('. join(',', [1,2,30]) .')')->toSql();

что может быть небезопасным порой. Как я могу получить запрос с привязками?

Ответы

Ответ 1

Проверьте метод getBindings() в классе Builder

getBindings()

$query = DB::table('table')->whereIn('some_field', [1,2,30]);

$sql = $query->toSql();

$bindings = $query->getBindings();

Ответ 2

public static function getQueries(Builder $builder)
{
    $addSlashes = str_replace('?', "'?'", $builder->toSql());
    return vsprintf(str_replace('?', '%s', $addSlashes), $builder->getBindings());
}

Ответ 3

Если вы хотите получить выполненный запрос, включая привязки, из журнала запросов:

\DB::enableQueryLog();
\DB::table('table')->get();
dd(str_replace_array('?', \DB::getQueryLog()[0]['bindings'], 
      \DB::getQueryLog()[0]['query']));

Ответ 4

Следующая функция гарантирует, что результирующий SQL не перепутает привязки со столбцами, заключив ? в '?'

    public static function getFinalSql($query)
    {
        $sql_str = $query->toSql();
        $bindings = $query->getBindings();

        $wrapped_str = str_replace('?', "'?'", $sql_str);

        return str_replace_array('?', $bindings, $wrapped_str);
    }

Ответ 5

Так как другие ответы не правильно цитируют выражения, вот мой подход. Он использует функцию escape, которая принадлежит текущему соединению с базой данных.

Он заменяет вопросительные знаки один за другим на соответствующую привязку, которая извлекается из $ bindings через array_shift(), потребляя массив в процессе. Обратите внимание, что привязки $ должны передаваться по ссылке, чтобы это работало.

function getSql($query)
{
        $bindings = $query->getBindings();

        return preg_replace_callback('/\?/', function ($match) use (&$bindings, $query) {
            return $query->getConnection()->getPdo()->quote(array_shift($bindings));
        }, $query->toSql());
}

Ответ 6

Я создал эту функцию. Это частично, это могут быть параметры, которые не рассматриваются, для меня этого было достаточно.
Мы рады добавить ваши улучшения в комментарии!

function getFullSql($query) {
  $sqlStr = $query->toSql();
  foreach ($query->getBindings() as $iter=>$binding) {

    $type = gettype($binding);
    switch ($type) {
      case "integer":
      case "double":
        $bindingStr = "$binding";
        break;
      case "string":
        $bindingStr = "'$binding'";
        break;
      case "object":
        $class = get_class($binding);
        switch ($class) {
          case "DateTime":
            $bindingStr = "'" . $binding->format('Y-m-d H:i:s') . "'";
            break;
          default:
            throw new \Exception("Unexpected binding argument class ($class)");
        }
        break;
      default:
        throw new \Exception("Unexpected binding argument type ($type)");
    }

    $currentPos = strpos($sqlStr, '?');
    if ($currentPos === false) {
      throw new \Exception("Cannot find binding location in Sql String for bundung parameter $binding ($iter)");
    }

    $sqlStr = substr($sqlStr, 0, $currentPos) . $bindingStr . substr($sqlStr, $currentPos + 1);
  }

  $search = ["select", "distinct", "from", "where", "and", "order by", "asc", "desc", "inner join", "join"];
  $replace = ["SELECT", "DISTINCT", "\n  FROM", "\n    WHERE", "\n    AND", "\n    ORDER BY", "ASC", "DESC", "\n  INNER JOIN", "\n  JOIN"];
  $sqlStr = str_replace($search, $replace, $sqlStr);

  return $sqlStr;
}

Ответ 7

Здесь все объяснено..... https://ajcastro29.blogspot.com/2017/11/laravel-join-derived-tables-properly.html

Я создал запрос области для этой вещи. Я думаю, что он также может быть в макросах..

public function scopeJoinDerived($query, $derivedQuery, $table, $one, $operator = null, $two = null, $type = 'inner', $where = false)
{
    $query->join(DB::raw("({$derivedQuery->toSql()}) as '{$table}'"), $one, $operator, $two, $type, $where);
    $join = last($query->getQuery()->joins);
    $join->bindings =  array_merge($derivedQuery->getBindings(), $join->bindings);

    return $query;
}