You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(api,generators,admin): honest row shapes, and a toggle that did nothing (#1060) (#1074)
* refactor(api,generators,admin): honest row shapes, and a toggle that did nothing (#1060)
PR 4. The ruler goes from 170 to 135 and all three modules reach zero.
Most of it is typing the producer rather than casting at the consumer.
AudienceQueryService::find_user_bookings() now declares publicly what it
returns instead of list<array<string, mixed>>, which is what left the REST
controller reading thirteen unverifiable keys. QRCodeGenerator's defaults and
parsed parameters are a declared shape all the way to the library call, and
its settings reads go through SettingsReader — the project's own rule for
ffc_settings, and also what makes them typed.
Declaring that shape turned up a toggle that never worked. The two writers of
qr_cache_enabled disagree on its type: the tab's form save stores int 1, while
the autosave endpoint — which is what flipping the switch actually calls —
stores a PHP boolean through RequestInput::is_truthy(). The check was
`1 === $value`, and `1 === true` is false, so turning the QR cache on from the
UI left it off. Reading through the existing typed accessor fixes it; the test
is verified failing against the old check.
SettingsReader gains get_string(), the typed accessor that was missing. It
refuses a non-scalar rather than casting — `(string) array()` is the literal
'Array' plus a notice. Its int and bool siblings keep their plain casts on
purpose: changing those changes what every existing caller gets back, which is
a wider decision than this PR.
Two smaller notes. The intersection `UserBookingRow&array{audiences: …}`
resolves to *NEVER* in PHPStan — two sealed array shapes cannot be
intersected — so the with-audiences shape repeats the keys; the duplication is
the cost of saying what the method returns. And a test fixture that omitted
`audiences` was fixed rather than the shape widened: the producer always sets
that key, so the fixture was describing a row production never emits.
get_post_meta() casts are handled by two private helpers in FormListColumns
rather than a shared class. The repository has 87 casts of that shape, but one
proven user is not duplication yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XWx9qJdjZdAq8crxM9GCU
* style(qrcode): align the assignments phpcbf flagged (#1060)
The WPCS gate reported two Generic.Formatting.MultipleStatementAlignment
warnings on the error-level block. My local phpcs run had been made before
that block's last edit, so it passed on a tree that no longer existed —
re-running the CI's exact command (phpcs over the changed-file list)
reproduces it, and phpcbf fixes it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XWx9qJdjZdAq8crxM9GCU
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -28,11 +28,16 @@ The format follows [Keep a Changelog] (https://keepachangelog.com/en/1.1.0/).
28
28
-**Formas de linha honestas em `frontend` e `core`** (#1060): `ActivityLogQuery` declara a linha do log derivada do `CREATE TABLE`, e `ReprintDetector` declara o formato do resultado que dois consumidores já liam às cegas. A régua de nível 9 baixou de 203 para 170 e os dois módulos ficaram em zero.
29
29
-**`Core\ArrayValue`** (#1060): leitura de escalar sobre array sem tipo — JSON decodificado, configuração de formulário, payload de token. Substitui o idioma `(string) ( $data['k'] ?? '' )`, que não confere nada: dado um array ele produz a string `Array`, dado um objeto sem `__toString` é fatal. Não serve para `$_POST` (isso é o `RequestInput`) nem para linha de banco (isso é shape declarada).
30
30
31
+
-**Formas de linha honestas em `api`, `generators` e `admin`** (#1060): o `QRCodeGenerator` passa a ler `ffc_settings` pelo `SettingsReader` — regra do próprio projeto — e seus parâmetros viraram uma shape tipada até a chamada da biblioteca; `find_user_bookings()` declara publicamente o que devolve, em vez de `array<string, mixed>`. A régua de nível 9 baixou de 170 para 135 e os três módulos ficaram em zero.
32
+
-**`SettingsReader::get_string()`** (#1060): acessor tipado que faltava. Recusa valor não escalar em vez de convertê-lo — `(string) array()` é a string `Array` mais um notice. Os acessores de int e bool seguem com o cast simples: mudá-los mudaria o que todo chamador existente recebe.
33
+
31
34
### Removed
32
35
33
36
-`Shortcodes::get_new_captcha_data()` (#1053): método público sem nenhum chamador em produção — o único consumidor era o próprio teste. A geração de desafio já é responsabilidade do contrato de captcha.
34
37
35
38
### Fixed
39
+
-**O cache de QR Code nunca ligava pelo toggle** (#1060): os dois gravadores da chave `qr_cache_enabled` discordam do tipo — o save do formulário grava `int 1`, e o autosave, que é o que o interruptor chama de fato, grava um booleano. A checagem era `1 === $valor`, e `1 === true` é falso, então ligar o cache pela interface deixava-o desligado.
40
+
36
41
-**`ReprintDetector::detect()` devolvia `date` com tipo diferente conforme o ramo** (#1060): inteiro (segundos unix) quando havia reimpressão, string vazia quando não. Só um consumidor lê a chave, e só no ramo de reimpressão, então o ramo vazio passou a devolver `0` — um contrato cujo tipo depende do ramo não pode ser verificado.
37
42
38
43
-**Ids não-numéricos em reservas de público viravam `0`** (#1060): `audience_ids` e `user_ids` chegam dentro de um `$data` do chamador, e cada entrada era convertida direto com `(int)` — uma string solta ou `null` virava `0` e gravava uma linha de junção apontando para um público que não existe. Agora entradas não-numéricas são descartadas.
// phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Deletes the plugin's own temp export file by absolute path. WP_Filesystem would need credentials, and this runs on a cleanup path with no user present.
0 commit comments