Команда Laravel выпустила версию v13.36.0, в которую вошли построители  Rule::  для правил валидации, ранее имевших только строковый синтаксис,  DB::olap()  для больших запросов в PlanetScale и других базах данных Vitess, опциональный сброс залипающих (sticky) соединений с базой данных между задачами очереди, синхронные бродкасты Mercure по умолчанию и многое другое.

#Построители правил для оставшихся правил валидации

@ericmp33 добавил метод  Rule::  для каждого правила валидации, у которого его еще не было. Такие правила, как  required_with ,  accepted_if ,  url ,  uuid  и  distinct , теперь можно записывать с помощью методов, которые ваша IDE сможет дополнять автоматически:

use Illuminate\Validation\Rule;
 
$request->validate([
    'phone' => [Rule::requiredWithout('email')],
    'website' => ['nullable', Rule::url()->protocols(['https'])],
    'device_id' => [Rule::uuid()->version(4)],
    'tags.*' => [Rule::distinct()->ignoreCase()],
    'password' => ['required', Rule::confirmed()],
]);
 

Правила без параметров, такие как  Rule::required()  и  Rule::nullable() , возвращают простую строку правила. Правила, принимающие имена полей или значения, возвращают объект, который передает свои параметры валидатору в виде массива, поэтому значение, содержащее запятую, больше не разделяется на два значения. В PR также добавлено  equals()  в гибкий построитель  Rule::date() .

Подробности смотрите в #61833.

#DB::olap() для PlanetScale и Vitess

Jack Bayliss добавил  olap()  и  isVitess()  в соединение MySQL. PlanetScale работает на базе Vitess, которая ограничивает запросы в своей стандартной рабочей нагрузке OLTP. В PlanetScale один запрос может вернуть максимум 100 000 строк. Метод  olap()  переключается на рабочую нагрузку OLAP на время выполнения колбэка и возвращает все обратно после его завершения:

$revenue = DB::olap(fn () => Order::query()
    ->selectRaw('customer_id, sum(total) as revenue')
    ->where('created_at', '>=', now()->subYears(3))
    ->groupBy('customer_id')
    ->get()
);
 

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

Подробности смотрите в #61932.

#Сброс залипающих соединений между задачами очереди

Если для соединения с базой данных чтения/записи включено  sticky , операция записи направляет последующие чтения на соединение записи. Воркер очереди — это долго работающий процесс, поэтому одна задача, выполняющая запись, может направить чтение всех последующих задач в этом воркере на соединение записи. Jack Bayliss добавил опциональный флаг, который сбрасывает состояние перед каждой задачей:

use Illuminate\Queue\Worker;
 
// AppServiceProvider::boot()
Worker::$flushStickyConnections = true;
 

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

Подробности смотрите в #61915.

#Трансляции Mercure по умолчанию выполняются синхронно

Kévin Dunglas изменил бродкастер Mercure так, чтобы он публиковал события сразу, а не помещал их в очередь. События, предназначенные только для соединений Mercure, теперь ведут себя как  ShouldBroadcastNow , а события, затрагивающие и другие соединения, по-прежнему отправляются в очередь. Установите  MERCURE_ASYNC=true , чтобы снова отправлять их в очередь. Асинхронному режиму требуется Mercure  url , поскольку воркеры очередей выполняют публикацию по протоколу HTTP:

MERCURE_URL="${APP_URL}/.well-known/mercure"
MERCURE_ASYNC=true
 

Этот же PR исправляет падение команд Artisan с ошибкой  BROADCAST_CONNECTION=mercure , когда не задан  url  и недоступна функция FrankenPHP  mercure_publish() .

Подробности смотрите в #61977.

#DeleteWhenMissingModels и FailOnTimeout для писем в очереди

Volodya Kurshudyan исправил проблему, из-за которой письма в очереди игнорировали атрибуты  #[DeleteWhenMissingModels]  и  #[FailOnTimeout] , а также соответствующие им свойства:

#[DeleteWhenMissingModels]
class OrderShipped extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;
 
    public function __construct(public Order $order) {}
}
 

Если заказ удален до отправки письма, задача теперь просто удаляется, вместо того чтобы завершаться с ошибкой  ModelNotFoundException . С помощью  #[FailOnTimeout]  письмо, превысившее время ожидания (timeout), помечается как упавшее, вместо того чтобы отправляться повторно (что могло привести к двойной отправке).

Подробности смотрите в #61899.

#Экранирование в письмах Markdown

Stephen Rees-Carter исправил экранирование пользовательского ввода в классах писем Markdown. Значение, размещенное в тексте ссылки Markdown, могло содержать обратную косую черту для экранирования закрывающей квадратной скобки, что позволяло изменить целевой адрес ссылки. Теперь обратные слеши экранируются наравне со скобками.

Подробности смотрите в #61755.

#Примечания к релизу

Полный список новых функций и обновлений представлен ниже, а разницу между версиями 13.35.0 и 13.36.0 можно посмотреть на GitHub. Следующие примечания к релизу взяты напрямую из списка изменений (changelog):

