v8.5.26
⚠️ Breaking: insert() and update() columns are PHP values now
A bare string passed as a column is a bound value, not SQL. SQL has to say
so: new Ovos\Pdo\Expression('NOW()') — the convention the model layer already
used, now true of the builder as well.
It fails loudly rather than quietly: strict mode rejects the literal text in a
DATETIME or INT column. The call sites this affected across the projects
vendoring dev-release/8.5 have already been adjusted.
The deprecated commented insertUpdateQuery() is gone; the builder has
ON DUPLICATE KEY UPDATE.
Store: the query carries its values
A condition, join or HAVING given as a tuple [sql, ...values] records its
values beside the SQL, and getValues() hands them back in the order the SQL
emits them. Store\Mysql::statement() prepares, binds by position with the
PHP types (a false stays 0, a null stays NULL) and executes, with
fetchModels(), fetchModel(), fetchRows(), fetchList(), fetchScalar()
and affected() beside it. executeFind(), fetchReferenced() and
fetchByReference() bind their IN lists — an IN list of names works now,
where it used to be unquoted SQL.
The gaps the console's stores kept hitting are closed: Delete can alias and
join (the setters lived on Select while Delete::getSql() already emitted
them); INSERT IGNORE; one ordered join list, so leftJoin() and
innerJoin() stop erasing each other; whereIn(field, values, bind: true) and
orWhereIn(); orderBy() and limit(?int) on Select, Update and Delete;
Insert::row() / rows() / onDuplicateKeyUpdate(); a group opening with
orWhere() no longer starts on a dangling OR; limit() / offset() are
ints, since native prepares refuse a string-bound LIMIT.
executeQuery() and runQuery() answer false without a source rather than
raising.
Console sender: enough for the console to replay the request that failed
- The request body, its content type and the safe headers. A JSON API call
has an empty$_POST— the body is a stream PHP never parses into fields — so
the console could only replay such a write as a bare method and URL, which is
a different request wearing the same name. The body now travels (16 KB, never
multipart, skipped on GET), scrubbed byLogger::removeText(), which reads
the same secret names out of the punctuation a body is written in and
honours a project's ownaddRemove(). announceRelease()— the deploy step tells the console a release shipped,
synchronously, answeringfalserather than throwing when the sender is off
or the console is out of reach.context.userId,context.status,runtime/entry/kind
beside the legacytype, and anenvironmentfield carrying the deploy
stage beside the release. Thelog_levelgate keys onkind, so security
events pass like 404s do.auth_successjoins the closed security vocabulary — the login that
worked after the ones that failed.- The release falls back to the
.releasestamp when none is configured. - Username and e-mail masks now say how long the original value was.
Rollup
Request durations ride the fragment as histograms, and a text/event-stream
response counts as traffic rather than as a duration — an SSE stream that stays
open for an hour is not an hour-long request.
Container, Dir, Strings, Config
Container::injectMissing()— complete an object built withnewwithout
overwriting what it already holds.injectObject()resolves every
#[Inject]property, so an object given part of its state by hand loses it;
this resolves only what is still uninitialised.Dir::isAbsolute()— POSIX, Windows drive and UNC roots in one place, so
"resolve this configured path against the base directory or not" stops
depending on which OS runs the code.Dir::getFiles()returns one order on every filesystem.Strings::displaySafe()— the control-byte wall for untrusted display
text, for surfaces with no escaping layer: terminals, logs, plain-text mail.
ESC, CR/LF, backspace, DEL and NUL out; markup passes untouched, because
encoding belongs to the renderer.- Config — an unknown
ENVnames itself, and.envreaches APCu only once
environments.ymlhas resolved.
The repository is public
Released under PolyForm Noncommercial 1.0.0 with a SECURITY.md and private
vulnerability reporting. The README is written to be read rather than adopted,
the test fixtures no longer name real people, addresses or articles, and the
installation instructions no longer open with an SSH deploy key — the packages
are fetched over HTTPS.