Skip to content

База данных: Конструктор запросов

1. Введение

Конструктор запросов базы данных Laravel предоставляет удобный и гибкий интерфейс для создания и выполнения запросов к базе данных. Он может использоваться для выполнения большинства операций с базой данных в вашем приложении и отлично работает со всеми поддерживаемыми Laravel системами баз данных.

Конструктор запросов Laravel использует привязку параметров PDO для защиты вашего приложения от атак типа SQL-инъекций. Нет необходимости очищать или обрабатывать строки, передаваемые в конструктор запросов в качестве привязок.

exclamation

PDO не поддерживает привязку имен столбцов. Поэтому никогда не позволяйте пользовательскому вводу определять имена столбцов, упоминаемых в ваших запросах, включая столбцы для операции "order by".

2. Выполнение запросов к базе данных

2.0.1. Получение всех строк из таблицы

Вы можете использовать метод table, предоставляемый фасадом DB, чтобы начать построение запроса. Метод table возвращает экземпляр гибкого конструктора запросов для указанной таблицы, что позволяет добавлять дополнительные ограничения к запросу, а затем получить результаты запроса с помощью метода get:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Вывести список всех пользователей приложения.
*/
public function index(): View
{
$users = DB::table('users')->get();
 
return view('user.index', ['users' => $users]);
}
}

Метод get возвращает экземпляр Illuminate\Support\Collection, содержащий результаты запроса, где каждый результат представлен экземпляром объекта PHP stdClass. Вы можете получить доступ к значению каждого столбца, обратившись к нему как к свойству объекта:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')->get();
 
foreach ($users as $user) {
echo $user->name;
}

2.0.2. Получение одной строки или одного столбца из таблицы

Если вам нужно получить только одну строку из таблицы базы данных, вы можете использовать метод first фасада DB. Этот метод вернет один объект stdClass:

$user = DB::table('users')->where('name', 'John')->first();
 
return $user->email;

Если вы хотите получить одну строку из таблицы базы данных, но при отсутствии совпадений выбросить исключение Illuminate\Database\RecordNotFoundException, вы можете использовать метод firstOrFail. Если исключение RecordNotFoundException не будет обработано, клиенту автоматически отправится HTTP-ответ с кодом 404:

$user = DB::table('users')->where('name', 'John')->firstOrFail();

Если вам не нужна вся строка, вы можете извлечь одно значение из записи, используя метод value. Этот метод вернет значение столбца напрямую:

$email = DB::table('users')->where('name', 'John')->value('email');

Чтобы получить одну строку по значению столбца id, используйте метод find:

$user = DB::table('users')->find(3);

2.0.3. Получение списка значений столбца

Если вы хотите получить экземпляр Illuminate\Support\Collection, содержащий значения одного столбца, вы можете использовать метод pluck. В этом примере мы получим коллекцию с названиями должностей пользователей:

use Illuminate\Support\Facades\DB;
 
$titles = DB::table('users')->pluck('title');
 
foreach ($titles as $title) {
echo $title;
}

Вы можете указать столбец, который должна использовать результирующая коллекция в качестве ключей, передав второй аргумент в метод pluck:

$titles = DB::table('users')->pluck('title', 'name');
 
foreach ($titles as $name => $title) {
echo $title;
}

2.1. Разбиение результатов

Если вам нужно работать с тысячами записей базы данных, рассмотрите возможность использования метода chunk, предоставляемого фасадом DB. Этот метод извлекает небольшие части результатов за раз и передает каждую часть в замыкание для обработки. Например, давайте извлечем всю таблицу users частями по 100 записей:

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
foreach ($users as $user) {
// ...
}
});

Вы можете остановить дальнейшую обработку частей, вернув false из замыкания:

DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
// Обработка записей...
 
return false;
});

Если вы обновляете записи базы данных во время обработки результатов частями, ваши результаты могут измениться неожиданным образом. Если вы планируете обновлять полученные записи при разбиении на части, всегда лучше использовать метод chunkById. Этот метод автоматически разбивает результаты на страницы на основе значения первичного ключа записи:

DB::table('users')->where('active', false)
->chunkById(100, function (Collection $users) {
foreach ($users as $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
}
});

Поскольку методы chunkById и lazyById добавляют свои собственные условия "where" к выполняемому запросу, вам следует обычно логически группировать свои условия внутри замыкания:

DB::table('users')->where(function ($query) {
$query->where('credits', 1)->orWhere('credits', 2);
})->chunkById(100, function (Collection $users) {
foreach ($users as $user) {
DB::table('users')
->where('id', $user->id)
->update(['credits' => 3]);
}
});
exclamation

При обновлении или удалении записей внутри обратного вызова для метода chunk любые изменения первичного или внешних ключей могут повлиять на запрос для обработки частей. Это может привести к тому, что некоторые записи не будут включены в результаты обработки частями.

2.2. Ленивая загрузка результатов с потоковой передачей

Метод lazy работает аналогично методу chunk в том смысле, что он выполняет запрос частями. Однако, вместо передачи каждой части в обратный вызов, метод lazy() возвращает LazyCollection, который позволяет взаимодействовать с результатами как с единым потоком:

use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
// ...
});

Если вы планируете обновлять полученные записи во время их перебора, лучше использовать методы lazyById или lazyByIdDesc. Эти методы автоматически разбивают результаты на страницы на основе значения первичного ключа записи:

DB::table('users')->where('active', false)
->lazyById()->each(function (object $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
});
exclamation

При обновлении или удалении записей во время их перебора любые изменения первичного или внешних ключей могут повлиять на запрос для обработки частей. Это может привести к тому, что некоторые записи не будут включены в результаты.