Команда Laravel выпустила версию v13.33.0 с поддержкой тегов для мемоизированного кэша, атрибутом модели Refreshes , который перезагружает сгенерированные колонки после записи, и многим другим:
#Мемоизированный кэш с тегами
Joost de Bruijn добавил метод tags() в хранилище мемоизированного кэша, так что Cache::memo() теперь работает с кэшем, содержащим теги. Чтения в рамках одного запроса обращаются к бэкенду кэша один раз, а после этого берутся из памяти:
// Two calls, one round trip to Redis
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
// Writes go to the tagged cache and drop the memoized copy
Cache::memo()->tags(['permissions'])->put("permissions:{$user->id}", $permissions);
// Flushing the tag also clears the memoized entries
Cache::memo()->tags(['permissions'])->flush();
До этого релиза тот же паттерн требовал ручного оборачивания вызова кэша с тегами во второй поиск через Cache::store('array') . Laravel News рассказывали о версии без тегов, когда она появилась в Laravel 12.9.
Читайте подробнее в статье Memoize Tagged Cache Reads in Laravel. Дополнительные сведения см. в PR #61593.
#Обновление атрибутов модели после записи
Caleb White добавил атрибут #[Refreshes] (и соответствующее свойство $refreshes ), который перезагружает определенные колонки из базы данных после создания или обновления модели. Он предназначен для колонок virtualAs , storedAs и других значений, устанавливаемых базой данных, которые в противном случае отсутствуют или являются устаревшими в модели в памяти до вызова refresh() :
use Illuminate\Database\Eloquent\Attributes\Refreshes;
#[Refreshes('name')]
class User extends Model
{
//
}
$user = User::create(['first_name' => 'Taylor', 'last_name' => 'Otwell']);
$user->name; // "Taylor Otwell" without calling refresh()
Обновление выполняет один запрос только для перечисленных колонок через соединение для записи. Атрибут принимает массив или список имен колонок в качестве аргументов переменной длины, а свойство $refreshes работает аналогично, если вы не используете атрибуты. Читайте подробнее в статье Refresh Generated Columns After Saving an Eloquent Model.
Дополнительные сведения см. в PR #61523.
#Сохранение реального NULL с помощью AsCollection и AsArrayObject
Zein Ahmad добавил опциональный режим nullable() для кастов AsCollection и AsArrayObject . Присвоение значения null одному из таких кастов сохраняет JSON-строку "null" в колонке, из-за чего whereNull() никогда не находит строку. С флагом nullable() каст сохраняет настоящий database NULL :
protected function casts(): array
{
return [
'items' => AsCollection::class, // unchanged: stores "null"
'meta' => AsCollection::nullable(), // stores NULL
'options' => AsArrayObject::nullable(),
];
}
Дополнительные сведения см. в PR #61596.
#Модификаторы inplace() и lock() для миграций индексов
Sander Muller добавил модификатор inplace() для операций с индексами и внешними ключами вместе с модификатором lock() , так что миграция для MySQL может запросить ALGORITHM=INPLACE и LOCK=NONE вместо выполнения блокирующей перестройки таблицы:
Schema::table('video_sessions', function (Blueprint $table) {
$table->index('foo', 'foo_index')->inplace()->lock('none');
});
Этот модификатор работает со следующими методами:
-
index() -
unique() -
primary() -
fullText() -
spatialIndex() -
foreign()
Он повторяет поведение модификатора instant() , который уже доступен при определении колонок.
Дополнительные сведения см. в PR #61602.
#Атрибуты Form Request из родительских классов
Md Sukkur Ali исправил работу атрибутов в формах запросов (form requests), чтобы дочерний запрос наследовал их из родительского класса. PHP не наследует атрибуты, поэтому такие атрибуты, как #[StopOnFirstFailure] , на общем базовом запросе игнорировались всеми подклассами:
#[StopOnFirstFailure]
#[FailOnUnknownFields]
abstract class ApiRequest extends FormRequest
{
//
}
// Both attributes now apply
class StorePostRequest extends ApiRequest
{
//
}
Дополнительные сведения см. в PR #61586.
#Отказ от завершения воркера при тайм-ауте
Jack Bayliss добавил флаг Worker::$killOnTimeout . По умолчанию задача, превысившая тайм-аут, приводит к завершению всего процесса воркера, после чего supervisor запускает новый экземпляр. Если установить флаг в значение false , воркер вместо этого выбросит исключение TimeoutExceededException , что позволит задаче выполнить очистку, а воркеру — продолжить работу:
use Illuminate\Queue\Worker;
Worker::$killOnTimeout = false;
Предупреждение: задача, оборачивающая свое тело handle() в широкий блок try/catch , может проглотить это исключение.
Связанный PR от Kieran Brown добавляет Worker::killUsing() — хук, который выполняется перед SIGKILL , позволяя передать супервайзеру пользовательский код завершения (#61622).
Дополнительные сведения см. в PR #61591.
#Тестовые хелперы mockArtisan() и realArtisan()
Jenthe Noordsij добавил два тестовых хелпера, разделяющих две задачи $this->artisan() . Метод mockArtisan() всегда возвращает PendingCommand для создания ожиданий, а realArtisan() всегда запускает команду и возвращает код завершения в виде int , так что вам больше не нужно переключать $mockConsoleOutput для переключения между этими режимами:
$this->mockArtisan('inspire')
->expectsOutputToContain('Simplicity')
->assertExitCode(0);
$code = $this->realArtisan('migrate', ['--force' => true]);
Дополнительные сведения см. в PR #61588.
#Примечания к релизу
Полный список новых функций и обновлений представлен ниже, а разницу между версиями 13.32.0 и 13.33.0 можно посмотреть на GitHub. Следующие примечания к релизу взяты напрямую из списка изменений (changelog):
#v13.33.0
- [13.x] Drop restart_syscalls from pcntl_signal in Worker by @jackbayliss in #61590
- Adjust when password hash is stored for authenticated sessions by @taylorotwell in #61594
- [13.x] Ability to opt out of killing the worker on job timeout by @jackbayliss in #61591
- [13.x] Fix enum keys in tagged cache many() and get() by @Meacue in #61603
- [13.x] Add opt-in support for persisting real NULL on AsCollection/AsArrayObject by @zeinrahmad76 in #61596
- [13.x] Fix Eloquent Collection duplicates() with a key or callback by @lazerg in #61597
- Improve Cloud job retries by @timacdonald in #61584
- [13.x] Support brick/math 0.20 & 1.0 by @jackbayliss in #61382
- [13.x] add health-start-period to workflows by @jackbayliss in #61608
- [13.x] Resolve FormRequest attributes from parent classes by @mdsukkur in #61586
- [13.x] Add order() to DevCommands by @jackbayliss in #61575
- [13.x] Add EncodedParameter to RouteUrlGenerator by @bytestream in #61610
- [13.x] Add inplace() DDL algorithm modifier for index and foreign key operations by @SanderMuller in #61602
- [13.x] Improve the value types of the Collection put method by @dfinchenko in #61611
- Allow relative URLs for Mercure hub by @barryvdh in #61629
- [13.x] Add server options to PostgreSQL connections by @DGarbs51 in #61627
- [13.x] Make the worker timed out exit code reachable by @kieranbrown in #61622
- Ci mariadb 11 by @Rhaima96 in #61615
- [13.x] Tagged memoized cache by @joostdebruijn in #61593
- Add "valkey://" and "valkeys://" protocol support by @cweiske in #61635
- [13.x] Fix SQLite schema dumps containing shadow tables by @jhm-ciberman in #61637
- [13.x] Make spelling consistent across docblocks by @shaedrich in #61631
- [13.x] Use
composer require --with-all-dependenciesto install additional requirements by @crynobone in #61617 - [13.x] Rebuild the phpredis client when a pipeline or transaction loses the connection by @maduonline in #61632
- Apply fixes from StyleCI by @taylorotwell in #61638
- [13.x] Add
--pretendoption toinstall:broadcastingcommand by @crynobone in #61633 - [13.x] Improved artisan mocking by @jnoordsij in #61588
- [13.x] feat: refresh configured model attributes after writes by @calebdw in #61523
- [13.x] Pass fresh batch to
BatchFinishedandBatchCanceledevents by @xurshudyan in #61644 - [13.x] Output empty JSON array from route:list --json when no routes match by @xurshudyan in #61642
- [13.x] Test against MariaDB 12.3 by @Rhaima96 in #61641
- [13.x] Use default view when make:notification --markdown has no value by @xurshudyan in #61643
- [13.x] Test Improvements by @crynobone in #61660
- [13.x] Fix
LazyCollection::take()with a negative limit larger than the collection by @crynobone in #61659 - [13.x] Skip batches that cannot be retried in queue:retry-batch by @xurshudyan in #61653
- [13.x] Consolidate overlapping tests by @jasonmccreary in #61648
- [13.x] Fix order-dependent tests by @jasonmccreary in #61647
- [13.x] Respect FILESYSTEM_DISK override when configuring Cloud disks by @DGarbs51 in #61664
- [13.x] Configure Laravel Cloud database read replicas by @WendellAdriel in #61665
- [13.x] Remove non-string headers from NotPwndVerifier by @kylemilloy in #61666
- [13.x] Fix ERR invalid cursor returned when calling
$predisClient->scan(null, ...)while using Redis 7.4 by @crynobone in #61673 - [13.x] Restore query logging when a pretend callback throws by @xurshudyan in #61671
- [13.x] add sole to higher order proxies by @jackbayliss in #61667
- [13.x] Add
createQuietlyandcreateManyQuietlytoBelongsToManyby @xurshudyan in #61669 - [13.x] Fix
whereValueBetween()binding expression values by @xurshudyan in #61670 - [13.x] Add opt-in native Postgres pooling for Laravel Cloud by @DGarbs51 in #61668
Комментарии (0)
Пока нет комментариев — будьте первым.