#v13.36.0

  • [12.x] Сделать код выхода воркера по таймауту доступным от @kieranbrown в #61623
  • [12.x] Добавить поддержку именованных поставщиков учетных данных S3 и дисков Cloud IAM от @kieranbrown в #61757
  • [12.x] Исправить проблемы с запросами от @taylorotwell в #61838
  • [12.x] Бэкпорт EncodedParameter из #61610 от @mahdyaralipor в #61871
  • [12.x] Генерировать другой файл кэша в зависимости от настроенного  $echoFormat  от @crynobone в #61822
  • [13.x] Добавить фоновое соединение в конфигурацию очереди по умолчанию от @svidskiy в #61917
  • [13.x] Разрешить воркерам очередей сбрасывать залипающие соединения между задачами от @jackbayliss в #61915
  • [13.x] Разрешить null в docblock для TestResponse::$streamedContent от @alies-dev в #61914
  • [13.x] Добавить поддержку  DeleteWhenMissingModels  и  FailOnTimeout  для писем в очереди от @xurshudyan в #61899
  • [13.x] Пересоздавать клиент phpredis, если ни один узел кластера не доступен от @cwang22 в #61911
  • [13.x] Включать соединение в вывод команды queue:work --json paused и resumed от @jackbayliss в #61896
  • Исправить утечку памяти в наборах тестов, вызываемую Prompts, от @timacdonald в #61872
  • [13.x] Исправить игнорирование Notification::locale() после отправки уведомления от @Taldres в #61904
  • [13.x] Разрешать псевдонимы карты морфизма (morph map aliases) в  constrain() ,  morphWith()  и  loadMorph()  от @xurshudyan в #61898
  • [13.x] Распознавать ошибки сбоя SSL EOF в PgBouncer как потерянные соединения от @0x15f в #61918
  • [13.x] Включать очередь и соединение в вывод команды queue:work --json stop от @jackbayliss в #61858
  • [13.x] Сохранять собственные команды консольного ядра на экземпляре ядра от @bert-w в #61931
  • [13.x] Сохранять числовые ключи в JSON-файлах переводов, загружаемых с помощью  FileLoader , от @sajjadhossainshohag в #61925
  • Исправить сброс верхней границы в Number::pairs() при начале новой пары от @abdulmajidcse в #61921
  • [13.x] Исправить игнорирование  retry_after  почтовыми службами failover и roundrobin от @xurshudyan в #61927
  • [13.x] Исправить сообщения eventStream(), содержащие переводы строк, от @sajjadhossainshohag в #61923
  • Предотвратить обход защиты через экранирование от @valorin в #61755
  • [13.x] Добавить IsVitess() и olap() в MySqlConnection от @jackbayliss в #61932
  • [13.x] Добавить построители правил валидации для оставшихся правил от @ericmp33 в #61833
  • [13.x] Освобождать постоянный сокет phpredis перед пересозданием клиента от @0x15f в #61919
  • [13.x] Добавить поддержку  phpstan/phpstan:2.3.1  от @SanderMuller в #61939
  • [13.x] Исправить генерацию запроса touch() для отношений HasOneOrManyThrough от @HamidRezaLS в #61942
  • [13.x] Исправить циклические ссылки в ограничениях мягкого удаления MorphTo от @babrmonta в #61944
  • [13.x] Скорректировать воркер, чтобы он не вызывал killback дважды от @jackbayliss в #61940
  • [13.x] Исправить выброс неверного исключения для отсутствующих ключей в  Context::pop()  от @xurshudyan в #61936
  • [13.x] Улучшить типы возвращаемых коллекций BelongsToMany от @axlon в #61954
  • [13.x] Сделать  Schema::getColumn()  нечувствительным к регистру от @svidskiy в #61967
  • [13.x] Исправить потерю обновлений путей JSON после чтения аксессора Attribute от @xurshudyan в #61962
  • [13.x] Исправить применение  Notification::locale()  к последующим уведомлениям от @sumaiazaman в #61959
  • [13.x] Восстановить короткое замыкание (short-circuiting) в Arr::first() для итерируемых объектов от @DirkHoffman в #61957
  • [13.x] Объединять отправку уведомлений очереди Redis в пакеты от @hectorgrecco в #61965
  • [13.x] Уменьшить дублирование кода в  setTrustedProxyIpAddresses()  от @weshooper в #61963
  • Применить исправления от StyleCI от @taylorotwell в #61969
  • [13.x] Удалить дублирующийся и неиспользуемый код из тестов View от @xurshudyan в #61976
  • [13.x] Исправить повторный выброс предыдущего исключения запланированными колбэками при последующих запусках от @sumaiazaman в #61973
  • [13.x] Исправить проблему, когда блокировки уникальных слушателей в очереди не освобождались при отмене транзакции от @sumaiazaman в #61974
  • Обновить группу github-actions с помощью 3 обновлений от @dependabot в #61990
  • [13.x] Скорректировать UniqueJobTest от @jackbayliss в #61985
  • [13.x] fix(broadcasting): распознавать атрибуты UniqueFor на событиях от @calebdw в #61981
  • [13.x] Исправить тайм-ауты процессов длительностью менее секунды, заданные как CarbonInterval, от @xurshudyan в #61979
  • [13.x] Исправить хаб FrankenPHP Mercure в CLI и сделать трансляцию событий Mercure синхронной по умолчанию от @dunglas в #61977
  • [13.x] Предотвратить рекурсивные переподключения во время переподключения соединения от @virtualtear в #61995
  • [13.x] Пропускать поиск контекстных привязок, если они не зарегистрированы от @xurshudyan в #61993
  • [13.x] Исправить пропуск приведения типов (casts) для дополнительных атрибутов при инкременте или декременте модели от @sumaiazaman в #61991