# Edição de 25 de setembro de 2026

Data: 2026-09-25

O Framework concentrou as mudanças de hoje: deadlocks em DatabaseLock, morph maps, queue:restart, consultas polimórficas, ordenação numérica e formatação de valores. No Laravel AI, o fluxo de tool approval foi ajustado. A recomendação do dia é Pest.

## Laravel Framework

### DatabaseLock deixa de engolir deadlocks dentro de transações [Merged]

Merged em 13.x. DatabaseLock não trata mais um deadlock dentro de transação como falha comum. O erro sobe para DB::transaction(), que pode fazer rollback ou retry como deveria.

## O problema

Se o insert da linha de lock entrava em deadlock dentro de uma transação, `DatabaseLock::acquire()` capturava o erro e seguia para o update.

No MySQL, a transação já podia ter sido revertida no banco enquanto o Laravel ainda a considerava aberta. A aplicação seguia rodando com writes anteriores perdidos e novas queries fora do fluxo esperado.

## A correção

Erros de concorrência agora são relançados quando há uma transação aberta. O mesmo vale para prune e release.

Fora de transações, o comportamento anterior continua igual.

Com isso, `DB::transaction()` volta a controlar rollback e retry quando o lock encontra um deadlock.

Link: https://github.com/laravel/framework/pull/61708

Fonte: laravel/framework


### requireMorphMap() passa a ser aplicado também na leitura [Merged]

Merged em 13.x. Com Relation::requireMorphMap() ativo, um *_type não mapeado agora falha também na leitura. Antes, o read side ainda podia cair para o nome bruto da classe.

## O que estava faltando

`Relation::requireMorphMap()` já protegia a escrita, mas a leitura ainda aceitava um valor bruto em `*_type` quando ele não existia no morph map.

Agora a mesma regra vale para os dois lados.

- `morphTo()` rejeita tipos não mapeados.
- Eager loading via `MorphTo::createModelByType()` faz o mesmo.

Sem `requireMorphMap()`, nada muda. Com ele ativo, um valor adulterado em `*_type` não resolve mais silenciosamente para outra classe.

Link: https://github.com/laravel/framework/pull/61711

Fonte: laravel/framework


### queue:restart agora acusa quando o worker não pode ser reiniciado [Merged]

Merged em 13.x. queue:restart agora falha de forma explícita quando interruption polling está desabilitado e o worker não pode ser reiniciado.

## O problema

Com `Queue::withoutInterruptionPolling()`, `queue:restart` podia terminar como se tudo tivesse funcionado, mesmo sem reiniciar o worker.

Agora o comando verifica essa condição, mostra erro e devolve exit code de falha.

Para deploys e automações, isso elimina um falso positivo que era fácil de passar despercebido.

Link: https://github.com/laravel/framework/pull/61706

Fonte: laravel/framework


### whereMorphedTo() passa a respeitar a owner key da relação [Merged]

Merged em 13.x. whereMorphedTo() e whereNotMorphedTo() passam a usar a owner key definida na relação, em vez de assumir a chave padrão.

## A correção

`whereMorphedTo()` podia montar a condição com a chave errada quando a relação polimórfica usava uma owner key customizada.

O ajuste também cobre `whereNotMorphedTo()`.

Projetos que usam chaves diferentes da primary key padrão deixam de receber uma query incoerente com a relação definida no model.

Link: https://github.com/laravel/framework/pull/61712

Fonte: laravel/framework


### sortBy() com múltiplas colunas corrige SORT_NUMERIC para decimais [Merged]

Merged em 13.x. sortBy() com múltiplas colunas e SORT_NUMERIC não converte mais os valores para int. Decimais como 1.2 e 1.9 deixam de ser tratados como iguais.

## O problema

Na versão com múltiplas comparações, `sortBy()` convertia valores de `SORT_NUMERIC` para `int`.

Por isso, `1.2`, `1.5` e `1.9` podiam cair no mesmo grupo e manter a ordem original.

A comparação agora usa float, igualando o comportamento ao `sortBy()` de uma única coluna e ao próprio `SORT_NUMERIC` do PHP.

