Move the collection mapping query from inside the Metadata decorator to
the getDatabasesDB resource factory. This avoids decorator-level
database queries that can fail in various contexts and cause cascading
issues.
The mapping is loaded once when getDatabasesDB creates the database
instance, and the results are passed to the Metadata decorator via
setCollectionId(). The decorator itself is now stateless with respect
to database queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Float attributes created via API use type 'double' (ColumnType::Double)
since the Float/Create endpoint was updated. The format registration
must match to pass format validation during attribute creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Metadata decorator now skips _metadata collection documents to prevent
injected $databaseId/$collectionId attributes from leaking into SQL
UPDATE statements via getAttributes()
- Add Tenancy hook to dbForProject in shared mode (was missing, causing
401 on session verification)
- Update Collection/Table response models to use $databaseId with $
prefix matching the decorator
- Update utopia-php/database with MongoDB tenant null filter fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Query::groupByType() now returns a GroupedQueries readonly class instead
of an associative array. All bracket access ($grouped['filters'], etc.)
must use arrow syntax ($grouped->filters).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Since setDocumentType('users', User::class) is registered on all
database instances, getDocument('users', ...) already returns User
instances. The new User($doc->getArrayCopy()) pattern was redundant
and could lose internal state managed by the database layer.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
- general.php: add instanceof guard in error handler to prevent calling
isPrivileged() on a plain Document if getResource('user') returns
an unexpected type
- graphql.php: add setUser() calls on request/response in graphql group
init so sensitive field filtering works correctly for GraphQL routes
- api.php: fix session group init type hint from Document to User for
consistency with all other init blocks
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
The user resource and realtime handlers return Document objects from
getDocument(), but isPrivileged()/isApp() are now instance methods on
the User class. Wrapping results with new User() ensures the correct
type is returned for all code paths.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
The error handler in general.php was calling User::isPrivileged()
statically, but the method was converted to an instance method.
This caused a fatal error on every request.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
All call sites now use $user->isApp() and $user->isPrivileged() instance
syntax instead of static User::isApp() / $user::isPrivileged() calls.
Added setUser() to Request class for consistency with Response.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
PHPStan correctly flagged that Document::isPrivileged() doesn't exist.
Changed type hints from Document $user to User $user in all action
signatures where $user::isPrivileged() is called, since the runtime
instance is always a User (or subclass).
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
Replace all static User::isPrivileged() calls with $user::isPrivileged()
across the codebase. Since $user is resolved via setDocumentType, this
allows subclasses to override the privilege check without CE needing to
know about downstream-specific roles.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
- Restore postgresql in compose.phtml allowedDbServices for consistency
with WhiteList validators, JS defaults, and compose template sections
- Log errors in performReset catch block instead of swallowing silently
- Move $currentStep assignment before waitForApiReady so timeout errors
are attributed to the correct step
- Replace blocking fgets loop in execWithContainerProgress with
non-blocking stream_select polling to prevent unbounded hangs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>