Команда Laravel выпустила версию 13.35.0, в которой появились  Route::query()  для HTTP-маршрутов  QUERY , опциональный метод  defaults()  для моделей Eloquent, массивы свойств в заглушках (fake assertions) для очередей, шин событий, событий и уведомлений, процентные лимиты памяти для  queue:work , два дополнения к планировщику для многосерверных конфигураций и деплоя, а также многое другое.

#Route::query()

Joel Butcher добавил  Route::query()  в Laravel 13. Он регистрирует маршрут для HTTP-метода  QUERY  — безопасного метода, который поддерживает тело запроса, что удобно для поисковых эндпоинтов с фильтрами, слишком большими для строки запроса:

Route::query('/products/search', SearchProductsController::class);
 

В Laravel 13.19 были добавлены  Http::query() , а также вспомогательные методы тестирования  query()  и  queryJson() , но определение маршрута означало  Route::match(['QUERY'], ...) .  QUERY  теперь входит в список глаголов маршрутизатора, поэтому  Route::any()  и  Route::redirect()  также соответствуют ему.

В отличие от версии, объединенной для Laravel 14, здесь сохраняется контракт  Registrar , а CSRF-защита по-прежнему проверяет запросы  QUERY  так же, как и запросы  POST . Для маршрута  QUERY  в группе middleware  web  требуется CSRF-токен или запись в списке  except . Наш туториал по использованию метода HTTP QUERY с поиском Scout охватывает клиентскую часть.

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

#Model defaults() с HasDefaultAttributes

Wes Hooper перенес метод модели  defaults()  из Laravel 14 в Laravel 13 в виде опционального трейта.  defaults()  — это метод-аналог свойства  $attributes , поэтому значения по умолчанию могут поступать из конфигурации, флагов функций или текущей даты. В Laravel 13 модель должна использовать трейт  HasDefaultAttributes , чтобы метод заработал:

use Illuminate\Database\Eloquent\Concerns\HasDefaultAttributes;
 
class Subscription extends Model
{
    use HasDefaultAttributes;
 
    protected function defaults(): array
    {
        return [
            'cancelled' => false,
            'trial_days' => Feature::active('extended-trials') ? 30 : 14,
        ];
    }
}
 

Трейт позволяет избежать влияния изменений на модели, у которых уже есть метод с именем  defaults() . Значения из  defaults()  имеют приоритет над  $attributes , и они являются «сырыми», поэтому пропускают приведение типов (casts) и мутаторы.

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

#Массивы свойств в Fake Assertions

Jack Bayliss обновил заглушки  Queue ,  Bus ,  Event  и  Notification , чтобы они принимали массив ожидаемых значений свойств там, где раньше принимали callback:

// Before
Queue::assertPushed(ProcessPodcast::class, function (ProcessPodcast $job) use ($podcast, $user) {
    return $job->podcast->is($podcast)
        && $job->user->is($user)
        && $job->status === 'pending';
});
 
// After
Queue::assertPushed(ProcessPodcast::class, [
    'podcast' => $podcast,
    'user' => $user,
    'status' => 'pending',
]);
 

Каждое значение сравнивается на строгое равенство, за исключением моделей Eloquent, которые сравниваются с помощью  is() . Свойства должны быть публичными, так как заглушка считывает их извне объекта.

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

#Процентные лимиты памяти для queue:work

Jack Bayliss также обновил опцию  --memory  в  queue:work , чтобы она принимала процент от  memory_limit  PHP, благодаря чему лимит воркера следует за размером контейнера, а не за фиксированным количеством мегабайт:

php artisan queue:work --memory=60%
 

При  memory_limit , равном  512M , воркер остановится после выполнения задачи, как только использует около 307 МБ. Если  memory_limit  равен  -1 , что обычно для PHP CLI, процент превращается в отрицательное число, и воркер никогда не остановится по памяти. Установите  memory_limit  для процесса воркера, если используете проценты.

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

#Schedule::alwaysOnOneServer()

Планировщик, запущенный на нескольких серверах или репликах, выполняет каждую задачу на каждом из них, если только задача не вызывает  onOneServer() . Третий PR от Jack Bayliss добавляет  Schedule::alwaysOnOneServer() , который применяет  onOneServer()  к каждой запланированной задаче:

// AppServiceProvider::boot()
Schedule::alwaysOnOneServer();
 

До сих пор единственным вариантом было обернуть каждую задачу в  routes/console.php  внутри вызова  Schedule::onOneServer()->group() . Задачи-замыкания без имени пропускаются, потому что  onOneServer()  требует имя для создания блокировки. Как и  onOneServer() , это требует кэш-драйвер, общий для всех серверов.

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