Link: https://github.com/laravel/framework/pull/61699

Fonte: laravel/framework


### Number evita -0 em format(), percentage() e currency() [Merged]

Merged em 13.x. Valores negativos muito pequenos que arredondam para zero não aparecem mais como -0, -0% ou -$0.00.

## O problema

O ICU preserva o sinal negativo mesmo quando o valor arredonda para zero.

```php
Number::currency(-0.001);          // "-$0.00"
Number::percentage(-0.4);          // "-0%"
Number::format(-0.4, precision: 0); // "-0"
```

Agora o formatter verifica a magnitude com a mesma configuração usada na saída. Se o resultado final é zero, o sinal é removido.

Isso evita valores estranhos em invoices, saldos, percentuais e também em `fileSize()`.

Link: https://github.com/laravel/framework/pull/61716

Fonte: laravel/framework


## Laravel AI

### Tool call passa a ser anunciado antes do approval request [Merged]

Merged após v1.0.0. FakeTextGateway agora anuncia a tool call antes do approval request, seguindo a mesma ordem dos gateways reais.

## O problema

Em respostas pausadas para aprovação, o `FakeTextGateway` podia emitir `tool-approval-request` antes de expor a tool invocation.

Isso quebrava dois cenários: o AI SDK UI podia lançar `No tool invocation found`, e `pendingApprovalsFor()` não encontrava approvals em conversas fake.

## A correção

O fake agora coloca as chamadas pendentes em `toolCalls` e usa `FinishReason::ToolCalls`, como os gateways reais.

Não há breaking change. O ganho é nos testes e nos streams de human-in-the-loop, que passam a reproduzir melhor o fluxo de produção.

Link: https://github.com/laravel/ai/pull/1070

Fonte: laravel/ai


## Recomendação do dia

### pestphp/pest [Recommended]

Pest é uma camada de testes para PHP baseada no ecossistema do PHPUnit, com sintaxe curta, integração com Laravel e plugins para browser testing e outros fluxos de desenvolvimento.

## Por que eu colocaria no radar

Pest mantém compatibilidade com o ecossistema do PHPUnit, mas corta bastante boilerplate. Em projetos Laravel, isso costuma deixar testes de feature e unitários mais fáceis de ler sem mudar a base técnica por baixo.

Também há plugins oficiais para Laravel e browser testing.

## Onde encaixa bem

Use Pest quando a equipe quer uma suíte mais enxuta, principalmente em projetos Laravel com muitos testes de feature ou quando browser testing faz parte do fluxo.

Se o projeto já tem uma suíte PHPUnit grande e estável, não há motivo para migrar tudo de uma vez. Os dois podem coexistir durante a transição.

## Instalação

A documentação atual orienta:

```bash
composer remove phpunit/phpunit
composer require pestphp/pest --dev --with-all-dependencies
./vendor/bin/pest --init
```

Para Laravel:

```bash
composer require pestphp/pest-plugin-laravel --dev
```

O plugin de browser testing usa Playwright e cobre navegação, interações, screenshots e fluxos completos no navegador.

Link: https://github.com/pestphp/pest

Fonte: pestphp/pest


## Fontes

- [Laravel Framework — DatabaseLock deadlocks](https://github.com/laravel/framework/pull/61708)
- [Laravel Framework — requireMorphMap read side](https://github.com/laravel/framework/pull/61711)
- [Laravel Framework — queue:restart restartability](https://github.com/laravel/framework/pull/61706)
- [Laravel Framework — whereMorphedTo owner key](https://github.com/laravel/framework/pull/61712)
- [Laravel Framework — SORT_NUMERIC decimals](https://github.com/laravel/framework/pull/61699)
- [Laravel Framework — negative zero formatting](https://github.com/laravel/framework/pull/61716)
- [Laravel AI — tool approval stream order](https://github.com/laravel/ai/pull/1070)
- [Pest](https://github.com/pestphp/pest)
- [Pest installation](https://pestphp.com/docs/installation)
