-
Notifications
You must be signed in to change notification settings - Fork 55
Internal attributes defaults #608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
6d5d60e
173264b
2ecf187
1d4d7d1
ba87da6
8545413
32c6884
ed9c424
f71ee21
22b5f19
8b0bc4c
b23b8a8
42600a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -350,6 +350,10 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||||||||||||||
| $sql .= " {$forUpdate}"; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!empty($selections)){ | ||||||||||||||||||||||||||||||
| echo $sql.PHP_EOL; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $stmt = $this->getPDO()->prepare($sql); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $stmt->bindValue(':_uid', $id); | ||||||||||||||||||||||||||||||
|
|
@@ -393,6 +397,12 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||||||||||||||
| unset($document['_permissions']); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $document['main::$permissions'] = json_decode($document['main::$permissions'], true); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if ($this->sharedTables) { | ||||||||||||||||||||||||||||||
| $document['main::$tenant'] = $document['main::$tenant'] === null ? null : (int)$document['main::$tenant']; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
Comment on lines
+396
to
+401
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Undefined-index & double-decode risk on
Additionally, - $document['main::$permissions'] = json_decode($document['main::$permissions'], true);
- if ($this->sharedTables) {
- $document['main::$tenant'] = $document['main::$tenant'] === null ? null : (int)$document['main::$tenant'];
- }
+ if (\array_key_exists('main::$permissions', $document)) {
+ $document['$permissions'] ??= json_decode($document['main::$permissions'] ?? '[]', true);
+ unset($document['main::$permissions']);
+ }
+
+ if ($this->sharedTables && \array_key_exists('main::$tenant', $document)) {
+ $document['$tenant'] ??= ($document['main::$tenant'] === null ? null : (int)$document['main::$tenant']);
+ unset($document['main::$tenant']);
+ }This keeps one canonical key ( 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| return new Document($document); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -1674,6 +1684,34 @@ public function getTenantQuery( | |||||||||||||||||||||||||||||
| return "{$condition} ({$alias}{$dot}_tenant IN ({$bindings}) {$orIsNull})"; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||
| * Get the SQL projection given the selected attributes | ||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||
| * @param array<string> $selects | ||||||||||||||||||||||||||||||
| * @return string | ||||||||||||||||||||||||||||||
| * @throws Exception | ||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||
| protected function addHiddenAttribute(array $selects): string | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| //return ''; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $alias = Query::DEFAULT_ALIAS; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $strings = []; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $strings[] = $alias.'._uid as '.$this->quote($alias.'::$id'); | ||||||||||||||||||||||||||||||
| $strings[] = $alias.'._id as '.$this->quote($alias.'::$sequence'); | ||||||||||||||||||||||||||||||
| $strings[] = $alias.'._permissions as '.$this->quote($alias.'::$permissions'); | ||||||||||||||||||||||||||||||
| $strings[] = $alias.'._createdAt as '.$this->quote($alias.'::$createdAt'); | ||||||||||||||||||||||||||||||
| $strings[] = $alias.'._updatedAt as '.$this->quote($alias.'::$updatedAt'); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if ($this->sharedTables) { | ||||||||||||||||||||||||||||||
| $strings[] = $alias.'._tenant as '.$this->quote($alias.'::$tenant'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return ', '.implode(', ', $strings); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+1683
to
+1707
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion
Consider: -protected function addHiddenAttribute(array $selects): string
+protected function getHiddenProjection(string $alias): string
{
- //return '';
- $alias = Query::DEFAULT_ALIAS;
-
- $strings = [];
+ $columns = [];
- $strings[] = $alias.'._uid as '.$this->quote($alias.'::$id');
+ $columns[] = "{$alias}._uid AS ".$this->quote($alias.'::$id');
...
- return ', '.implode(', ', $strings);
+ return implode(', ', $columns);
}Then compose the projection once in
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||
| * Get the SQL projection given the selected attributes | ||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||
|
|
@@ -1685,28 +1723,17 @@ public function getTenantQuery( | |||||||||||||||||||||||||||||
| protected function getAttributeProjection(array $selections, string $prefix): mixed | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| if (empty($selections) || \in_array('*', $selections)) { | ||||||||||||||||||||||||||||||
| return "{$this->quote($prefix)}.*"; | ||||||||||||||||||||||||||||||
| return "{$this->quote($prefix)}.* {$this->addHiddenAttribute($selections)}"; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $internalKeys = [ | ||||||||||||||||||||||||||||||
| '$id', | ||||||||||||||||||||||||||||||
| '$sequence', | ||||||||||||||||||||||||||||||
| '$permissions', | ||||||||||||||||||||||||||||||
| '$createdAt', | ||||||||||||||||||||||||||||||
| '$updatedAt', | ||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $selections = \array_diff($selections, [...$internalKeys, '$collection']); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| foreach ($internalKeys as $internalKey) { | ||||||||||||||||||||||||||||||
| $selections[] = $this->getInternalKeyForAttribute($internalKey); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| $selections = array_diff($selections, ['$collection']); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| foreach ($selections as &$selection) { | ||||||||||||||||||||||||||||||
| $selection = $this->getInternalKeyForAttribute($selection); | ||||||||||||||||||||||||||||||
| $selection = "{$this->quote($prefix)}.{$this->quote($this->filter($selection))}"; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return \implode(',', $selections); | ||||||||||||||||||||||||||||||
| return \implode(',', $selections).$this->addHiddenAttribute($selections); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
1719
to
1731
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion
Refactor to:
Example patch (after adopting comment above): -if (empty($selections) || \in_array('*', $selections)) {
- return "{$this->quote($prefix)}.* {$this->addHiddenAttribute($selections)}";
-}
+if (empty($selections) || \in_array('*', $selections, true)) {
+ return "{$this->quote($prefix)}.*";
+}
...
-return \implode(',', $selections).$this->addHiddenAttribute($selections);
+return \implode(',', $selections).', '.$this->getHiddenProjection($prefix);
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| protected function getInternalKeyForAttribute(string $attribute): string | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -526,6 +526,25 @@ public function silent(callable $callback, ?array $listeners = null): mixed | |||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Check if attribute is internal | ||||||||||||||||||
| * | ||||||||||||||||||
| * @param string $attribute | ||||||||||||||||||
| * @return bool | ||||||||||||||||||
| */ | ||||||||||||||||||
| public static function isInternalAttribute(string $attribute): bool | ||||||||||||||||||
| { | ||||||||||||||||||
| if (str_contains($attribute, '$')) { | ||||||||||||||||||
| foreach (Database::INTERNAL_ATTRIBUTES as $attr) { | ||||||||||||||||||
| if (str_contains($attribute, $attr['$id'])) { | ||||||||||||||||||
| return true; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| return false; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Get getConnection Id | ||||||||||||||||||
| * | ||||||||||||||||||
|
|
@@ -3277,7 +3296,7 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||
| if ($collection->getId() !== self::METADATA) { | ||||||||||||||||||
| if (!$validator->isValid([ | ||||||||||||||||||
| ...$collection->getRead(), | ||||||||||||||||||
| ...($documentSecurity ? $document->getRead() : []) | ||||||||||||||||||
| ...($documentSecurity ? $document->getRead('main::$permissions') : []) | ||||||||||||||||||
| ])) { | ||||||||||||||||||
| return new Document(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -3294,17 +3313,17 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||
| $queries, | ||||||||||||||||||
| $forUpdate | ||||||||||||||||||
| ); | ||||||||||||||||||
|
|
||||||||||||||||||
| if ($document->isEmpty()) { | ||||||||||||||||||
| return $document; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| $document->setAttribute('$collection', $collection->getId()); | ||||||||||||||||||
| $document->setAttribute('main::$collection', $collection->getId()); | ||||||||||||||||||
|
|
||||||||||||||||||
| if ($collection->getId() !== self::METADATA) { | ||||||||||||||||||
| if (!$validator->isValid([ | ||||||||||||||||||
| ...$collection->getRead(), | ||||||||||||||||||
| ...($documentSecurity ? $document->getRead() : []) | ||||||||||||||||||
| ...($documentSecurity ? $document->getRead('main::$permissions') : []) | ||||||||||||||||||
| ])) { | ||||||||||||||||||
| return new Document(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -3335,6 +3354,9 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||
|
|
||||||||||||||||||
| $this->trigger(self::EVENT_DOCUMENT_READ, $document); | ||||||||||||||||||
|
|
||||||||||||||||||
| $document->setAttribute('main::$createdAt', DateTime::formatTz($document->getAttribute('main::$createdAt'))); | ||||||||||||||||||
| $document->setAttribute('main::$updatedAt', DateTime::formatTz($document->getAttribute('main::$updatedAt'))); | ||||||||||||||||||
|
|
||||||||||||||||||
| return $document; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -3667,6 +3689,14 @@ public function createDocument(string $collection, Document $document): Document | |||||||||||||||||
|
|
||||||||||||||||||
| $this->trigger(self::EVENT_DOCUMENT_CREATE, $document); | ||||||||||||||||||
|
|
||||||||||||||||||
| $document->setAttribute('main::$id', $document->getId()); | ||||||||||||||||||
| $document->setAttribute('main::$sequence', $document->getSequence()); | ||||||||||||||||||
| $document->setAttribute('main::$permissions', $document->getPermissions()); | ||||||||||||||||||
| $document->setAttribute('main::$createdAt', $document->getCreatedAt()); | ||||||||||||||||||
| $document->setAttribute('main::$updatedAt', $document->getUpdatedAt()); | ||||||||||||||||||
| $document->setAttribute('main::$tenant', $document->getTenant()); | ||||||||||||||||||
| $document->setAttribute('main::$collection', $document->getCollection()); | ||||||||||||||||||
|
|
||||||||||||||||||
| return $document; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -3989,7 +4019,7 @@ private function relateDocuments( | |||||||||||||||||
|
|
||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| // If the related document doesn't exist, create it, inheriting permissions if none are set | ||||||||||||||||||
| if (!isset($relation['$permissions'])) { | ||||||||||||||||||
| if (!isset($relation['$permissions'])) { // todo: Should this be main::$permissions | ||||||||||||||||||
| $relation->setAttribute('$permissions', $document->getPermissions()); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -4114,6 +4144,10 @@ public function updateDocument(string $collection, string $id, Document $documen | |||||||||||||||||
|
|
||||||||||||||||||
| $document = $this->withTransaction(function () use ($collection, $id, $document) { | ||||||||||||||||||
| $time = DateTime::now(); | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * @var $old Document | ||||||||||||||||||
| */ | ||||||||||||||||||
| $old = Authorization::skip(fn () => $this->silent( | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix invalid PHPDoc
- * @var $old Document
+ * @var Document $old📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: CodeQL[error] 4151-4151: PHPDoc tag @var has invalid value ($old Document): Unexpected token "$old", expected type at offset 24 🤖 Prompt for AI Agents |
||||||||||||||||||
| fn () => $this->getDocument($collection->getId(), $id, forUpdate: true) | ||||||||||||||||||
| )); | ||||||||||||||||||
|
|
@@ -4143,8 +4177,14 @@ public function updateDocument(string $collection, string $id, Document $documen | |||||||||||||||||
| $relationships[$relationship->getAttribute('key')] = $relationship; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| $alias = Query::DEFAULT_ALIAS; | ||||||||||||||||||
|
|
||||||||||||||||||
| // Compare if the document has any changes | ||||||||||||||||||
| foreach ($document as $key => $value) { | ||||||||||||||||||
| if (str_starts_with($key, $alias.'::') && Database::isInternalAttribute($key)){ | ||||||||||||||||||
| continue; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Skip the nested documents as they will be checked later in recursions. | ||||||||||||||||||
| if (\array_key_exists($key, $relationships)) { | ||||||||||||||||||
| // No need to compare nested documents more than max depth. | ||||||||||||||||||
|
|
@@ -4288,6 +4328,14 @@ public function updateDocument(string $collection, string $id, Document $documen | |||||||||||||||||
|
|
||||||||||||||||||
| $this->trigger(self::EVENT_DOCUMENT_UPDATE, $document); | ||||||||||||||||||
|
|
||||||||||||||||||
| $document->setAttribute('main::$id', $document->getId()); | ||||||||||||||||||
| $document->setAttribute('main::$sequence', $document->getSequence()); | ||||||||||||||||||
| $document->setAttribute('main::$permissions', $document->getPermissions()); | ||||||||||||||||||
| $document->setAttribute('main::$createdAt', $document->getCreatedAt()); | ||||||||||||||||||
| $document->setAttribute('main::$updatedAt', $document->getUpdatedAt()); | ||||||||||||||||||
| $document->setAttribute('main::$tenant', $document->getTenant()); | ||||||||||||||||||
| $document->setAttribute('main::$collection', $document->getCollection()); | ||||||||||||||||||
|
|
||||||||||||||||||
| return $document; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -4565,7 +4613,7 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
| $related = $this->skipRelationships( | ||||||||||||||||||
| fn () => $this->getDocument($relatedCollection->getId(), $value, [Query::select(['$id'])]) | ||||||||||||||||||
| ); | ||||||||||||||||||
|
|
||||||||||||||||||
| var_dump($related); | ||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| // If no such document exists in related collection | ||||||||||||||||||
| // For one-one we need to update the related key to null if no relation exists | ||||||||||||||||||
|
|
@@ -4588,6 +4636,13 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
| $related->getId(), | ||||||||||||||||||
| $related->setAttribute($twoWayKey, $document->getId()) | ||||||||||||||||||
| )); | ||||||||||||||||||
| var_dump($relatedCollection->getId()); | ||||||||||||||||||
| var_dump($value); | ||||||||||||||||||
| var_dump(\gettype($value)); | ||||||||||||||||||
| var_dump($twoWay); | ||||||||||||||||||
| var_dump($twoWayKey); | ||||||||||||||||||
| var_dump($related); | ||||||||||||||||||
| var_dump($document->getId()); | ||||||||||||||||||
| break; | ||||||||||||||||||
| case 'object': | ||||||||||||||||||
| if ($value instanceof Document) { | ||||||||||||||||||
|
|
@@ -4606,7 +4661,7 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
|
|
||||||||||||||||||
| $this->relationshipWriteStack[] = $relatedCollection->getId(); | ||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) {// todo check if should be main::$permissions | ||||||||||||||||||
| $value->setAttribute('$permissions', $document->getAttribute('$permissions')); | ||||||||||||||||||
| } | ||||||||||||||||||
| $related = $this->createDocument( | ||||||||||||||||||
|
|
@@ -4695,7 +4750,7 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
| ); | ||||||||||||||||||
|
|
||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| if (!isset($relation['$permissions'])) { | ||||||||||||||||||
| if (!isset($relation['$permissions'])) { // todo check if should be main::$permissions | ||||||||||||||||||
| $relation->setAttribute('$permissions', $document->getAttribute('$permissions')); | ||||||||||||||||||
| } | ||||||||||||||||||
| $this->createDocument( | ||||||||||||||||||
|
|
@@ -4735,7 +4790,7 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
| ); | ||||||||||||||||||
|
|
||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) { // todo check if should be main::$permissions | ||||||||||||||||||
| $value->setAttribute('$permissions', $document->getAttribute('$permissions')); | ||||||||||||||||||
| } | ||||||||||||||||||
| $this->createDocument( | ||||||||||||||||||
|
|
@@ -4808,7 +4863,7 @@ private function updateDocumentRelationships(Document $collection, Document $old | |||||||||||||||||
| $related = $this->getDocument($relatedCollection->getId(), $relation->getId(), [Query::select(['$id'])]); | ||||||||||||||||||
|
|
||||||||||||||||||
| if ($related->isEmpty()) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) { | ||||||||||||||||||
| if (!isset($value['$permissions'])) {// todo check if should be main::$permissions | ||||||||||||||||||
| $relation->setAttribute('$permissions', $document->getAttribute('$permissions')); | ||||||||||||||||||
| } | ||||||||||||||||||
| $related = $this->createDocument( | ||||||||||||||||||
|
|
@@ -6085,6 +6140,9 @@ public function find(string $collection, array $queries = [], string $forPermiss | |||||||||||||||||
|
|
||||||||||||||||||
| if (!$node->isEmpty()) { | ||||||||||||||||||
| $node->setAttribute('$collection', $collection->getId()); | ||||||||||||||||||
| $node->setAttribute('main::$collection', DateTime::formatTz($node->getAttribute('main::$collection'))); | ||||||||||||||||||
| $node->setAttribute('main::$createdAt', DateTime::formatTz($node->getAttribute('main::$createdAt'))); | ||||||||||||||||||
| $node->setAttribute('main::$updatedAt', DateTime::formatTz($node->getAttribute('main::$updatedAt'))); | ||||||||||||||||||
| } | ||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -6298,6 +6356,21 @@ public static function addFilter(string $name, callable $encode, callable $decod | |||||||||||||||||
| */ | ||||||||||||||||||
| public function encode(Document $collection, Document $document): Document | ||||||||||||||||||
| { | ||||||||||||||||||
| /** | ||||||||||||||||||
| * When iterating over an ArrayObject, foreach uses an internal iterator (like Iterator), and modifying the object during iteration doesn’t affect the iterator immediately. | ||||||||||||||||||
| */ | ||||||||||||||||||
| $keysToRemove = []; | ||||||||||||||||||
|
|
||||||||||||||||||
| foreach ($document as $key => $value) { | ||||||||||||||||||
| if (strpos($key, '::$') !== false) { | ||||||||||||||||||
| $keysToRemove[] = $key; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| foreach ($keysToRemove as $key) { | ||||||||||||||||||
| unset($document[$key]); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| $attributes = $collection->getAttribute('attributes', []); | ||||||||||||||||||
|
|
||||||||||||||||||
| $internalAttributes = \array_filter(Database::INTERNAL_ATTRIBUTES, function ($attribute) { | ||||||||||||||||||
|
|
@@ -6586,12 +6659,12 @@ private function validateSelections(Document $collection, array $queries): array | |||||||||||||||||
|
|
||||||||||||||||||
| $selections = \array_merge($selections, $relationshipSelections); | ||||||||||||||||||
|
|
||||||||||||||||||
| $selections[] = '$id'; | ||||||||||||||||||
| $selections[] = '$sequence'; | ||||||||||||||||||
| $selections[] = '$collection'; | ||||||||||||||||||
| $selections[] = '$createdAt'; | ||||||||||||||||||
| $selections[] = '$updatedAt'; | ||||||||||||||||||
| $selections[] = '$permissions'; | ||||||||||||||||||
| // $selections[] = '$id'; | ||||||||||||||||||
| // $selections[] = '$sequence'; | ||||||||||||||||||
| // $selections[] = '$collection'; | ||||||||||||||||||
| // $selections[] = '$createdAt'; | ||||||||||||||||||
| // $selections[] = '$updatedAt'; | ||||||||||||||||||
| // $selections[] = '$permissions'; | ||||||||||||||||||
|
|
||||||||||||||||||
| return \array_values(\array_unique($selections)); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -80,17 +80,17 @@ public function getCollection(): string | |||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @return array<string> | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public function getPermissions(): array | ||||||||||||||||||||||||||||||||||
| public function getPermissions(string $attribute = '$permissions'): array | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| return \array_values(\array_unique($this->getAttribute('$permissions', []))); | ||||||||||||||||||||||||||||||||||
| return \array_values(\array_unique($this->getAttribute($attribute, []))); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
86
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against non-array permission payloads
- public function getPermissions(string $attribute = '$permissions'): array
- {
- return \array_values(\array_unique($this->getAttribute($attribute, [])));
- }
+ public function getPermissions(string $attribute = '$permissions'): array
+ {
+ $permissions = $this->getAttribute($attribute, []);
+
+ if (!\is_array($permissions)) {
+ // Fail-safe – return an empty list rather than trigger a PHP warning
+ return [];
+ }
+
+ return \array_values(\array_unique($permissions));
+ }Same defensive check is advisable in the other helpers that delegate to this method. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @return array<string> | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public function getRead(): array | ||||||||||||||||||||||||||||||||||
| public function getRead(string $attribute = '$permissions'): array | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| return $this->getPermissionsByType(Database::PERMISSION_READ); | ||||||||||||||||||||||||||||||||||
| return $this->getPermissionsByType(Database::PERMISSION_READ, $attribute); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+91
to
94
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Propagate the attribute parameter to the convenience helpers
If callers pass a custom attribute key to - public function getRead(string $attribute = '$permissions'): array
- {
- return $this->getPermissionsByType(Database::PERMISSION_READ, $attribute);
- }
+ public function getRead(string $attribute = '$permissions'): array
+ {
+ return $this->getPermissionsByType(Database::PERMISSION_READ, $attribute);
+ }Replicate the additional
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
|
|
@@ -132,11 +132,11 @@ public function getWrite(): array | |||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @return array<string> | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public function getPermissionsByType(string $type): array | ||||||||||||||||||||||||||||||||||
| public function getPermissionsByType(string $type, string $attribute = '$permissions'): array | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| $typePermissions = []; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| foreach ($this->getPermissions() as $permission) { | ||||||||||||||||||||||||||||||||||
| foreach ($this->getPermissions($attribute) as $permission) { | ||||||||||||||||||||||||||||||||||
| if (!\str_starts_with($permission, $type)) { | ||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
@@ -183,13 +183,8 @@ public function getAttributes(): array | |||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| $attributes = []; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| $internalKeys = \array_map( | ||||||||||||||||||||||||||||||||||
| fn ($attr) => $attr['$id'], | ||||||||||||||||||||||||||||||||||
| Database::INTERNAL_ATTRIBUTES | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| foreach ($this as $attribute => $value) { | ||||||||||||||||||||||||||||||||||
| if (\in_array($attribute, $internalKeys)) { | ||||||||||||||||||||||||||||||||||
| if (Database::isInternalAttribute($attribute)){ | ||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.