#Остановка долго выполняющихся запланированных команд при деплое

 php artisan schedule:interrupt  останавливает цикл внутри минуты в  schedule:run , но команда, запущенная с помощью  runInBackground() , этого не видела. cyppe изменил прерывание так, чтобы оно сохраняло временную метку, аналогично тому, как работает  queue:restart , и добавил  Schedule::hasBeenInterruptedSince() , чтобы длинная команда могла остановиться в безопасной точке:

use Illuminate\Console\Scheduling\Schedule;
 
public function handle(Schedule $schedule)
{
    $startedAt = now();
 
    foreach ($this->batches() as $batch) {
        if ($schedule->hasBeenInterruptedSince($startedAt)) {
            return;
        }
 
        $this->process($batch);
    }
}
 

 schedule:run  использует ту же проверку, поэтому прерывание, произошедшее ранее в течение минуты, больше не останавливает выполнение, начавшееся после него.

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

#response()->markdown()

Ashot Gharakeshishyan добавил метод  markdown()  в фабрику ответов, который работает в паре с существующим методом запроса  wantsMarkdown() :

return $request->wantsMarkdown()
    ? response()->markdown($post->markdown)
    : view('posts.show', ['post' => $post]);
 

Он возвращает обычный ответ с типом контента  text/markdown  и принимает статус и заголовки, как  response()->make() .

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

#Ленивое создание корня для локальных дисков

Jamie York добавил опцию  lazy_root_creation  для дисков  local . По умолчанию локальный адаптер Flysystem создает корневой каталог при создании диска. Если эта опция установлена в  true , каталог создается при записи первого файла:

'reports' => [
    'driver' => 'local',
    'root' => storage_path('app/reports'),
    'lazy_root_creation' => true,
],
 

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

#Примечания к выпуску

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

