Skip to content

Commit fa461e5

Browse files
abnegateclaude
andcommitted
(fix): normalize tenant types at boundary, restore strict comparison
- Add symmetric ctype_digit normalization to Adapter::getTenant() to match Document::getTenant(), ensuring both return int for numeric IDs - Replace is_numeric with ctype_digit to avoid truncating float strings - Revert all != back to !== now that types are normalized at the source - Extract duplicated array-to-Document coercion into private helper - Replace empty() with precise === '' check for ID validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c9a9c7c commit fa461e5

File tree

5 files changed

+34
-25
lines changed

5 files changed

+34
-25
lines changed

src/Database/Adapter.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,16 @@ public function setTenant(int|string|null $tenant): bool
244244
/**
245245
* Get Tenant.
246246
*
247-
* Get tenant to use for shared tables
247+
* Get tenant to use for shared tables.
248+
* Numeric values are normalized to int for consistent comparison
249+
* across adapters that may return string representations.
248250
*/
249251
public function getTenant(): int|string|null
250252
{
253+
if (\is_string($this->tenant) && \ctype_digit($this->tenant)) {
254+
return (int) $this->tenant;
255+
}
256+
251257
return $this->tenant;
252258
}
253259

src/Database/Document.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,16 @@ public function getUpdatedAt(): ?string
237237
/**
238238
* Get the tenant ID associated with this document.
239239
*
240+
* Numeric string values are normalized to int for consistent comparison
241+
* across adapters that may return string representations (e.g. PDO stringify).
242+
*
240243
* @return int|string|null The tenant ID, or null if not set.
241244
*/
242245
public function getTenant(): int|string|null
243246
{
244247
$tenant = $this->getAttribute('$tenant');
245248

246-
if (\is_numeric($tenant)) {
249+
if (\is_string($tenant) && \ctype_digit($tenant)) {
247250
return (int) $tenant;
248251
}
249252

src/Database/Hook/Relationships.php

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ public function __construct(
5353
) {
5454
}
5555

56+
private function coerceToDocument(Document $document, string $key, mixed $value): mixed
57+
{
58+
if (\is_array($value) && ! \array_is_list($value)) {
59+
try {
60+
$value = new Document($value); // @phpstan-ignore argument.type
61+
} catch (StructureException $e) {
62+
throw new RelationshipException('Invalid relationship value. ' . $e->getMessage());
63+
}
64+
$document->setAttribute($key, $value);
65+
}
66+
67+
return $value;
68+
}
69+
5670
/**
5771
* {@inheritDoc}
5872
*/
@@ -148,14 +162,7 @@ public function afterDocumentCreate(Document $collection, Document $document): D
148162
$this->writeStack[] = $collection->getId();
149163

150164
try {
151-
if (\is_array($value) && ! \array_is_list($value)) {
152-
try {
153-
$value = new Document($value); // @phpstan-ignore argument.type
154-
} catch (StructureException $e) {
155-
throw new RelationshipException('Invalid relationship value. ' . $e->getMessage());
156-
}
157-
$document->setAttribute($key, $value);
158-
}
165+
$value = $this->coerceToDocument($document, $key, $value);
159166

160167
if (\is_array($value)) {
161168
if (
@@ -290,14 +297,7 @@ public function afterDocumentUpdate(Document $collection, Document $old, Documen
290297
$key = $typedRelAttr->key;
291298
$value = $document->getAttribute($key);
292299

293-
if (\is_array($value) && ! \array_is_list($value)) {
294-
try {
295-
$value = new Document($value); // @phpstan-ignore argument.type
296-
} catch (StructureException $e) {
297-
throw new RelationshipException('Invalid relationship value. ' . $e->getMessage());
298-
}
299-
$document->setAttribute($key, $value);
300-
}
300+
$value = $this->coerceToDocument($document, $key, $value);
301301

302302
$oldValue = $old->getAttribute($key);
303303
$rel = RelationshipVO::fromDocument($collection->getId(), $relationship);
@@ -543,7 +543,7 @@ public function afterDocumentUpdate(Document $collection, Document $old, Documen
543543
}
544544
$this->db->purgeCachedDocument($relatedCollection->getId(), $value);
545545
} elseif ($value instanceof Document) {
546-
if (empty($value->getId())) {
546+
if ($value->getId() === '') {
547547
throw new RelationshipException('Invalid relationship value. Document must have a valid $id.');
548548
}
549549

src/Database/Traits/Collections.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public function updateCollection(string $id, array $permissions, bool $documentS
247247

248248
if (
249249
$this->adapter->getSharedTables()
250-
&& $collection->getTenant() != $this->adapter->getTenant()
250+
&& $collection->getTenant() !== $this->adapter->getTenant()
251251
) {
252252
throw new NotFoundException('Collection not found');
253253
}
@@ -279,7 +279,7 @@ public function getCollection(string $id): Document
279279
$id !== self::METADATA
280280
&& $this->adapter->getSharedTables()
281281
&& $collection->getTenant() !== null
282-
&& $collection->getTenant() != $this->adapter->getTenant()
282+
&& $collection->getTenant() !== $this->adapter->getTenant()
283283
) {
284284
return new Document();
285285
}
@@ -326,7 +326,7 @@ public function getSizeOfCollection(string $collection): int
326326
throw new NotFoundException('Collection not found');
327327
}
328328

329-
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
329+
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
330330
throw new NotFoundException('Collection not found');
331331
}
332332

@@ -354,7 +354,7 @@ public function getSizeOfCollectionOnDisk(string $collection): int
354354
throw new NotFoundException('Collection not found');
355355
}
356356

357-
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
357+
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
358358
throw new NotFoundException('Collection not found');
359359
}
360360

@@ -388,7 +388,7 @@ public function deleteCollection(string $id): bool
388388
throw new NotFoundException('Collection not found');
389389
}
390390

391-
if ($this->adapter->getSharedTables() && $collection->getTenant() != $this->adapter->getTenant()) {
391+
if ($this->adapter->getSharedTables() && $collection->getTenant() !== $this->adapter->getTenant()) {
392392
throw new NotFoundException('Collection not found');
393393
}
394394

src/Database/Traits/Documents.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ public function upsertDocumentsWithIncrease(
14051405
if ($document->getTenant() === null) {
14061406
throw new DatabaseException('Missing tenant. Tenant must be set when tenant per document is enabled.');
14071407
}
1408-
if (! $old->isEmpty() && $old->getTenant() != $document->getTenant()) {
1408+
if (! $old->isEmpty() && $old->getTenant() !== $document->getTenant()) {
14091409
throw new DatabaseException('Tenant cannot be changed.');
14101410
}
14111411
} else {

0 commit comments

Comments
 (0)