Вопросы с меткой [laravel-8]
Руководство по использованию метки laravel-8 отсутствует.
86 вопросов
Конкурсные
Неотвеченные
- Конкурсные 0
- Неотвеченные
- Цитируемые
- Рейтинг
- Неотвеченные (мои метки)
1k показов
Laravel 8 SQLSTATE[HY000] [2002] Connection refused
Всем привет! Проблема следующая, когда пытаюсь сделать любой запрос к базе выдает ошибку SQLSTATE[HY000] [2002] Connection refused, при этом миграции работают без проблем. Пробовал менять 127.0.0.1 на .
10 показов
Обращение к модели laravel 8 из вебсокета
как решить эту проблему? отправляю сообщение из JS-вебсокета -> сообщение попадает в серверный вебсокет -> обращаюсь к контроллеру -> контроллер обращается к модели (для примера Offer::all()).
Laraver Orchid Выгрузка в excel
Есть проект он на laravel 8, для админки установлен orchid, на одной странцие я выгружаю пользователей в excel файл, нужно чтобы данная выгрузка учитывала установленный фильтр. Вот каку меня сейчас .
2k показов
Failed to load resource: the server responded with a status of 404 (Not Found)
Имеется такой маршрут: Route::get(‘/product/
58 показов
как получить рандомное число из диапазона в том числе и с плавающей точкой? Decimal
К примеру, есть rand(), но там только int. А как сделать, чтобы на выходе получалось число из диапазонов таких число должно быть Decimal на выходе: $rand = rand(1.12, 5.45); или //типа 3.82 $rand = .
38 показов
Laravel — многие ко многим
Не работает связь многие ко многим. Не могу понять, почему? Musics.php
Почему возникает ошибка при загрузке картинки?
Делаю на ларавел 8. Есть форма, в которой есть поле для фото — foto_main. В контроллере пишу такой код: public function store(Request $request) < $params = $request->all(); .
Почему middleware блокирует страницы?
Использую вполне стандартный функционал. Использую два middleware по умолчанию: auth и guest. В файле app\Http\Kernel.php прописаны следующие строки: protected $routeMiddleware = [ ‘auth’ =&.
109 показов
Как сделать корректную пагинацию с ГЕТ-параметрами?
Делаю на laravel 8 вывод данных с пагинацией. Все работает замечательно. У меня свой шаблон пагинации. Он прописан так: << $houses->links(‘catalogs.paginate’) >> Однако, когда я произвожу на .<>
75 показов
Вернуть значения таблицы в шаблон находящийся внутри шаблона LARAVEL
Всем привет! У меня есть таблица categories из которой нужно вытащить данные в шаблон categories.blade.php, который не используется как самостоятельная страница. Этот шаблон используется только внутри .
59 показов
Не работает upsert в laravel
Laravel Framework 8.35.1 Пытаюсь обновить записи через upsert, но при выполнении ниже представленного кода laravel пытается добавить новую запись. Id является первичным ключом в таблице, записи .
99 показов
Как отсортировать коллекцию по алфавиту в Laravel?
Как отсортировать коллекцию в Laravel в алфавитном порядке (от А до Z)? Сейчас код выглядит следующим образом: $cities = usort(Cities::all()->toArray(), fn($a, $b) => $a[‘name’] <=>$b[‘.=>
85 показов
belongsToMany не работает
У меня есть 3 таблицы videos (id) video_user (user_id, video_id) users (id) Мне нужно чтобы я мог получить все видео, которые опубликовал пользователь Я уже попытался это сделать таким образом: User.
165 показов
Laravel отправка email сообщения в определенное время
Нужно отправлять сообщение на почту людям за 2 часа, 1 час , пол часа, 15 минут до начала определенного события, как это реализовать в ларавел?
429 показов
Как проверить через какую страницу зашёл пользователь?
Как узнать с какой страницы попал пользователь на другую? Есть например страница 1 и пользователь перешел при помощи неё на страницу 2, как узнать на какой страницы был пользователь?
15 30 50 на странице
-
Важное на Мете
Связанные метки
Подписаться на ленту
Лента последних активных вопросов с меткой [laravel-8]
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.9.3159
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Расширение синтаксиса Blade
Хочу поделиться с сообществом своей небольшой библиотекой, добавляющей управляющие директивы в синтаксис Laravel-шаблонизатора Blade.
Сразу небольшой пример как это выглядит:
После знакомства с Angular.js привычные глазу шаблоны стали казаться нелогичными и неудобными. Хотелось управлять тэгами и аттрибутами, а не обращаться с HTML, как с обычной строкой. Благо Blade позволяет легко расширить функционал, чем я и воспользовался.
Установка
- Добавить пакет «sleeping-owl/blade-extended» в ваш composer.json.
- Добавить Service provider в ваш «app/config/app.php» — ‘SleepingOwl\BladeExtended\BladeExtendedServiceProvider’.
- Расширенный синтаксис теперь вам доступен.
Как это работает
Библиотека до банального проста — все, что она делает, это конвертирует аттрибуты в корректный Blade-синтаксис. Так например код:
будет приведен к виду:
@if(test()) @endif @foreach($items as $item)>>@endforeach
Несколько сложнее дела обстоят с аттрибутами тэга — тут используется helper, который выводит аттрибут, только если он содержит значение.
Поддерживаемые директивы
bd-foreach, bd-inner-foreach
Повторяет тэг целиком (bd-foreach), либо все содержимое тэга (bd-inner-foreach) в соответствии с указанными значениями.
bd-if
Выводит или нет тэг в зависимости от условия.
bd-class
Добавляет один или несколько классов элементу, можно использовать условия. Если у тэга уже определен аттрибут class, то новые классы будут добавлены к нему.
bd-attr-
Работает аналогично bd-class, но не поддерживает множественные значения и добавление к существующему аттрибуту.
bd-yield, bd-include
Эти директивы добавляют в тело тэга соответствующие команды Blade.
bd-section
Обрамляет тэг в blade-секцию.
Хотите еще расширить синтаксис?
Функционал моей библиотеки, расширяющей возможности Blade, так же может быть расширен. Вы можете зарегистрировать свои аттрибуты, которые будут обрабатываться:
BladeExtended::extend('bd-test', function (BladeExtended $bladeExtended, &$finded) < $bladeExtended->wrapOuterContent($finded, '@if(myCustomTest())', '@endif'); >);
Laravel: 20 полезных советов
Итак, я решил составить список из 20 моих любимых советов, которые я размещал в своих аккаунтах в соцсетях, чтобы все могли познакомиться с ними. Они не размещены в каком-то определённом порядке, но я надеюсь, что вы найдёте хотя бы один новый совет, который окажется полезным.
Вступление
Я регулярно публикую небольшие сниппеты и советы в Твиттере (@AshAllenDesign), которые вы можете использовать в своих Laravel-приложениях. Но из-за особенностей социальной сети, старый контент может быть перемещён вглубь ленты и не виден через несколько дней после его публикации.
1. Используйте поля типа DATETIME вместо Boolean
В ваших Laravel приложениях, зачастую можно использовать поля типа DATETIME вместо boolean .
Например, если бы у нас была модель Post , вместо поля is_published типа boolean вы могли бы использовать поле published_at типа DATETIME .
Используя этот подход, вы по-прежнему можете проверить опубликована ли запись, а также получить дополнительную информацию, о том, когда именно она была опубликована.
Возможно вам не нужна точная дата сейчас, но она может быть полезной в будущих функциях (таких, как отчётность).
Например, мы могли бы обновить модель Post , что бы она выглядела следующим образом:
class Post extends Model
public function isPublished(): bool
return $this->published_at !== null;
>
>
Это означает, что мы можем использовать $post->isPublished() для получения логического значения. И мы могли бы использовать $post->published_at для получения даты и времени публикации записи.
Сам фреймворк Laravel использует этот подход для обратимого удаления (soft delete) моделей и устанавливает поле deleted_at при мягком удалении модели.
2. Именование столбцов типа Date и Time
Может быть, весьма полезным использовать соглашение об именовании action_at для ваших полей DATETIME и TIMESTAMP . Это помогает мгновенно распознать является ли поле, с которым вы работаете, полем даты и времени (и, вероятно, экземпляром класса Carbon , если вы выполнили приведение к нему).
Например, вместо использования таких полей как:
- publish_time
- verified_date
- password_reset
Было бы полезнее переименовать их в:
- published_at
- verified_at
- password_reset_at
3. Используйте Матричные Последовательности в Фабриках
Вы можете использовать MatrixSequence в фабриках моделей для создания дополнительных данных для тестов.
User::factory(4)
->state(
new MatrixSequence(
[['first_name' => 'John', 'last_name' => 'Jane']],
[['first_name' => 'Alice', 'last_name' => 'Bob']],
),
)
->create();
Исполнение приведённого выше фрагмента кода создаст четыре записи модели User со следующими полями:
- first_name: John, last_name: Alice
- first_name: John, last_name: Bob
- first_name: Jane, last_name: Alice
- first_name: Jane, last_name: Bob
4. Используйте when в PendingRequest
Вы можете использовать метод when в классе PendingRequest при построении запросов с фасадом http .
Предположим, что у вас есть следующий код:
$http = Http::withBasicAuth($username, $password);
if (app()->environment('local'))
$http->withoutVerifying();
>
Если вы предпочитаете, чтобы логика запроса была объединена, а не разделена с помощью оператора if , вы можете переписать её используя when :
$http = Http::withBasicAuth($username, $password)
->when(app()->environment('local'), function (PendingRequest $request)
$request->withoutVerifying();
>);
При использовании любого из этих подходов нет правильного или неправильного варианта, всё зависит от личных предпочтений в написании кода.
5. Использование директив Blade checked и selected
Когда вы создаёте формы в Blade, вам может понадобиться установить значение checkbox в checked или выбрать из списка select один или несколько элементов option . Для этого вы можете использовать директивы Blade @checked и @selected .
Например, если мы хотим, чтобы checkbox был отмечен, если пользователь активен, мы могли бы использовать следующий подход:
input type="checkbox"
name="active"
value="active"
@checked($user->active) />
Точно так же мы могли бы использовать тот же подход, если бы хотели выбрать определённый option в элементе select с помощью директивы @selected :
select name="version">
@foreach ($product->versions as $version)
option value="" @selected(old('version') == $version)>
/option>
@endforeach
/select>
6. Используйте Mockery::on() в PHPUnit тестах
При написании тестов на Laravel и PHP вам может понадобиться смоделировать класс (такой, как сервис или action). Смоделировав класс, вы можете убедиться, что он был вызван, как ожидалось, с правильными аргументами, но без запуска кода внутри него. Это может быть особенно полезно при тестировании ваших контроллеров.
Вам может захотеться сделать тесты более строгими и убедится, что конкретная модель или объект передаются методу. Для этого вы можете использовать Mockery::on() .
В качестве базового пример возьмём следующий контроллер. Метод контроллера выполняет action PublishPost , при этом action принимает модель Post . Затем мы возвращаем в ответ простой JSON .
// app/Http/Controllers/PublishPostController
use App\Actions\PublishPost;
use App\Models\Post;
class PublishPostController extends Controller
public function __invoke(Post $post, PublishPost $action): Response
$action->execute($post);
return response()->json([
'success' => true,
]);
>
>
В нашем тесте мы можем настроить смоделированный action, до того как мы сделаем HTTP-вызов. В смоделированном методе мы можем указать, что ожидаем, что метод execute будет вызван один раз и ему будет переданная нами модель Post
Если эти критерии соблюдены, ассерты будут пройдены и мы будем знать, что action был вызван так, как мы и ожидали. В противном случае, если критерии не соблюдены, тест не будет выполнен.
// tests/Feature/PublishPostControllerTest
use App\Actions\PublishPost;
use App\Models\Post;
use Mockery;
use Mockery\MockInterface;
use Tests\TestCase;
class PublishPostControllerTest extends TestCase
/** @test */
public function post_can_be_deleted(): void
$post = Post::factory()->create();
$this->mock(PublishPost::class, function (MockInterface $mock) use ($post)
$mock->shouldReceive('execute')
->once()
->withArgs([
Mockery::on(fn (Post $arg): bool => $arg->is($post)),
]);
>);
$this->post(route('post.publish', $post))
->assertOk()
->assertJson([
'success' => true,
]);
>
>
Если вам интересно больше узнать о тестировании, то возможно вас заинтересует статья Laravel: Как сделать ваше приложение более тестируемым
7. Используйте getOrPut() в Коллекциях/Collection
Есть полезный метод getOrPut() , который вы можете использовать в своих Коллекциях. Его можно использовать для извлечения элемента (если он уже существует) или для его вставки и извлечения, если он не существует.
Это может быть полезно при создании коллекции с данными из нескольких источников, и если вы не хотите дублировать элементы в своих данных.
Например, вместо того, что бы писать:
if (! $collection->has($key))
$collection->put($key, $this->builtItem($data));
>
return $collection->get($key);
Вы можете использовать метод getOrPut() следующим образом:
return $collection->getOrPut($key, fn () => $this->buildItem($data));
8. Отладка HTTP Запросов
При отправке HTTP запросов из вашего приложения Laravel с использованием HTTP фасада вы можете захотеть посмотреть дамп запроса. Это может быть чрезвычайно полезно для отладки, и я сам этим пользуюсь во время разработки для устранения проблем с запросами к внешним API.
Для дампа данных запроса, вы можете использовать метод dump() следующим образом:
Http::dump()->get($url);
Точно так же вы можете использовать метод dd , для остановки приложения и вывода данных:
Http::dd()->get($url);
9. Репликация Моделей
В Laravel приложении можно дублировать Модель используя метод replicate() . Это упрощает копирование Моделей.
Я использую эту функциональность в своём блоге для создания копии общего шаблона записи в блоге, который я использую для создания новой статьи.
Например, вы можете продублировать модель следующим образом:
$post = Post::find(123);
$copiedPost = $post->replicate();
$copiedPost->save();
Если вы хотите исключить копирование некоторых свойств, то можете передать их имена в виде массива:
$post = Post::find(123);
$copiedPost = $post->replicate([
'author_id',
]);
$copiedPost->save();
Кроме того, метод replicate() создаёт не сохранённую модель, поэтому вы можете связать вместе со своими обычными методами модели. Например, вы можете скопировать модель и добавить copy в конце заголовка, что бы вы могли видеть, что запись была реплицирована.
$post = Post::find(123);
$copiedPost = $post->replicate([
'author_id',
])->fill([
'title' => $post->title.' (copy)',
]);
$copiedPost->save();
Важно помнить, что модели не сохраняются в базе данных после использования метода replicate() . Итак, вам нужно убедиться, что вы сохраняете их используя метод save .
10. Добавление подсказок автозаполнения к командам artisan
Когда вы создаёте свои artisan-команды в своём приложении Laravel, вы можете использовать метод anticipate для предоставления пользователю подсказок автозаполнения.
Например, у нас может быть команда, которая находит пользователя по электронной почте. В этой команде мы могли бы передать список возможных адресов электронной почты методу anticipate , что бы они отображались на экране когда пользователь начинает печатать:
class TestCommand extends Command
public function handle()
$email = $this->anticipate('Find user by email: ', [
'mail@ashallendesign.co.uk',
'hello@example.com',
]);
>
>
Стоит отметить, что пользователь по-прежнему может ввести ответ, которого нет в списке. Метод anticipate используется только для подсказок, а не для проверки ввода.
11. Использование wasRecentlyCreated в Моделях
Бывают случаи, когда в Laravel приложении нужно проверить, была ли модель извлечена из базы или только что создана, в текущем жизненном цикле запроса — например, при использовании метода firstOrCreate .
Для этого вы можете использовать поле wasRecentlyCreated в модели следующим образом:
$user = User::firstOrCreate(
['email' => request('email')],
['name' => request('name')],
);
if ($user->wasRecentlyCreated)
// Ваш пользователь был только что создан.
> else
// Ваш пользователь уже существует и был получен из базы данных.
>
12. Изменение ключа для привязки Модели к Route
В маршрутах вашего Laravel приложения вы можете изменять ключ, который используется для определения моделей использующих привязку модели к маршруту.
Например, предположим, что у вас есть маршрут, который принимает slug записи в блоге:
Route::get('blog/', [BlogController::class, 'show']);
Затем в нашем контроллере нужно будет вручную попытаться найти запись в блоге. Допустим, внутри контроллера этот метод выглядит так:
use App\Actions\PublishPost;
use App\Models\Post;
class BlogController extends Controller
public function show($slug)
$post = Post::where('slug', $slug)->firstOrFail();
return view('blog.show', [
'post' => $post,
]);
>
>
Чтобы упростить и очистить этот код, мы могли бы заменить в маршруте параметр slug на post:slug :
Route::get('blog/', [BlogController::class, 'show']);
Теперь, мы можем обновить наш метод контроллера на ожидание модели Post в качестве параметра $post , и Laravel автоматически найдёт модель Post которой принадлежит slug переданный в URL.
Это означает, что нам не нужно вручную находить модель в контроллере, и мы можем позволить Laravel определить её следующим образом:
use App\Actions\PublishPost;
use App\Models\Post;
class BlogController extends Controller
public function show(Post $post)
return view('blog.show', [
'post' => $post,
]);
>
>
13. Использование Внедрения Зависимости / Dependency Injection
Внедрение зависимости в коде вашего Laravel приложения позволяет разрешать зависимости от контейнера всякий раз, когда вы создаёте новый класс. Это сделает код лучше поддерживаемым и тестируемым.
В этом примере мы не используем Внедрение Зависимости, а просто создадим новый класс:
class MyController extends Controller
public function __invoke()
$service = new MyService();
$service->handle();
>
>
Теперь мы удалим в первую строку метода и добавим MyService в качестве параметра. Laravel будет при вызове этого метода каждый раз внедрять $service для нас, что бы мы могли его использовать.
class MyController extends Controller
public function __invoke(MyService $service)
$service->handle();
>
>
Также бывают случаи, когда вы находитесь внутри класса, и оказывается, что без серьёзного рефакторинга вы не сможете внедрить свой класс, передав его в качестве дополнительного параметра метода. В таком случае можно использовать хэлпер resolve() предоставляемый Laravel, например:
class MyClass
public function execute()
$service = resolve(MyService::class);
$service->handle();
>
>
14. Фильтрация Коллекций по типу класса
Вы можете фильтровать Коллекции laravel по заданному типу класса, используя метод whereInstanceOf . Это может быть полезным если вы создаёте Коллекции из нескольких источников данных (например, полиморфных отношений) и вам нужно отфильтровать их до определённых классов.
Например, мы могли бы иметь следующую Коллекцию и отфильтровать её, что бы она содержала только класс User :
$collection = collect([
new User(),
new User(),
new User(),
new Comment(),
]);
$filtered = $collection->whereInstanceOf(User::class)->all();
Метод whereInstanceOf() также принимает массив классов, если вы хотите фильтровать более чем по одному классу. Например, что бы отфильтровать Коллекцию так, что бы она содержала только классы Post и Comment , вы можете сделать это следующим образом:
$filtered = $collection->whereInstanceOf([Post::class, Comment::class])->all();
15. Определение пользовательской логики временного URL
Вы можете настроить способ создания временных URL-адресов для отдельных хранилищ данных. Это может быть удобно, если у вас есть контроллер позволяющий загружать файлы в хранилища, которые не поддерживают временные URL-адреса.
Для использования этой функции необходимо зарегистрировать логику (обычно в сервис провайдере) с помощью метода buildTemporaryUrlsUsing .
Вот пример, как мы могли бы зарегистрировать некую пользовательскую логику для создания временных URL-адресов для локального хранилища данных (локального диска):
public function boot()
Storage::disk('local')->buildTemporaryUrlsUsing(function ($path, $expiration, $options)
return URL::temporarySignedRoute(
'files.download',
$expiration,
array_merge($options, ['path' => $path]),
);
>);
>
После регистрации логики, вы можете её использовать функционал с помощью метода temporaryUrl , например так:
$tempUrl = Storage::disk('local')->temporaryUrl('file.jpg', now()->addMinutes(5));
16. Валидация MAC адресов
В Laravel доступно полезное правило mac_address , которое можно использовать для валидации того, является ли поле mac адресом.
Например, следующая проверка будет пройдена, поскольку значение является валидным MAC-адресом:
Validator::make([
'device_mac' => '00:1A:C2:7B:00:47'
], [
'device_mac' => 'mac_address',
])->passes();
Но следующая проверка завершится ошибкой, поскольку значение не является MAC-адресом:
Validator::make([
'device_mac' => 'invalid-mac-address'
], [
'device_mac' => 'mac_address',
])->passes();
17. Шифрование полей в Базе Данных
Вы можете хранить отдельные поля в зашифрованном формате используя задав в свойстве $cast модели значение encrypted для шифруемого поля. Это полезно, если вы храните личные данные в базе данных, которые нуждаются в дополнительной защите в случае взлома данных.
Например, чтобы зашифровать поле my_encrypted_field в модели User , вам нужно обновить свои модель следующим образом:
class User extends Authenticatable
protected $casts = [
'my_encrypted_field' => 'encrypted',
];
>
Вы можете продолжать использовать поле как обычно. Например, что бы обновить значение хранящееся в my_encrypted_field , мы всё ещё можем использовать метод update , как обычно:
$user->update(['my_encrypted_field' => 'hello123']);
Если бы вы сейчас заглянули в базу данных, то не увидели бы значения hello123 в поле my_encrypted_field . Вместо этого вы увидели бы его зашифрованную версию.
Но вы по прежнему можете использовать оригинальное значение в своём коде без внесения каких-либо изменений:
$result = $user->my_encrypted_field;
// $result is equal to: "hello123"
Важно помнить, что шифрование использует APP_KEY приложения, поэтому если он будет скомпрометирован в результате взлома или изменён, можно будет расшифровать зашифрованные поля, хранящиеся в базе данных.
18. Перемещение Логики в Методы
Вместо прямой проверки полей в условных выражениях иногда можно перенести логику в метод.
Это поможет улучшить читаемость кода, а также поможет придерживаться принципа DRY , если вам нужно повторно использовать туже логику (или если логика изменится в будущем).
Например, предположим, что мы хотим проверить, одобрен ли пользователь. Наш код может выглядеть так:
if ($user->approved === Approval::APPROVED)
// Сделать что-то.
>
Но основная проблема с этим подходом заключается в том, что если мы используем его в нескольких местах кодовой базы, то будет сложно его обновлять, если потребуется изменить логику.
Итак, мы можем переместить логику в метод (например, isApproved ) модели User . Теперь мы можем вызывать этот метод, вместо прямой проверки поля.
Например, теперь наша модель может выглядеть так:
// app/Models/User.php
class User extends Model
public function isApproved(): bool
return $this->approved === Approval::APPROVED;
>
>
Это означает, что мы можем использовать этот метод в нашем коде следующим образом:
if ($user->isApproved())
// Сделать что-то.
>
19. Использование различных параметров режима обслуживания
Laravel предоставляет несколько опций режима обслуживания, которые могут быть очень удобны в использовании.
Для перевода вашего приложения в режим обслуживания, вы можете запустить следующую команду:
php artisan down
Вы можете обновлять страницу обслуживания через заданные промежутки времени, чтобы пользователям не приходилось обновлять её в ручную при резервном копировании сайта. Вы можете сделать это, используя параметр —refresh и указать время обновления в секундах, например:
php artisan down --refresh=30
Возможно, вы захотите предоставить себе доступ к приложению, когда оно находится в режиме обслуживания для ваших пользователей. Для этого вы можете использовать параметр —secret и задать его значение.
Например, мы могли бы установить значение —secret , как your-secret-here . Это будет означать, что если вы зайдёте на your-app-domain.com/your-secret-here , вам будет предоставлен доступ и вы сможете просматривать остальную часть приложения как обычно. Вы можете включить режим обслуживания используя параметр —secret :
php artisan down --secret="your-secret-here"
Если вы не хотите использовать страницу 503 режима обслуживания по умолчанию предоставляемую Laravel, вы можете задать свою с помощью опции —render . Например, если мы хотим использовать resources/views/errors/maintenance.blade.php :
php artisan down --render="errors/maintenance.blade.php"
20. Использование Readonly-свойств
В PHP 8.1 вы можете использовать Readonly-свойств . Они чрезвычайно полезны для уменьшения размера DTO (data transfer objects) и облегчения чтения без ненужных геттеров.
Давайте посмотрим, как DTO может выглядеть без readonly-свойств:
class StoreUserDTO
public function __construct(
private string $name,
private string $email,
private string $password,
)
//
>
public function getName(): string
return $this->name;
>
public function getEmail(): string
return $this->email;
>
public function getPassword(): string
return $this->password;
>
>
Теперь давайте взглянем на тот же DTO, используя readonly-свойства:
class StoreUserDTO
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly string $password,
)
//
>
>
Я думаю, вы согласитесь, что второй вариант с использованием readonly-свойств выглядит намного чище и проще для понимания с первого взгляда.
Заключение
Надеюсь эта статья научит вас хотя бы одному новому совету или трюку, который вы сможете использовать в своих приложениях Laravel.
Если эта статья помогла вам, я хотел бы узнать об этом. Кроме того, если у вас есть отзывы по улучшению этой статьи, я то же хотел бы узнать их.
База данных · Построитель запросов
Построитель запросов к базе данных Laravel предлагает удобный и гибкий интерфейс для создания и выполнения запросов к базе данных. Его можно использовать для выполнения большинства операций с базой данных в вашем приложении и он отлично работает со всеми поддерживаемыми Laravel системами баз данных.
Построитель запросов Laravel использует связывание параметров PDO для защиты приложения от SQL-инъекций. Нет необходимости чистить строки, передаваемые как связываемые параметры.
PDO не поддерживает связывание имен столбцов. Поэтому, вы никогда не должны использовать какие-либо входящие от пользователя данные в качестве имен столбцов, используемые вашими запросами, включая столбцы в запросах order by и т.д.
Выполнение запросов к базе данных
Получение всех строк из таблицы
Вы можете использовать метод table фасада DB , чтобы начать запрос. Метод table возвращает текущий экземпляр построителя запросов для данной таблицы, позволяя вам связать больше ограничений к запросу и, наконец, получить результаты, используя метод get :
namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\DB; class UserController extends Controller < /** * Показать список всех пользователей приложения. * * @return \Illuminate\Http\Response */ public function index() < $users = DB::table('users')->get(); return view('user.index', ['users' => $users]); > >
Метод get возвращает экземпляр Illuminate\Support\Collection , содержащий результаты запроса, где каждый результат является экземпляром объекта stdClass PHP. Вы можете получить доступ к значению каждого столбца, обратившись к столбцу как к свойству объекта:
use Illuminate\Support\Facades\DB; $users = DB::table('users')->get(); foreach ($users as $user) < echo $user->name; >
Коллекции Laravel содержат множество чрезвычайно мощных методов для работы с наборами данных. Для получения дополнительной информации о коллекциях Laravel ознакомьтесь с их документацией.
Получение одной строки / столбца из таблицы
Если вам просто нужно получить одну строку из таблицы базы данных, вы можете использовать метод first фасада DB . Этот метод вернет единственный объект stdClass :
$user = DB::table('users')->where('name', 'John')->first(); return $user->email;
Если вам не нужна вся строка, вы можете извлечь одно значение из записи с помощью метода value . Этот метод вернет значение столбца напрямую:
$email = DB::table('users')->where('name', 'John')->value('email');
Чтобы получить одну строку по значению столбца id , используйте метод find :
$user = DB::table('users')->find(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; >
Разбиение результатов
Если вам нужно работать с тысячами записей базы данных, рассмотрите возможность использования метода chunk фасада DB . Этот метод извлекает за раз небольшой фрагмент результатов и передает каждый фрагмент в функцию-аргумент для обработки. Например, давайте извлечем всю таблицу users фрагментами по 100 записей за раз:
use Illuminate\Support\Facades\DB; DB::table('users')->orderBy('id')->chunk(100, function ($users) < foreach ($users as $user) < // > >);
Вы можете остановить обработку последующих фрагментов, вернув из функции обработки false :
DB::table('users')->orderBy('id')->chunk(100, function ($users) < // Обрабатываем записи . return false; >);
Если вы обновляете записи базы данных во время фрагментирования результатов, то результаты ваших фрагментов могут измениться неожиданным образом. Если вы планируете обновлять полученные записи при фрагментировании, всегда лучше использовать вместо этого метод chunkById . Этот метод автоматически разбивает результаты на фрагменты на основе первичного ключа записи:
DB::table('users')->where('active', false) ->chunkById(100, function ($users) < foreach ($users as $user) < DB::table('users') ->where('id', $user->id) ->update(['active' => true]); > >);
При обновлении или удалении записей внутри функции-аргумента, любые изменения первичного или внешних ключей могут повлиять на запрос очередного фрагмента. Это может потенциально привести к тому, что записи могут не быть включены в последующие результаты выполнения функции.
Отложенная потоковая передача результатов
Метод lazy работает аналогично методу chunk в том смысле, что он выполняет запрос по частям. Однако вместо передачи каждого фрагмента непосредственно в функцию-обработчик, метод lazy() возвращает экземпляр LazyCollection , что позволяет вам взаимодействовать с результатами как с единым потоком:
use Illuminate\Support\Facades\DB; DB::table('users')->lazy()->each(function ($user) < // >);
Еще раз, если вы планируете обновлять полученные записи во время их итерации, лучше вместо этого использовать методы lazyById или lazyByIdDesc . Эти методы автоматически разбивают результаты «постранично» на основе первичного ключа записи:
DB::table('users')->where('active', false) ->lazyById()->each(function ($user) < DB::table('users') ->where('id', $user->id) ->update(['active' => true]); >);
При обновлении или удалении записей во время их итерации любые изменения первичного ключа или внешних ключей могут повлиять на запрос фрагмента. Это может потенциально привести к тому, что записи не будут включены в результирующий набор.
Агрегатные функции
Построитель запросов также содержит множество методов для получения агрегированных значений, таких как count , max , min , avg , и sum . После создания запроса вы можете вызвать любой из этих методов:
use Illuminate\Support\Facades\DB; $users = DB::table('users')->count(); $price = DB::table('orders')->max('price');
Конечно, вы можете комбинировать эти методы с другими выражениями, чтобы уточнить способ вычисления вашего совокупного значения:
$price = DB::table('orders') ->where('finalized', 1) ->avg('price');
Определение наличия записей
Вместо использования метода count для определения существования каких-либо записей, соответствующих ограничениям вашего запроса, используйте методы exists и doesntExist :
if (DB::table('orders')->where('finalized', 1)->exists()) < // . > if (DB::table('orders')->where('finalized', 1)->doesntExist()) < // . >
Выражения Select
Уточнения выражения Select
Возможно, вам не всегда нужно выбирать все столбцы из таблицы базы данных. Используя метод select , вы можете указать собственное выражение SELECT для запроса:
use Illuminate\Support\Facades\DB; $users = DB::table('users') ->select('name', 'email as user_email') ->get();
Метод distinct позволяет вам заставить запрос возвращать уникальные результаты:
$users = DB::table('users')->distinct()->get();
Если у вас уже есть экземпляр построителя запросов, и вы хотите добавить столбец к существующему выражению SELECT , то вы можете использовать метод addSelect :
$query = DB::table('users')->select('name'); $users = $query->addSelect('age')->get();
Сырые SQL-выражения
Иногда вам может понадобиться вставить в запрос произвольную строку, содержащую часть SQL-запроса. Для этого вы можете использовать метод raw фасада DB :
$users = DB::table('users') ->select(DB::raw('count(*) as user_count, status')) ->where('status', '<>', 1) ->groupBy('status') ->get();
Сырые выражения будут вставлены в запрос в виде строк, поэтому следует проявлять особую осторожность, чтобы не создавать уязвимости для SQL-инъекций.
Сырые sql-выражения
Вместо использования метода DB::raw , вы также можете использовать следующие методы для вставки произвольного SQL-выражения в различные части вашего запроса. Помните, Laravel не может гарантировать, что любой запрос, использующий сырые SQL-выражения, защищен от уязвимостей SQL-инъекций.
selectRaw
Метод selectRaw можно использовать вместо addSelect(DB::raw(. )) . Этот метод принимает необязательный массив параметров для подстановки в качестве второго аргумента:
$orders = DB::table('orders') ->selectRaw('price * ? as price_with_tax', [1.0825]) ->get();
whereRaw / orWhereRaw
Методы whereRaw и orWhereRaw можно использовать для вставки сырого SQL-выражения WHERE в ваш запрос. Эти методы принимают необязательный массив параметров в качестве второго аргумента:
$orders = DB::table('orders') ->whereRaw('price > IF(state = "TX", ?, 100)', [200]) ->get();
havingRaw / orHavingRaw
Методы havingRaw и orHavingRaw могут использоваться для вставки необработанной строки в качестве значения выражения HAVING . Эти методы принимают необязательный массив параметров в качестве второго аргумента:
$orders = DB::table('orders') ->select('department', DB::raw('SUM(price) as total_sales')) ->groupBy('department') ->havingRaw('SUM(price) > ?', [2500]) ->get();
orderByRaw
Метод orderByRaw используется для предоставления необработанной строки в качестве значения выражения ORDER BY :
$orders = DB::table('orders') ->orderByRaw('updated_at - created_at DESC') ->get();
groupByRaw
Метод groupByRaw используется для предоставления необработанной строки в качестве значения выражения GROUP BY :
$orders = DB::table('orders') ->select('city', 'state') ->groupByRaw('city, state') ->get();
Соединения Joins
Inner Join
Построитель запросов также может использоваться для добавления выражений соединения (join) к вашим запросам. Чтобы выполнить базовое «внутреннее соединение» (inner join), вы можете использовать метод join . Первым аргументом, передаваемым методу join , является имя таблицы, к которой вам нужно присоединиться, а остальные аргументы определяют ограничения столбца для соединения. Вы даже можете соединить несколько таблиц в один запрос:
use Illuminate\Support\Facades\DB; $users = DB::table('users') ->join('contacts', 'users.id', '=', 'contacts.user_id') ->join('orders', 'users.id', '=', 'orders.user_id') ->select('users.*', 'contacts.phone', 'orders.price') ->get();
Left Join / Right Join
Если вы хотите выполнить «левое соединение» или «правое соединение» вместо «внутреннего соединения», используйте методы leftJoin или rightJoin . Эти методы имеют ту же сигнатуру, что и метод join :
$users = DB::table('users') ->leftJoin('posts', 'users.id', '=', 'posts.user_id') ->get(); $users = DB::table('users') ->rightJoin('posts', 'users.id', '=', 'posts.user_id') ->get();
Cross Join
Вы можете использовать метод crossJoin для выполнения «перекрестного соединения». Перекрестные соединения генерируют декартово произведение между первой таблицей и соединяемой таблицей:
$sizes = DB::table('sizes') ->crossJoin('colors') ->get();
Расширенные выражения соединения
Вы также можете указать более сложные выражения соединения. Для начала передайте функцию в качестве второго аргумента методу join . Функция получит экземпляр Illuminate\Database\Query\JoinClause , который позволяет вам указать ограничения JOIN :
DB::table('users') ->join('contacts', function ($join) < $join->on('users.id', '=', 'contacts.user_id')->orOn(. ); >) ->get();
Если вы хотите использовать выражение WHERE в своих соединениях, вы можете использовать методы where и orWhere экземпляра JoinClause . Вместо сравнения двух столбцов эти методы будут сравнивать столбец со значением:
DB::table('users') ->join('contacts', function ($join) < $join->on('users.id', '=', 'contacts.user_id') ->where('contacts.user_id', '>', 5); >) ->get();
Подзапросы соединений
Вы можете использовать методы joinSub , leftJoinSub , и rightJoinSub , чтобы присоединить запрос к подзапросу. Каждый из этих методов получает три аргумента: подзапрос, псевдоним таблицы и функцию, определяющую связанные столбцы. В этом примере мы получим коллекцию пользователей, где каждая запись пользователя также содержит временную метку created_at последнего опубликованного поста пользователя в блоге:
$latestPosts = DB::table('posts') ->select('user_id', DB::raw('MAX(created_at) as last_post_created_at')) ->where('is_published', true) ->groupBy('user_id'); $users = DB::table('users') ->joinSub($latestPosts, 'latest_posts', function ($join) < $join->on('users.id', '=', 'latest_posts.user_id'); >)->get();
Объединения результатов Unions
Построитель запросов также содержит удобный метод «объединения» двух или более запросов вместе. Например, вы можете создать первый запрос и использовать метод union для объединения его с другими запросами:
use Illuminate\Support\Facades\DB; $first = DB::table('users') ->whereNull('first_name'); $users = DB::table('users') ->whereNull('last_name') ->union($first) ->get();
В дополнение к методу union , построитель запросов содержит метод unionAll . Запросы, объединенные с использованием метода unionAll , не будут удалять повторяющиеся результаты. Метод unionAll имеет ту же сигнатуру, что и метод union .
Основные выражения Where
Выражения Where
Вы можете использовать метод where построителя запросов, чтобы добавить в запрос выражения WHERE . Самый простой вызов метода where требует трех аргументов. Первый аргумент – это имя столбца. Второй аргумент – это оператор, который может быть любым из поддерживаемых базой данных операторов. Третий аргумент – это значение, которое нужно сравнить со значением столбца.
Например, следующий запрос извлекает пользователей, у которых значение столбца votes равно 100 , а значение столбца age больше, чем 35 :
$users = DB::table('users') ->where('votes', '=', 100) ->where('age', '>', 35) ->get();
Для удобства, если вы хотите убедиться, что столбец соответствует = переданному значению, то вы можете передать это значение в качестве второго аргумента в метод where . Laravel будет предполагать, что вы хотите использовать оператор = :
$users = DB::table('users')->where('votes', 100)->get();
Как упоминалось ранее, вы можете использовать любой оператор, который поддерживается вашей системой баз данных:
$users = DB::table('users') ->where('votes', '>=', 100) ->get(); $users = DB::table('users') ->where('votes', '<>', 100) ->get(); $users = DB::table('users') ->where('name', 'like', 'T%') ->get();
Вы также можете передать массив условий методу where . Каждый элемент массива должен быть массивом, содержащим три аргумента, как и обычно передаваемых методу where :
$users = DB::table('users')->where([ ['status', '=', '1'], ['subscribed', '<>', '1'], ])->get();
PDO не поддерживает привязку имен столбцов. Поэтому вы никогда не должны брать из пользовательского ввода имена столбцов для совершения запросов, включая столбцы «order by».
Выражения Or Where
При объединении в цепочку вызовов метода where построителя запросов выражения WHERE будут объединены вместе с помощью оператора AND . Однако, вы можете использовать метод orWhere для добавления выражения к запросу с помощью оператора OR . Метод orWhere принимает те же аргументы, что и метод where :
$users = DB::table('users') ->where('votes', '>', 100) ->orWhere('name', 'John') ->get();
Если вам нужно сгруппировать условие OR в круглых скобках, вы можете передать функцию в качестве первого аргумента методу orWhere :
$users = DB::table('users') ->where('votes', '>', 100) ->orWhere(function($query) < $query->where('name', 'Abigail') ->where('votes', '>', 50); >) ->get();
В приведенном выше примере будет получен следующий SQL:
select * from users where votes > 100 or (name = 'Abigail' and votes > 50)
Вы всегда должны группировать вызовы orWhere , чтобы избежать неожиданного поведения при применении глобальных диапазонов.
Выражения Where и JSON
Laravel также поддерживает запросы в базах данных, которые обеспечивают поддержку JSON-типов столбцов. В настоящее время это MySQL 5.7+, PostgreSQL, SQL Server 2016 и SQLite 3.9.0 (с расширением JSON1). Чтобы запросить столбец JSON, используйте оператор -> :
$users = DB::table('users') ->where('preferences->dining->meal', 'salad') ->get();
Вы можете использовать whereJsonContains для запроса массивов JSON. Эта функция не поддерживается базой данных SQLite:
$users = DB::table('users') ->whereJsonContains('options->languages', 'en') ->get();
Если ваше приложение использует базы данных MySQL или PostgreSQL, вы можете передать массив значений методу whereJsonContains :
$users = DB::table('users') ->whereJsonContains('options->languages', ['en', 'de']) ->get();
Вы можете использовать метод whereJsonLength для запроса массивов JSON по их длине:
$users = DB::table('users') ->whereJsonLength('options->languages', 0) ->get(); $users = DB::table('users') ->whereJsonLength('options->languages', '>', 1) ->get();
Дополнительные выражения Where
whereBetween / orWhereBetween
Метод whereBetween проверяет, находится ли значение столбца между двумя значениями:
$users = DB::table('users') ->whereBetween('votes', [1, 100]) ->get();
whereNotBetween / orWhereNotBetween
Метод whereNotBetween проверяет, что значение столбца находится вне двух значений:
$users = DB::table('users') ->whereNotBetween('votes', [1, 100]) ->get();
whereIn / whereNotIn / orWhereIn / orWhereNotIn
Метод whereIn проверяет, что значение переданного столбца содержится в указанном массиве:
$users = DB::table('users') ->whereIn('id', [1, 2, 3]) ->get();
Метод whereNotIn проверяет, что значение переданного столбца не содержится в указанном массиве:
$users = DB::table('users') ->whereNotIn('id', [1, 2, 3]) ->get();
Если вы добавляете в свой запрос большой массив связываемых целочисленных параметров, то методы whereIntegerInRaw или whereIntegerNotInRaw могут использоваться для значительного сокращения потребляемой памяти.
whereNull / whereNotNull / orWhereNull / orWhereNotNull
Метод whereNull проверяет, что значение переданного столбца равно NULL :
$users = DB::table('users') ->whereNull('updated_at') ->get();
Метод whereNotNull проверяет, что значение переданного столбца не равно NULL :
$users = DB::table('users') ->whereNotNull('updated_at') ->get();
whereDate / whereMonth / whereDay / whereYear / whereTime
Метод whereDate используется для сравнения значения столбца с датой:
$users = DB::table('users') ->whereDate('created_at', '2016-12-31') ->get();
Метод whereMonth используется для сравнения значения столбца с конкретным месяцем:
$users = DB::table('users') ->whereMonth('created_at', '12') ->get();
Метод whereDay используется для сравнения значения столбца с определенным днем месяца:
$users = DB::table('users') ->whereDay('created_at', '31') ->get();
Метод whereYear используется для сравнения значения столбца с конкретным годом:
$users = DB::table('users') ->whereYear('created_at', '2016') ->get();
Метод whereTime используется для сравнения значения столбца с определенным временем:
$users = DB::table('users') ->whereTime('created_at', '=', '11:20:45') ->get();
whereColumn / orWhereColumn
Метод whereColumn используется для проверки равенства двух столбцов:
$users = DB::table('users') ->whereColumn('first_name', 'last_name') ->get();
Вы также можете передать оператор сравнения методу whereColumn :
$users = DB::table('users') ->whereColumn('updated_at', '>', 'created_at') ->get();
Вы также можете передать массив сравнений столбцов методу whereColumn . Эти условия будут объединены с помощью оператора AND :
$users = DB::table('users') ->whereColumn([ ['first_name', '=', 'last_name'], ['updated_at', '>', 'created_at'], ])->get();
Логическая группировка
Иногда требуется сгруппировать несколько выражений WHERE в круглых скобках, чтобы добиться желаемой логической группировки вашего запроса. Фактически, вы должны всегда группировать вызовы метода orWhere в круглых скобках, чтобы избежать неожиданного поведения запроса. Для этого вы можете передать функцию методу where :
$users = DB::table('users') ->where('name', '=', 'John') ->where(function ($query) < $query->where('votes', '>', 100) ->orWhere('title', '=', 'Admin'); >) ->get();
Как вы можете видеть, передача функции в метод where инструктирует построитель запросов начать группу ограничений. Функция получит экземпляр построителя запросов, который вы можете использовать для задания ограничений, которые должны содержаться в группе скобок. В приведенном выше примере будет получен следующий SQL:
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
Вы всегда должны группировать вызовы orWhere , чтобы избежать неожиданного поведения при применении глобальных диапазонов.
Расширенные выражения Where
Выражения Where Exists
Метод whereExists позволяет писать выражения WHERE EXISTS SQL. Метод whereExists принимает функцию, которая получит экземпляр построителя запросов, позволяя вам определить запрос, который должен быть помещен внутри выражения EXISTS :
$users = DB::table('users') ->whereExists(function ($query) < $query->select(DB::raw(1)) ->from('orders') ->whereColumn('orders.user_id', 'users.id'); >) ->get();
В приведенном выше примере будет получен следующий SQL:
select * from users where exists ( select 1 from orders where orders.user_id = users.id )
Подзапросы выражений Where
Иногда требуется создать выражение WHERE , которое сравнивает результаты подзапроса с переданным значением. Вы можете добиться этого, передав функцию и значение методу where . Например, следующий запрос будет извлекать всех пользователей, недавно имевших «членство» указанного типа:
use App\Models\User; $users = User::where(function ($query) < $query->select('type') ->from('membership') ->whereColumn('membership.user_id', 'users.id') ->orderByDesc('membership.start_date') ->limit(1); >, 'Pro')->get();
Или вам может потребоваться создать выражение «where», которое сравнивает столбец с результатами подзапроса. Вы можете сделать это, передав методу where столбец, оператор и функцию. Например, следующий запрос будет извлекать все записи о доходах, где сумма меньше средней:
use App\Models\Income; $incomes = Income::where('amount', ', function ($query) < $query->selectRaw('avg(i.amount)')->from('incomes as i'); >)->get();
Сортировка, группировка, ограничение и смещение
Сортировка
Метод orderBy
Метод orderBy позволяет вам сортировать результаты запроса по конкретному столбцу. Первый аргумент, принимаемый методом orderBy , должен быть столбцом, по которому вы хотите выполнить сортировку, а второй аргумент определяет направление сортировки и может быть либо asc , либо desc :
$users = DB::table('users') ->orderBy('name', 'desc') ->get();
Для сортировки по нескольким столбцам вы можете просто вызывать orderBy столько раз, сколько необходимо:
$users = DB::table('users') ->orderBy('name', 'desc') ->orderBy('email', 'asc') ->get();
Методы latest и oldest
Методы latest и oldest позволяют легко упорядочивать результаты по дате. По умолчанию результат будет упорядочен по столбцу created_at таблицы. Или вы можете передать имя столбца, по которому хотите сортировать:
$user = DB::table('users') ->latest() ->first();
Случайный порядок
Метод inRandomOrder используется для случайной сортировки результатов запроса. Например, вы можете использовать этот метод для выборки случайного пользователя:
$randomUser = DB::table('users') ->inRandomOrder() ->first();
Удаление существующих сортировок
Метод reorder удаляет все выражения ORDER BY , которые ранее были применены к запросу:
$query = DB::table('users')->orderBy('name'); $unorderedUsers = $query->reorder()->get();
Вы можете передать столбец и направление при вызове метода reorder , чтобы удалить все существующие выражения ORDER BY и применить к запросу совершенно новый порядок:
$query = DB::table('users')->orderBy('name'); $usersOrderedByEmail = $query->reorder('email', 'desc')->get();
Группировка
Методы groupBy и having
Как и следовало ожидать, для группировки результатов запроса могут использоваться методы groupBy и having . Сигнатура метода having аналогична сигнатуре метода where :
$users = DB::table('users') ->groupBy('account_id') ->having('account_id', '>', 100) ->get();
Вы можете использовать метод havingBetween для фильтрации результатов в заданном диапазоне:
$report = DB::table('orders') ->selectRaw('count(id) as number_of_orders, customer_id') ->groupBy('customer_id') ->havingBetween('number_of_orders', [5, 15]) ->get();
Вы можете передать несколько аргументов методу groupBy для группировки по нескольким столбцам:
$users = DB::table('users') ->groupBy('first_name', 'status') ->having('account_id', '>', 100) ->get();
Чтобы создать более сложные операторы having , см. метод havingRaw .
Ограничение и смещение
Методы skip и take
Вы можете использовать методы skip и take , чтобы ограничить количество результатов, возвращаемых запросом, или пропустить указанное количество результатов из запроса:
$users = DB::table('users')->skip(10)->take(5)->get();
Как вариант, вы можете использовать методы limit и offset . Эти методы функционально эквивалентны методам take и skip соответственно:
$users = DB::table('users') ->offset(10) ->limit(5) ->get();
Условные выражения
Иногда может потребоваться, чтобы определенные выражения запроса применялись к запросу на основании другого условия. Например, бывает необходимо применить оператор WHERE только в том случае, если переданное входящее значение присутствует в HTTP-запросе. Вы можете сделать это с помощью метода when :
$role = $request->input('role'); $users = DB::table('users') ->when($role, function ($query, $role) < return $query->where('role_id', $role); >) ->get();
Метод when выполняет переданную функцию-аргумент только тогда, когда первый аргумент равен true . Если первый аргумент – false , функция не будет выполнена. Итак, в приведенном выше примере функция метода when будет вызываться только в том случае, если поле role присутствует во входящем запросе и оценивается как true .
Вы можете передать другую функцию в качестве третьего аргумента методу when . Это функция будет выполнена только в том случае, если первый аргумент оценивается как false . Чтобы проиллюстрировать этот функционал, определим порядок вывода записей по умолчанию для запроса:
$sortByVotes = $request->input('sort_by_votes'); $users = DB::table('users') ->when($sortByVotes, function ($query, $sortByVotes) < return $query->orderBy('votes'); >, function ($query) < return $query->orderBy('name'); >) ->get();
Вставка
Построитель запросов также содержит метод insert , который можно использовать для вставки записей в таблицу базы данных. Метод insert принимает массив имен и значений столбцов:
DB::table('users')->insert([ 'email' => 'kayla@example.com', 'votes' => 0 ]);
Вы можете вставить сразу несколько записей, передав массив массивов. Каждый из массивов представляет собой запись, которую нужно вставить в таблицу:
DB::table('users')->insert([ ['email' => 'picard@example.com', 'votes' => 0], ['email' => 'janeway@example.com', 'votes' => 0], ]);
Метод insertOrIgnore будет игнорировать ошибки повторяющихся записей при вставке записей в базу данных:
DB::table('users')->insertOrIgnore([ ['id' => 1, 'email' => 'sisko@example.com'], ['id' => 2, 'email' => 'archer@example.com'], ]);
insertOrIgnore будет игнорировать дубликаты записей, а также может игнорировать другие типы ошибок в зависимости от движка базы данных. Например, insertOrIgnore будет обходить строгий режим MySQL.
Автоинкрементирование идентификаторов
Если таблица имеет автоинкрементный идентификатор, то используйте метод insertGetId , чтобы вставить запись и затем получить идентификатор этой записи:
$id = DB::table('users')->insertGetId( ['email' => 'john@example.com', 'votes' => 0] );
При использовании PostgreSQL метод insertGetId ожидает, что автоинкрементный столбец будет называться id . Если вы хотите получить идентификатор из другой «последовательности», вы можете передать имя столбца в качестве второго параметра методу insertGetId .
Обновления-вставки
Метод upsert вставляет записи, которые не существуют, и обновляет записи, которые уже существуют, новыми значениями, которые вы можете указать. Первый аргумент метода состоит из значений для вставки или обновления, а второй аргумент перечисляет столбцы, которые однозначно идентифицируют записи в связанной таблице. Третий и последний аргумент метода – это массив столбцов, который следует обновить, если соответствующая запись уже существует в базе данных:
DB::table('flights')->upsert([ ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99], ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150] ], ['departure', 'destination'], ['price']);
В приведенном выше примере Laravel попытается вставить две записи. Если запись уже существует с такими же значениями столбцов departure и destination , то Laravel обновит столбец price этой записи.
Все базы данных, кроме SQL Server, требуют, чтобы столбцы во втором аргументе метода upsert имели «первичный» или «уникальный» индекс. Вдобавок, драйвер базы данных MySQL игнорирует второй аргумент метода upsert и всегда использует «первичный» и «уникальный» индексы таблицы для обнаружения существующих записей.
Обновление
Помимо вставки записей в базу данных, построитель запросов также может обновлять существующие записи с помощью метода update . Метод update , как и метод insert , принимает массив пар столбцов и значений, указывающих столбцы, которые нужно обновить. Вы можете ограничить запрос update с помощью выражений WHERE :
$affected = DB::table('users') ->where('id', 1) ->update(['votes' => 1]);
Обновление или вставка
Иногда требуется обновить существующую запись в базе данных или создать ее, если соответствующей записи не существует. В этом сценарии может использоваться метод updateOrInsert . Метод updateOrInsert принимает два аргумента: массив условий, по которым нужно найти запись, и массив пар столбцов и значений, указывающих столбцы, которые нужно обновить.
Метод updateOrInsert попытается найти соответствующую запись в базе данных, используя пары столбец и значение первого аргумента. Если запись существует, она будет обновлена значениями второго аргумента. Если запись не может быть найдена, будет вставлена новая запись с объединенными атрибутами обоих аргументов:
DB::table('users') ->updateOrInsert( ['email' => 'john@example.com', 'name' => 'John'], ['votes' => '2'] );
Обновление столбцов JSON
При обновлении столбца JSON вы должны использовать синтаксис -> для обновления соответствующего ключа в объекте JSON. Эта операция поддерживается в MySQL 5.7+ и PostgreSQL 9.5+:
$affected = DB::table('users') ->where('id', 1) ->update(['options->enabled' => true]);
Увеличение и уменьшение отдельных значений
Конструктор запросов также содержит удобные методы увеличения или уменьшения значения конкретного столбца. Оба метода принимают по крайней мере один аргумент: столбец, который нужно изменить. Может быть указан второй аргумент, определяющий величину, на которую следует увеличить или уменьшить столбец:
DB::table('users')->increment('votes'); DB::table('users')->increment('votes', 5); DB::table('users')->decrement('votes'); DB::table('users')->decrement('votes', 5);
Вы также можете указать дополнительные столбцы для обновления во время выполнения запроса:
DB::table('users')->increment('votes', 1, ['name' => 'John']);
Удаление
Метод delete может использоваться для удаления записей из таблицы. Он возвращает количество затронутых строк. Вы можете ограничить операторы delete , добавив метод where перед вызовом метода delete :
$deleted = DB::table('users')->delete(); $deleted = DB::table('users')->where('votes', '>', 100)->delete();
Если вы хотите очистить всю таблицу, что приведет к удалению всех записей из таблицы и сбросу автоинкрементного идентификатора на ноль, вы можете использовать метод truncate :
DB::table('users')->truncate();
Очистка таблицы и PostgreSQL
При очистке базы данных PostgreSQL будет применено поведение CASCADE . Это означает, что все связанные с внешним ключом записи в других таблицах также будут удалены.
Пессимистическая блокировка
Построитель запросов также включает несколько функций, которые помогут вам достичь «пессимистической блокировки» при выполнении ваших операторов SELECT . Чтобы выполнить оператор с «совместной блокировкой», вы можете вызвать метод sharedLock в запросе. Совместная блокировка предотвращает изменение выбранных строк до тех пор, пока ваша транзакция не будет зафиксирована:
DB::table('users') ->where('votes', '>', 100) ->sharedLock() ->get();
В качестве альтернативы вы можете использовать метод lockForUpdate . Блокировка «для обновления» предотвращает изменение выбранных записей или их выбор с помощью другой совместной блокировки:
DB::table('users') ->where('votes', '>', 100) ->lockForUpdate() ->get();
Отладка
Вы можете использовать методы dd или dump при построении запроса, чтобы отобразить связанные параметры запроса и сам SQL-запрос. Метод dd отобразит отладочную информацию и затем прекратит выполнение запроса. Метод dump отобразит информацию об отладке, но позволит продолжить выполнение запроса:
DB::table('users')->where('votes', '>', 100)->dd(); DB::table('users')->where('votes', '>', 100)->dump();
Русскоязычное комьюнити
- Группа в VK
- Телеграм LaravelRUS
- Телеграм Laravel для новичков
- Телеграм LaravelPro
Обучающие ресурсы
- Laracasts
- Codecourse
- Курс Дмитрия Елисеева
- Adam Wathan
Блоги разработчиков
- Laravel News
- Freek Van der Herten
- Brent Roose
- Marcel Pociot