#v13.35.0

  • [13.x] Разрешить fake assertions принимать массив свойств от @jackbayliss в #61770
  • [13.x] Поддержка процентов для queue:work --memory от @jackbayliss в #61753
  • [13.x] Позволить долго выполняющимся запланированным командам видеть schedule:interrupt от @cyppe в #61764
  • [13.x] Сделать параллельные callback-функции скомпилированных представлений устойчивыми к параллельному запуску от @joshdaugherty в #61786
  • [13.x] Добавить метод markdown() в фабрику ответов от @Ashot1995 в #61800
  • [13.x] Добавить  onOneServer  в вывод  schedule:list --json  от @MizouziE в #61798
  • [13.x] Добавить опцию конфигурации  lazy_root_creation  для дисков  local  от @ziadoz в #61799
  • [13.x] Улучшения тестирования от @crynobone в #61790
  • Улучшения исключений от @timacdonald в #61791
  • [13.x] Добавить Schedule::alwaysOnOneServer(); от @jackbayliss в #61789
  • [13.x] Добавить тест для notifyJobOfSignal SIGALRM от @jackbayliss в #61787
  • [13.x] Оптимизировать Str::finish и Str::start от @HamidRezaLS в #61803
  • [13.x] Исправить цикл ссылок в callback-функции по умолчанию PendingRequest::throw() от @andrewnabors в #61802
  • [13.x] Исправить Memcached lock isLocked() для свободной блокировки от @mrjavadseydi в #61801
  • [13.x] Добавить поддержку метода маршрута QUERY от @joelbutcher в #61797
  • [13.x] Исправить DatabaseRule where() и whereNot(), теряющие значения false от @sajjadhossainshohag в #61796
  • [13.x] Исправить вспомогательные функции длительности, обрезающие значения float от @xurshudyan в #61825
  • [13.x] Освобождать уникальные блокировки заданий в  Queue::fakeFor()  от @xurshudyan в #61824
  • [13.x] Исправить  forceCreate() , игнорирующий  withAttributes()  от @xurshudyan в #61823
  • [13.x] Исправить  has()  и  withCount()  в отношениях  HasOneThrough  one-of-many от @xurshudyan в #61818
  • [13.x] Принимать null пароль в hashPasswordForCookie от @troioi-vn в #61817
  • [13.x] Исправить  chunkById()  и  lazyById() , зацикливающиеся на моделях с приведенным первичным ключом от @xurshudyan в #61816
  • [13.x] Исправить custom MorphPivot, не затрагивающий владельцев при отсоединении (detach) от @mrjavadseydi в #61812
  • [13.x] Исправить collapse(), collapseWithKeys() и flatten(), отбрасывающие ленивые коллекции от @ahmadreza-fatemikia в #61811
  • [13.x] Исправить DB::setDefaultConnection(), сохраняющий перечисления (enums) в конфигурации от @ahmadreza-fatemikia в #61810
  • [13.x] Нормализовать очередь в методе SQS bulk от @jackbayliss в #61828
  • [13.x] Исправить  HasOneThrough::is() , сравнивающий неверные ключи от @xurshudyan в #61827
  • [13.x] Исправить игнорирование унаследованных атрибутов очереди, когда дочерний элемент использует Queueable от @xurshudyan в #61826
  • [13.x] Исправить обновления пути JSON в  AsEncryptedArrayObject  и  AsEncryptedCollection  от @xurshudyan в #61834
  • Исправить сопоставление корневого маршрута с кэшем маршрутов при обслуживании из подкаталога от @Simon0Harms в #61794
  • Решить проблемы с запросами от @taylorotwell в #61837
  • [13.x] Документировать поддержку перечислений (enum) для диска в  copyToDisk()  и  moveToDisk()  от @riesjart в #61867
  • [13.x] Пропускать построение запроса в loadMissing(), когда отношения не заданы от @MAboyadak в #61869
  • [13.x] Принимать перечисления (enums) в  FilesystemManager::set() ,  forgetDisk()  и  purge()  от @riesjart в #61868
  • [13.x] Исправить параллельное тестирование с PHPUnit 13.4 от @lazerg в #61859
  • [13.x] Исправить  AsHtmlString  атрибуты, сериализующиеся в пустой объект от @xurshudyan в #61854
  • [13.x] Исправить  whereJsonOverlaps()  с путем JSON в MySQL от @xurshudyan в #61853
  • [13.x] Исправить цикл ссылок в callback-функциях Mailable headers() и priority() от @xurshudyan в #61863
  • [13.x] Исправить  findOrNew()  и  chunkMap()  в HasManyThrough и BelongsToMany от @xurshudyan в #61855
  • [13.x] Исправить  incrementOrCreate() , не устанавливающий внешний ключ в отношениях от @xurshudyan в #61849
  • [13.x] Исправить  loadMissing()  с вложенными отношениями в смешанных  morphTo  моделях от @xurshudyan в #61845
  • [13.x] Исправить Eloquent Collection findOrFail() с коллекцией идентификаторов от @xurshudyan в #61844
  • [13.x] Исправить  cursorPaginate() , теряющий привязки union select и join от @xurshudyan в #61841
  • [13.x] Исправить docblocks метода  logoutOtherDevices  от @imanghafoori1 в #61877
  • [13.x] Исправить обновления пути JSON, отбрасывающие несохраненные изменения в приведенных объектах от @xurshudyan в #61847
  • [13.x ]  never  тип возвращаемого значения для метода  failedBasicResponse  от @imanghafoori1 в #61887
  • [13.x] Исправить сбои загрузки файлов с именами без эквивалента ASCII от @jhm-ciberman в #61888
  • [13.x] Квалифицировать столбцы eager loaded в отношениях through и one-of-many от @xurshudyan в #61885
  • [13.x] Исправить утечку переработанных моделей в последующие вызовы той же фабрики от @xurshudyan в #61884
  • [13.x] Использовать заглушку для pwnedpasswords API в ValidationPasswordRuleTest::testMessagesOrder от @xurshudyan в #61880
  • [13.x] Исправить  morphTo()->withTrashed() , игнорируемый  has()  и  whereHasMorph()  от @xurshudyan в #61846
  • [13.x] Исправить  incrementOrCreate() , игнорирующий дополнительные атрибуты при создании от @xurshudyan в #61878
  • [13.x] Исправить неопределенный ключ массива в GenericUser::getAuthPassword() для пользователей без пароля от @tommie1001 в #61876
  • [13.x] Улучшения тестирования базы данных от @jnoordsij в #61819
  • [13.x] Перенести  defaults()  через опциональный трейт от @weshooper в #61813
  • Обновить source-map-js с 1.2.1 до 1.2.2 в /src/Illuminate/Foundation/resources/exceptions/renderer от @dependabot в #61889
  • [13.x] Исправить  schedule:list  преобразование часового пояса, когда следующие запуски приходятся на переход на летнее время от @xiCO2k в #61894
  • [13.x] Не разворачивать URL-шаблоны без параметров URL от @xurshudyan в #61893
  • [13.x] Игнорировать _token и _method при сбое на неизвестных полях от @xurshudyan в #61891
  • [13.x] Исправить  withCasts()  в клонированном запросе, изменяющем приведения (casts) исходного запроса от @xurshudyan в #61883
Входные данные пусты. Пожалуйста, предоставьте HTML-фрагмент для перевода.