Merge pull request #11754 from appwrite/claude/sync-1.9.x-fix-tests-VoCBt

Fix PHPStan baseline and code quality issues
This commit is contained in:
Damodar Lohani
2026-04-02 08:17:54 +05:45
committed by GitHub
39 changed files with 260 additions and 750 deletions
+9 -1
View File
@@ -150,8 +150,16 @@ jobs:
- name: Install dependencies
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
- name: Cache PHPStan result cache
uses: actions/cache@v4
with:
path: .phpstan-cache
key: phpstan-${{ github.sha }}
restore-keys: |
phpstan-
- name: Run PHPStan
run: composer analyze
run: composer analyze -- --no-progress
locale:
name: Checks / Locale
+1
View File
@@ -21,6 +21,7 @@ appwrite.config.json
/app/config/specs/
/docs/examples/
.phpunit.cache
.phpstan-cache
playwright-report
test-results
docker-compose.web-installer.yml
+4
View File
@@ -1180,6 +1180,7 @@ Http::get('/v1/messaging/providers/:providerId/logs')
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
'userType' => $log['data']['userType'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
@@ -2585,6 +2586,7 @@ Http::get('/v1/messaging/topics/:topicId/logs')
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
'userType' => $log['data']['userType'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
@@ -3000,6 +3002,7 @@ Http::get('/v1/messaging/subscribers/:subscriberId/logs')
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
'userType' => $log['data']['userType'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
@@ -3813,6 +3816,7 @@ Http::get('/v1/messaging/messages/:messageId/logs')
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
'userType' => $log['data']['userType'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
+2
View File
@@ -972,6 +972,8 @@ Http::get('/v1/users/:userId/logs')
'userId' => ID::custom($log['data']['userId']),
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
'userType' => $log['data']['userType'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
-508
View File
@@ -216,102 +216,6 @@ parameters:
count: 1
path: src/Appwrite/GraphQL/Resolvers.php
-
message: '#^Variable \$databaseId might not be defined\.$#'
identifier: variable.undefined
count: 5
path: src/Appwrite/GraphQL/Schema.php
-
message: '#^Variable \$sdk in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/GraphQL/Schema.php
-
message: '#^Method Appwrite\\GraphQL\\Types\:\:assoc\(\) should return Appwrite\\GraphQL\\Types\\Json but returns GraphQL\\Type\\Definition\\Type\.$#'
identifier: return.type
count: 1
path: src/Appwrite/GraphQL/Types.php
-
message: '#^Method Appwrite\\GraphQL\\Types\:\:inputFile\(\) should return Appwrite\\GraphQL\\Types\\InputFile but returns GraphQL\\Type\\Definition\\Type\.$#'
identifier: return.type
count: 1
path: src/Appwrite/GraphQL/Types.php
-
message: '#^Method Appwrite\\GraphQL\\Types\:\:json\(\) should return Appwrite\\GraphQL\\Types\\Json but returns GraphQL\\Type\\Definition\\Type\.$#'
identifier: return.type
count: 1
path: src/Appwrite/GraphQL/Types.php
-
message: '#^Class Appwrite\\Network\\Validator\\CNAME not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/GraphQL/Types/Mapper.php
-
message: '#^Class Utopia\\Validator\\Origin not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/GraphQL/Types/Mapper.php
-
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V15\:\:documentsIterator\(\)\.$#'
identifier: method.notFound
count: 7
path: src/Appwrite/Migration/Version/V15.php
-
message: '#^Method Appwrite\\Migration\\Version\\V15\:\:fixDocument\(\) should return Utopia\\Database\\Document but empty return statement found\.$#'
identifier: return.empty
count: 1
path: src/Appwrite/Migration/Version/V15.php
-
message: '#^PHPDoc tag @return with type string\|false is not subtype of native type string\.$#'
identifier: return.phpDocType
count: 1
path: src/Appwrite/Migration/Version/V15.php
-
message: '#^Variable \$tag on left side of \?\? always exists and is always null\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Migration/Version/V15.php
-
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V17\:\:documentsIterator\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Appwrite/Migration/Version/V17.php
-
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V18\:\:documentsIterator\(\)\.$#'
identifier: method.notFound
count: 2
path: src/Appwrite/Migration/Version/V18.php
-
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V19\:\:documentsIterator\(\)\.$#'
identifier: method.notFound
count: 4
path: src/Appwrite/Migration/Version/V19.php
-
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V20\:\:documentsIterator\(\)\.$#'
identifier: method.notFound
count: 6
path: src/Appwrite/Migration/Version/V20.php
-
message: '#^Variable \$query on left side of \?\? always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Migration/Version/V20.php
-
message: '#^Method Appwrite\\Network\\Cors\:\:headers\(\) should return array\<string, string\> but returns array\<string, int\|string\>\.$#'
identifier: return.type
@@ -474,18 +378,6 @@ parameters:
count: 1
path: src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php
-
message: '#^Variable \$device might not be defined\.$#'
identifier: variable.undefined
count: 5
path: src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
-
message: '#^Variable \$path might not be defined\.$#'
identifier: variable.undefined
count: 5
path: src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
-
message: '#^Call to method getAttribute\(\) on an unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#'
identifier: class.notFound
@@ -546,12 +438,6 @@ parameters:
count: 1
path: src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php
-
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php
-
message: '#^Undefined variable\: \$cpus$#'
identifier: variable.undefined
@@ -600,24 +486,6 @@ parameters:
count: 1
path: src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php
-
message: '#^Variable \$device might not be defined\.$#'
identifier: variable.undefined
count: 5
path: src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
-
message: '#^Variable \$path might not be defined\.$#'
identifier: variable.undefined
count: 5
path: src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
-
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php
-
message: '#^Variable \$iv might not be defined\.$#'
identifier: variable.undefined
@@ -630,30 +498,6 @@ parameters:
count: 1
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php
-
message: '#^Variable \$allowedFileExtensions on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
-
message: '#^Variable \$antivirus on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
-
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
-
message: '#^Variable \$transformations on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
-
message: '#^Caught class Appwrite\\Platform\\Modules\\Teams\\Http\\Memberships\\Throwable not found\.$#'
identifier: class.notFound
@@ -678,78 +522,6 @@ parameters:
count: 14
path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php
-
message: '#^Variable \$logBase might not be defined\.$#'
identifier: variable.undefined
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
-
message: '#^Variable \$previewUrl in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
-
message: '#^Variable \$repositoryName in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
-
message: '#^Variable \$rule in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
-
message: '#^Result of method Utopia\\Http\\Response\:\:redirect\(\) \(void\) is used\.$#'
identifier: method.void
count: 2
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
-
message: '#^Undefined variable\: \$redirectFailure$#'
identifier: variable.undefined
count: 2
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
-
message: '#^Variable \$redirectFailure in empty\(\) is never defined\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
-
message: '#^Result of method Appwrite\\Utopia\\Response\:\:json\(\) \(void\) is used\.$#'
identifier: method.void
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
-
message: '#^Variable \$logBase might not be defined\.$#'
identifier: variable.undefined
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
-
message: '#^Variable \$previewUrl in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
-
message: '#^Variable \$repositoryName in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
-
message: '#^Variable \$rule in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
-
message: '#^Variable \$providerConfig on left side of \?\? always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
@@ -918,108 +690,6 @@ parameters:
count: 1
path: src/Appwrite/SDK/Method.php
-
message: '#^PHPDoc tag @param references unknown parameter\: \$services$#'
identifier: parameter.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format.php
-
message: '#^PHPDoc tag @return with type Appwrite\\SDK\\Specification\\Format is incompatible with native type array\.$#'
identifier: return.phpDocType
count: 1
path: src/Appwrite/SDK/Specification/Format.php
-
message: '#^Cannot unset offset ''schema'' on array\{description\: ''No content'', content\?\: non\-empty\-array\<''''\|''\*/\*''\|''application/json''\|''image/\*''\|''image/png''\|''multipart/form\-data''\|''text/html''\|''text/plain'', array\{schema\: array\{''\$ref''\: non\-falsy\-string\}\}\|array\{schema\: array\{oneOf\: array\<array\{''\$ref''\: non\-falsy\-string\}\>\}\}\>\}\.$#'
identifier: unset.offset
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Class Utopia\\Database\\Validator\\DatetimeValidator not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Class Utopia\\Validator\\Length not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Class Utopia\\Validator\\Mock not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Offset ''securityDefinitions'' on array\{openapi\: ''3\.0\.0'', info\: array\{version\: string, title\: string, description\: string, termsOfService\: string, contact\: array\{name\: string, url\: string, email\: string\}, license\: array\{name\: ''BSD\-3\-Clause'', url\: ''https\://raw…''\}\}, servers\: array\{array\{url\: string\}, array\{url\: string\}\}, paths\: array\{\}, tags\: array, components\: array\{schemas\: array\{\}, securitySchemes\: array\}, externalDocs\: array\{description\: string, url\: string\}\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Variable \$desc on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Variable \$validator in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
-
message: '#^Class Utopia\\Database\\Validator\\DatetimeValidator not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Class Utopia\\Validator\\Length not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Class Utopia\\Validator\\Mock not found\.$#'
identifier: class.notFound
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^PHPDoc tag @var with type Appwrite\\SDK\\Method is not subtype of native type \*NEVER\*\.$#'
identifier: varTag.nativeType
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Variable \$additionalMethods in empty\(\) always exists and is always falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Variable \$desc on left side of \?\?\= always exists and is not nullable\.$#'
identifier: nullCoalesce.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Variable \$sdk in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^Variable \$validator in empty\(\) always exists and is not falsy\.$#'
identifier: empty.variable
count: 1
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
-
message: '#^PHPDoc tag @param has invalid value \(Document \$this\)\: Unexpected token "\$this", expected variable at offset 69 on line 4$#'
identifier: phpDoc.parseError
@@ -1032,196 +702,18 @@ parameters:
count: 1
path: src/Appwrite/Utopia/Database/Documents/User.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Databases\\Legacy\\DatabasesStringTypesTest\:\:\$setupCache through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 4
path: tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsGuestTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsGuestTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsMemberTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsMemberTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsTeamTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsTeamTest.php
-
message: '#^Method PHPUnit\\Framework\\TestCase\:\:addToAssertionCount\(\) invoked with 2 parameters, 1 required\.$#'
identifier: arguments.count
count: 1
path: tests/e2e/Services/Functions/FunctionsCustomClientTest.php
-
message: '#^Variable \$largeTag might not be defined\.$#'
identifier: variable.undefined
count: 8
path: tests/e2e/Services/Functions/FunctionsCustomServerTest.php
-
message: '#^Binary operation "\+" between string and 1 results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: tests/e2e/Services/GraphQL/Legacy/AbuseTest.php
-
message: '#^Variable \$from in empty\(\) is never defined\.$#'
identifier: empty.variable
count: 1
path: tests/e2e/Services/GraphQL/MessagingTest.php
-
message: '#^Method Tests\\E2E\\Services\\GraphQL\\StorageClientTest\:\:testGetFileDownload\(\) should return array but return statement is missing\.$#'
identifier: return.missing
count: 1
path: tests/e2e/Services/GraphQL/StorageClientTest.php
-
message: '#^Method Tests\\E2E\\Services\\GraphQL\\StorageServerTest\:\:testGetFileDownload\(\) should return array but return statement is missing\.$#'
identifier: return.missing
count: 1
path: tests/e2e/Services/GraphQL/StorageServerTest.php
-
message: '#^Binary operation "\+" between string and 1 results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php
-
message: '#^Variable \$from in empty\(\) is never defined\.$#'
identifier: empty.variable
count: 1
path: tests/e2e/Services/Messaging/MessagingConsoleClientTest.php
-
message: '#^Variable \$from in empty\(\) is never defined\.$#'
identifier: empty.variable
count: 1
path: tests/e2e/Services/Messaging/MessagingCustomClientTest.php
-
message: '#^Variable \$from in empty\(\) is never defined\.$#'
identifier: empty.variable
count: 1
path: tests/e2e/Services/Messaging/MessagingCustomServerTest.php
-
message: '#^Anonymous function has an unused use \$databaseId\.$#'
identifier: closure.unusedUse
count: 6
path: tests/e2e/Services/Migrations/MigrationsConsoleClientTest.php
-
message: '#^Anonymous function has an unused use \$tableId\.$#'
identifier: closure.unusedUse
count: 6
path: tests/e2e/Services/Migrations/MigrationsConsoleClientTest.php
-
message: '#^Variable \$largeFile might not be defined\.$#'
identifier: variable.undefined
count: 8
path: tests/e2e/Services/Storage/StorageConsoleClientTest.php
-
message: '#^Variable \$largeFile might not be defined\.$#'
identifier: variable.undefined
count: 8
path: tests/e2e/Services/Storage/StorageCustomClientTest.php
-
message: '#^Variable \$largeFile might not be defined\.$#'
identifier: variable.undefined
count: 8
path: tests/e2e/Services/Storage/StorageCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\TablesDB\\DatabasesStringTypesTest\:\:\$setupCache through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 4
path: tests/e2e/Services/TablesDB/DatabasesStringTypesTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsGuestTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsGuestTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsMemberTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsMemberTest.php
-
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsTeamTest\:\:getIndexUrl\(\)\.$#'
identifier: method.notFound
count: 1
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsTeamTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedHashedPasswordUsers through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 2
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedUser through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 7
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedUserTarget through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 7
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userEmailUpdated through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 3
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userNameUpdated through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 3
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userNumberUpdated through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 3
path: tests/e2e/Services/Users/UsersCustomServerTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\VCS\\VCSConsoleClientTest\:\:\$cachedFunctionData through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 4
path: tests/e2e/Services/VCS/VCSConsoleClientTest.php
-
message: '#^Unsafe access to private property Tests\\E2E\\Services\\VCS\\VCSConsoleClientTest\:\:\$cachedInstallationId through static\:\:\.$#'
identifier: staticClassAccess.privateProperty
count: 4
path: tests/e2e/Services/VCS/VCSConsoleClientTest.php
-
message: '#^Unsafe call to private method Tests\\Unit\\Auth\\KeyTest\:\:generateKey\(\) through static\:\:\.$#'
identifier: staticClassAccess.privateMethod
count: 3
path: tests/unit/Auth/KeyTest.php
-
message: '#^Call to an undefined method Utopia\\Queue\\Publisher\:\:getEvents\(\)\.$#'
identifier: method.notFound
+1
View File
@@ -3,6 +3,7 @@ includes:
parameters:
level: 3
tmpDir: .phpstan-cache
paths:
- src
- app
+2 -2
View File
@@ -4,7 +4,7 @@ namespace Appwrite\Event\Message;
use Utopia\Database\Document;
class Usage extends Base
final class Usage extends Base
{
/**
* @param Document $project
@@ -40,7 +40,7 @@ class Usage extends Base
*/
public static function fromArray(array $data): static
{
return new static(
return new self(
project: new Document($data['project'] ?? []),
metrics: $data['metrics'] ?? [],
reduce: array_map(fn (array $doc) => new Document($doc), $data['reduce'] ?? []),
+76 -75
View File
@@ -98,10 +98,9 @@ class Schema
foreach ($routes as $route) {
/** @var Route $route */
/** @var \Appwrite\SDK\Method $sdk */
$sdk = $route->getLabel('sdk', false);
if (empty($sdk)) {
if ($sdk === false) {
continue;
}
@@ -177,7 +176,7 @@ class Schema
$required = $attr['required'];
$default = $attr['default'];
$escapedKey = str_replace('$', '', $key);
$collections[$collectionId][$escapedKey] = [
$collections[$databaseId][$collectionId][$escapedKey] = [
'type' => Mapper::attribute(
$type,
$array,
@@ -187,80 +186,82 @@ class Schema
];
}
foreach ($collections as $collectionId => $attributes) {
$objectType = new ObjectType([
'name' => $collectionId,
'fields' => \array_merge(
["_id" => ['type' => Type::string()]],
$attributes
),
]);
$attributes = \array_merge(
$attributes,
Mapper::args('mutate')
);
$queryFields[$collectionId . 'Get'] = [
'type' => $objectType,
'args' => Mapper::args('id'),
'resolve' => Resolvers::documentGet(
$utopia,
$databaseId,
$collectionId,
$urls['get'],
)
];
$queryFields[$collectionId . 'List'] = [
'type' => Type::listOf($objectType),
'args' => Mapper::args('list'),
'resolve' => Resolvers::documentList(
$utopia,
$databaseId,
$collectionId,
$urls['list'],
$params['list'],
),
'complexity' => $complexity,
];
$mutationFields[$collectionId . 'Create'] = [
'type' => $objectType,
'args' => $attributes,
'resolve' => Resolvers::documentCreate(
$utopia,
$databaseId,
$collectionId,
$urls['create'],
$params['create'],
)
];
$mutationFields[$collectionId . 'Update'] = [
'type' => $objectType,
'args' => \array_merge(
Mapper::args('id'),
\array_map(
fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']),
foreach ($collections as $databaseId => $databaseCollections) {
foreach ($databaseCollections as $collectionId => $attributes) {
$objectType = new ObjectType([
'name' => $collectionId,
'fields' => \array_merge(
["_id" => ['type' => Type::string()]],
$attributes
),
]);
$attributes = \array_merge(
$attributes,
Mapper::args('mutate')
);
$queryFields[$collectionId . 'Get'] = [
'type' => $objectType,
'args' => Mapper::args('id'),
'resolve' => Resolvers::documentGet(
$utopia,
$databaseId,
$collectionId,
$urls['get'],
)
),
'resolve' => Resolvers::documentUpdate(
$utopia,
$databaseId,
$collectionId,
$urls['update'],
$params['update'],
)
];
$mutationFields[$collectionId . 'Delete'] = [
'type' => Mapper::model('none'),
'args' => Mapper::args('id'),
'resolve' => Resolvers::documentDelete(
$utopia,
$databaseId,
$collectionId,
$urls['delete'],
)
];
];
$queryFields[$collectionId . 'List'] = [
'type' => Type::listOf($objectType),
'args' => Mapper::args('list'),
'resolve' => Resolvers::documentList(
$utopia,
$databaseId,
$collectionId,
$urls['list'],
$params['list'],
),
'complexity' => $complexity,
];
$mutationFields[$collectionId . 'Create'] = [
'type' => $objectType,
'args' => $attributes,
'resolve' => Resolvers::documentCreate(
$utopia,
$databaseId,
$collectionId,
$urls['create'],
$params['create'],
)
];
$mutationFields[$collectionId . 'Update'] = [
'type' => $objectType,
'args' => \array_merge(
Mapper::args('id'),
\array_map(
fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']),
$attributes
)
),
'resolve' => Resolvers::documentUpdate(
$utopia,
$databaseId,
$collectionId,
$urls['update'],
$params['update'],
)
];
$mutationFields[$collectionId . 'Delete'] = [
'type' => Mapper::model('none'),
'args' => Mapper::args('id'),
'resolve' => Resolvers::documentDelete(
$utopia,
$databaseId,
$collectionId,
$urls['delete'],
)
];
}
}
$offset += $limit;
}
+16 -7
View File
@@ -15,10 +15,13 @@ class Types
*
* @return Json
*/
public static function json(): Type
public static function json(): Json
{
if (Registry::has(Json::class)) {
return Registry::get(Json::class);
$type = Registry::get(Json::class);
if ($type instanceof Json) {
return $type;
}
}
$type = new Json();
Registry::set(Json::class, $type);
@@ -28,12 +31,15 @@ class Types
/**
* Get the JSON type.
*
* @return Json
* @return Assoc
*/
public static function assoc(): Type
public static function assoc(): Assoc
{
if (Registry::has(Assoc::class)) {
return Registry::get(Assoc::class);
$type = Registry::get(Assoc::class);
if ($type instanceof Assoc) {
return $type;
}
}
$type = new Assoc();
Registry::set(Assoc::class, $type);
@@ -45,10 +51,13 @@ class Types
*
* @return InputFile
*/
public static function inputFile(): Type
public static function inputFile(): InputFile
{
if (Registry::has(InputFile::class)) {
return Registry::get(InputFile::class);
$type = Registry::get(InputFile::class);
if ($type instanceof InputFile) {
return $type;
}
}
$type = new InputFile();
Registry::set(InputFile::class, $type);
+1 -3
View File
@@ -273,11 +273,9 @@ class Mapper
case \Appwrite\Auth\Validator\Password::class:
case \Appwrite\Event\Validator\Event::class:
case \Appwrite\Event\Validator\FunctionEvent::class:
case \Appwrite\Network\Validator\CNAME::class:
case \Utopia\Emails\Validator\Email::class:
case \Appwrite\Network\Validator\Redirect::class:
case \Appwrite\Network\Validator\DNS::class:
case \Appwrite\Network\Validator\Origin::class:
case \Appwrite\Task\Validator\Cron::class:
case \Appwrite\Utopia\Database\Validator\CustomId::class:
case \Utopia\Database\Validator\Key::class:
@@ -286,7 +284,7 @@ class Mapper
case \Utopia\Validator\HexColor::class:
case \Utopia\Validator\Host::class:
case \Utopia\Validator\IP::class:
case \Utopia\Validator\Origin::class:
case \Appwrite\Network\Validator\Origin::class:
case \Utopia\Validator\Text::class:
case \Utopia\Validator\URL::class:
case \Utopia\Validator\WhiteList::class:
+25
View File
@@ -13,6 +13,7 @@ use Utopia\Database\Exception\Limit;
use Utopia\Database\Exception\Structure;
use Utopia\Database\Helpers\ID;
use Utopia\Database\PDO;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
abstract class Migration
@@ -204,6 +205,30 @@ abstract class Migration
}
}
/**
* @param array<Query> $queries
* @return \Generator<int, Document>
* @throws Exception
*/
protected function documentsIterator(string $collection, array $queries = []): \Generator
{
$offset = 0;
do {
$documents = $this->dbForProject->find($collection, [
...$queries,
Query::limit($this->limit),
Query::offset($offset),
]);
foreach ($documents as $document) {
yield $document;
}
$offset += \count($documents);
} while (\count($documents) === $this->limit);
}
/**
* Creates collection from the config collection.
*
+4 -5
View File
@@ -1224,7 +1224,7 @@ class V15 extends Migration
* @param \Utopia\Database\Document $document
* @return \Utopia\Database\Document
*/
protected function fixDocument(Document $document)
protected function fixDocument(Document $document): Document
{
switch ($document->getCollection()) {
case 'cache':
@@ -1234,7 +1234,7 @@ class V15 extends Migration
* skipping migration for 'cache' and 'variables'.
* 'users' already migrated.
*/
return;
return $document;
case '_metadata':
/**
@@ -1480,7 +1480,6 @@ class V15 extends Migration
* Filter from the 'encrypt' filter.
*
* @param string $value
* @return string|false
*/
protected function encryptFilter(string $value): string
{
@@ -1492,8 +1491,8 @@ class V15 extends Migration
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => \bin2hex($iv),
'tag' => \bin2hex($tag ?? ''),
'tag' => \bin2hex($tag),
'version' => '1',
]);
]) ?: '';
}
}
+1 -1
View File
@@ -452,7 +452,7 @@ class V20 extends Migration
Query::equal('period', ['1d']),
]);
$value = $query ?? 0;
$value = $query;
$this->createInfMetric($to, $value);
}
@@ -88,16 +88,11 @@ class Get extends Action
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
}
switch ($type) {
case 'output':
$path = $deployment->getAttribute('buildPath', '');
$device = $deviceForBuilds;
break;
case 'source':
$path = $deployment->getAttribute('sourcePath', '');
$device = $deviceForFunctions;
break;
}
[$path, $device] = match ($type) {
'output' => [$deployment->getAttribute('buildPath', ''), $deviceForBuilds],
'source' => [$deployment->getAttribute('sourcePath', ''), $deviceForFunctions],
default => throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid deployment download type.'),
};
if (!$device->exists($path)) {
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
@@ -170,8 +170,6 @@ class Update extends Base
$runtime = $function->getAttribute('runtime');
}
$enabled ??= $function->getAttribute('enabled', true);
$repositoryId = $function->getAttribute('repositoryId', '');
$repositoryInternalId = $function->getAttribute('repositoryInternalId', '');
@@ -87,16 +87,11 @@ class Get extends Action
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
}
switch ($type) {
case 'output':
$path = $deployment->getAttribute('buildPath', '');
$device = $deviceForBuilds;
break;
case 'source':
$path = $deployment->getAttribute('sourcePath', '');
$device = $deviceForSites;
break;
}
[$path, $device] = match ($type) {
'output' => [$deployment->getAttribute('buildPath', ''), $deviceForBuilds],
'source' => [$deployment->getAttribute('sourcePath', ''), $deviceForSites],
default => throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid deployment download type.'),
};
if (!$device->exists($path)) {
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
@@ -172,8 +172,6 @@ class Update extends Base
$framework = $site->getAttribute('framework');
}
$enabled ??= $site->getAttribute('enabled', true);
$repositoryId = $site->getAttribute('repositoryId', '');
$repositoryInternalId = $site->getAttribute('repositoryInternalId', '');
@@ -99,12 +99,8 @@ class Update extends Action
$permissions ??= $bucket->getPermissions();
$maximumFileSize ??= $bucket->getAttribute('maximumFileSize', (int) System::getEnv('_APP_STORAGE_LIMIT', 0));
$allowedFileExtensions ??= $bucket->getAttribute('allowedFileExtensions', []);
$enabled ??= $bucket->getAttribute('enabled', true);
$encryption ??= $bucket->getAttribute('encryption', true);
$antivirus ??= $bucket->getAttribute('antivirus', true);
$compression ??= $bucket->getAttribute('compression', Compression::NONE);
$transformations ??= $bucket->getAttribute('transformations', true);
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission::aggregate($permissions);
@@ -110,10 +110,7 @@ class Update extends Action
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
try {
$providerRepositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($providerRepositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$providerRepositoryName = $github->getRepositoryName($providerRepositoryId);
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -65,6 +65,7 @@ class Get extends Action
}
$state = \json_decode($state, true);
$redirectFailure = $state['failure'] ?? '';
$projectId = $state['projectId'] ?? '';
$project = $dbForPlatform->getDocument('projects', $projectId);
@@ -74,10 +75,11 @@ class Get extends Action
if (!empty($redirectFailure)) {
$separator = \str_contains($redirectFailure, '?') ? '&' : ':';
return $response
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($redirectFailure . $separator . \http_build_query(['error' => $error]));
return;
}
throw new Exception(Exception::PROJECT_NOT_FOUND, $error);
@@ -165,10 +167,11 @@ class Get extends Action
if (!empty($redirectFailure)) {
$separator = \str_contains($redirectFailure, '?') ? '&' : ':';
return $response
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($redirectFailure . $separator . \http_build_query(['error' => $error]));
return;
}
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $error);
@@ -49,6 +49,8 @@ trait Deployment
) {
$errors = [];
foreach ($repositories as $repository) {
$logBase = 'vcs.github.event.repo.unknown';
try {
$repositoryId = $repository->getId();
$projectId = $repository->getAttribute('projectId');
@@ -107,18 +109,11 @@ trait Deployment
$owner = $github->getOwnerName($providerInstallationId) ?? '';
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$repositoryName = $github->getRepositoryName($providerRepositoryId);
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$isAuthorized = !$external;
if (!$isAuthorized && !empty($providerPullRequestId)) {
@@ -291,10 +286,7 @@ trait Deployment
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$repositoryName = $github->getRepositoryName($providerRepositoryId);
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -501,7 +493,7 @@ trait Deployment
$rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId));
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
$previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
$previewUrl = !$rule->isEmpty() ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
if (!empty($previewUrl)) {
$comment = new Comment($platform);
@@ -524,10 +516,7 @@ trait Deployment
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$repositoryName = $github->getRepositoryName($providerRepositoryId);
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -83,7 +83,7 @@ class Create extends Action
default => null,
};
return $response->json($parsedPayload);
$response->json($parsedPayload);
}
protected function preprocessEvent(Request $request)
@@ -204,9 +204,6 @@ abstract class Format
*
* Get services value
*
* @param array $services
*
* @return self
*/
public function getServices(): array
{
@@ -79,8 +79,8 @@ class OpenAPI3 extends Format
$output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '<YOUR_API_KEY>'];
}
if (isset($output['securityDefinitions']['JWT'])) {
$output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => '<YOUR_JWT>'];
if (isset($output['components']['securitySchemes']['JWT'])) {
$output['components']['securitySchemes']['JWT']['x-appwrite'] = ['demo' => '<YOUR_JWT>'];
}
if (isset($output['components']['securitySchemes']['Locale'])) {
@@ -99,7 +99,7 @@ class OpenAPI3 extends Format
$sdk = $route->getLabel('sdk', false);
if (empty($sdk)) {
if ($sdk === false) {
continue;
}
@@ -125,7 +125,9 @@ class OpenAPI3 extends Format
$namespace = $sdk->getNamespace() ?? 'default';
$desc ??= '';
if ($desc === null) {
$desc = '';
}
$descContents = \str_ends_with($desc, '.md') ? \file_get_contents($desc) : $desc;
$temp = [
@@ -163,7 +165,7 @@ class OpenAPI3 extends Format
];
}
if (!empty($additionalMethods)) {
if (\is_array($additionalMethods) && \count($additionalMethods) > 0) {
$temp['x-appwrite']['methods'] = [];
foreach ($additionalMethods as $methodObj) {
/** @var Method $methodObj */
@@ -329,7 +331,7 @@ class OpenAPI3 extends Format
if (($response->getCode() ?? 500) === 204) {
$temp['responses'][(string)$response->getCode() ?? '500']['description'] = 'No content';
unset($temp['responses'][(string)$response->getCode() ?? '500']['schema']);
unset($temp['responses'][(string)$response->getCode() ?? '500']['content']);
}
}
@@ -383,7 +385,7 @@ class OpenAPI3 extends Format
$validator = $validator->getValidator();
}
$class = !empty($validator)
$class = $validator instanceof Validator
? \get_class($validator)
: '';
@@ -431,7 +433,7 @@ class OpenAPI3 extends Format
$node['schema']['type'] = $validator->getType();
$node['schema']['x-example'] = ($param['example'] ?? '') ?: '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
break;
case \Utopia\Database\Validator\DatetimeValidator::class:
case \Utopia\Database\Validator\Datetime::class:
$node['schema']['type'] = $validator->getType();
$node['schema']['format'] = 'datetime';
$node['schema']['x-example'] = ($param['example'] ?? '') ?: Model::TYPE_DATETIME_EXAMPLE;
@@ -463,7 +465,6 @@ class OpenAPI3 extends Format
$node['schema']['x-example'] = ($param['example'] ?? '') ?: 'https://example.com';
break;
case \Utopia\Validator\JSON::class:
case \Utopia\Validator\Mock::class:
case \Utopia\Validator\Assoc::class:
$param['default'] = (empty($param['default'])) ? new \stdClass() : $param['default'];
$node['schema']['type'] = 'object';
@@ -563,12 +564,6 @@ class OpenAPI3 extends Format
$node['schema']['x-example'] = $param['example'];
}
break;
case \Utopia\Validator\Length::class:
$node['schema']['type'] = $validator->getType();
if (!empty($param['example'])) {
$node['schema']['x-example'] = $param['example'];
}
break;
case \Utopia\Validator\WhiteList::class:
if ($array) {
$validator = $validator->getValidator();
@@ -96,10 +96,9 @@ class Swagger2 extends Format
$scope = $route->getLabel('scope', '');
/** @var Method $sdk */
$sdk = $route->getLabel('sdk', false);
if (empty($sdk)) {
if ($sdk === false) {
continue;
}
@@ -127,7 +126,9 @@ class Swagger2 extends Format
$sdkPlatforms = array_values(array_unique($sdkPlatforms));
$namespace = $sdk->getNamespace() ?? 'default';
$desc ??= '';
if ($desc === null) {
$desc = '';
}
$descContents = \str_ends_with($desc, '.md') ? \file_get_contents($desc) : $desc;
$temp = [
@@ -171,7 +172,7 @@ class Swagger2 extends Format
$temp['produces'][] = $produces;
}
if (!empty($additionalMethods)) {
if (\is_array($additionalMethods) && \count($additionalMethods) > 0) {
$temp['x-appwrite']['methods'] = [];
foreach ($additionalMethods as $methodObj) {
/** @var Method $methodObj */
@@ -388,7 +389,7 @@ class Swagger2 extends Format
$validator = $validator->getValidator();
}
$class = !empty($validator)
$class = $validator instanceof Validator
? \get_class($validator)
: '';
@@ -436,7 +437,7 @@ class Swagger2 extends Format
$node['type'] = $validator->getType();
$node['x-example'] = ($param['example'] ?? '') ?: '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
break;
case \Utopia\Database\Validator\DatetimeValidator::class:
case \Utopia\Database\Validator\Datetime::class:
$node['type'] = $validator->getType();
$node['format'] = 'datetime';
$node['x-example'] = ($param['example'] ?? '') ?: Model::TYPE_DATETIME_EXAMPLE;
@@ -479,7 +480,6 @@ class Swagger2 extends Format
}
break;
case \Utopia\Validator\JSON::class:
case \Utopia\Validator\Mock::class:
case \Utopia\Validator\Assoc::class:
$node['type'] = 'object';
$node['default'] = (empty($param['default'])) ? new \stdClass() : $param['default'];
@@ -552,12 +552,6 @@ class Swagger2 extends Format
$node['x-example'] = $param['example'];
}
break;
case \Utopia\Validator\Length::class:
$node['type'] = $validator->getType();
if (!empty($param['example'])) {
$node['x-example'] = $param['example'];
}
break;
case \Utopia\Validator\WhiteList::class:
if ($array) {
$validator = $validator->getValidator();
@@ -29,8 +29,8 @@ class DatabasesStringTypesTest extends Scope
protected function setupDatabaseAndCollection(): array
{
$cacheKey = $this->getProject()['$id'] ?? 'default';
if (!empty(static::$setupCache[$cacheKey])) {
return static::$setupCache[$cacheKey];
if (!empty(self::$setupCache[$cacheKey])) {
return self::$setupCache[$cacheKey];
}
$projectId = $this->getProject()['$id'];
@@ -135,12 +135,12 @@ class DatabasesStringTypesTest extends Scope
// Wait for all attributes to be available
$this->waitForAllAttributes($databaseId, $collectionId);
static::$setupCache[$cacheKey] = [
self::$setupCache[$cacheKey] = [
'databaseId' => $databaseId,
'collectionId' => $collectionId,
];
return static::$setupCache[$cacheKey];
return self::$setupCache[$cacheKey];
}
public function testCreateDatabase(): void
@@ -45,6 +45,12 @@ trait DatabasesPermissionsBase
return $recordId ? "{$base}/{$recordId}" : $base;
}
protected function getIndexUrl(string $databaseId, string $containerId, string $indexId = ''): string
{
$base = "{$this->getContainerUrl($databaseId, $containerId)}/indexes";
return $indexId ? "{$base}/{$indexId}" : $base;
}
// User Management Methods
public function createUser(string $id, string $email, string $password = 'test123!'): array
{
@@ -414,7 +414,7 @@ class FunctionsCustomClientTest extends Scope
'offset' => 2
]);
$this->assertEquals(200, $templatesOffset['headers']['status-code']);
$this->addToAssertionCount(1, $templatesOffset['body']['templates']);
$this->addToAssertionCount(1);
$this->assertEquals($templates['body']['templates'][2]['id'], $templatesOffset['body']['templates'][0]['id']);
// List templates with filters
@@ -1003,6 +1003,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id']
];
$id = '';
$largeTag = null;
while (!feof($handle)) {
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-fx.tar.gz');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
+1 -1
View File
@@ -409,7 +409,7 @@ class MessagingTest extends Scope
$apiKey = $emailDSN->getPassword();
$domain = $emailDSN->getUser();
if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
if (empty($to) || empty($fromName) || empty($fromEmail) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
$this->markTestSkipped('Email provider not configured');
}
@@ -229,6 +229,8 @@ class StorageClientTest extends Scope
], $this->getHeaders()), $gqlPayload);
$this->assertEquals(47218, \strlen($file['body']));
return $file;
}
/**
@@ -291,6 +291,8 @@ class StorageServerTest extends Scope
], $this->getHeaders()), $gqlPayload);
$this->assertEquals(47218, \strlen($file['body']));
return $file;
}
/**
@@ -2241,7 +2241,7 @@ trait MessagingBase
$authKey = $smsDSN->getPassword();
$templateId = $smsDSN->getParam('templateId');
if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) {
if (empty($to) || empty($senderId) || empty($authKey)) {
$this->markTestSkipped('SMS provider not configured');
}
@@ -64,8 +64,8 @@ trait MigrationsBase
*/
protected function setupMigrationDatabase(): array
{
if (!empty(static::$cachedDatabaseData)) {
return static::$cachedDatabaseData;
if (!empty(self::$cachedDatabaseData)) {
return self::$cachedDatabaseData;
}
$response = $this->client->call(Client::METHOD_POST, '/databases', [
@@ -81,11 +81,11 @@ trait MigrationsBase
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['$id']);
static::$cachedDatabaseData = [
self::$cachedDatabaseData = [
'databaseId' => $response['body']['$id'],
];
return static::$cachedDatabaseData;
return self::$cachedDatabaseData;
}
/**
@@ -94,8 +94,8 @@ trait MigrationsBase
*/
protected function setupMigrationTable(): array
{
if (!empty(static::$cachedTableData)) {
return static::$cachedTableData;
if (!empty(self::$cachedTableData)) {
return self::$cachedTableData;
}
// Ensure database exists first
@@ -141,12 +141,12 @@ trait MigrationsBase
$this->assertEquals('available', $response['body']['status']);
}, 5000, 500);
static::$cachedTableData = [
self::$cachedTableData = [
'databaseId' => $databaseId,
'tableId' => $tableId,
];
return static::$cachedTableData;
return self::$cachedTableData;
}
public function performMigrationSync(array $body): array
@@ -670,7 +670,7 @@ trait MigrationsBase
]);
// Clear the cache since we cleaned up
static::$cachedDatabaseData = [];
self::$cachedDatabaseData = [];
}
public function testAppwriteMigrationDatabasesRow(): void
@@ -757,8 +757,8 @@ trait MigrationsBase
]);
// Clear the caches since we cleaned up
static::$cachedDatabaseData = [];
static::$cachedTableData = [];
self::$cachedDatabaseData = [];
self::$cachedTableData = [];
}
/**
@@ -1331,7 +1331,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
$this->assertEventually(function () use ($missingColumn) {
$migrationId = $missingColumn['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
@@ -1363,7 +1363,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
$this->assertEventually(function () use ($missingColumn) {
$migrationId = $missingColumn['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
@@ -1395,7 +1395,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($irrelevantColumn, $databaseId, $tableId) {
$this->assertEventually(function () use ($irrelevantColumn) {
$migrationId = $irrelevantColumn['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
@@ -1422,7 +1422,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
$this->assertEventually(function () use ($migration) {
$migrationId = $migration['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
@@ -1464,7 +1464,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
$this->assertEventually(function () use ($migration) {
$migrationId = $migration['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
@@ -4018,7 +4018,7 @@ trait MigrationsBase
]
);
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
$this->assertEventually(function () use ($migration) {
$migrationId = $migration['body']['$id'];
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
'content-type' => 'application/json',
+3 -1
View File
@@ -97,6 +97,7 @@ trait StorageBase
'x-appwrite-project' => $this->getProject()['$id']
];
$id = '';
$largeFile = null;
while (!feof($handle)) {
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
@@ -132,7 +133,7 @@ trait StorageBase
self::$cachedBucketFile[$cacheKey] = [
'bucketId' => $bucketId,
'fileId' => $file['body']['$id'],
'largeFileId' => $largeFile['body']['$id'],
'largeFileId' => $largeFile['body']['$id'] ?? '',
'largeBucketId' => $bucket2['body']['$id'],
'webpFileId' => $webpFile['body']['$id']
];
@@ -261,6 +262,7 @@ trait StorageBase
'x-appwrite-project' => $this->getProject()['$id']
];
$id = '';
$largeFile = null;
while (!feof($handle)) {
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
@@ -29,8 +29,8 @@ class DatabasesStringTypesTest extends Scope
protected function setupDatabaseAndTable(): array
{
$cacheKey = $this->getProject()['$id'] ?? 'default';
if (!empty(static::$setupCache[$cacheKey])) {
return static::$setupCache[$cacheKey];
if (!empty(self::$setupCache[$cacheKey])) {
return self::$setupCache[$cacheKey];
}
$projectId = $this->getProject()['$id'];
@@ -131,7 +131,7 @@ class DatabasesStringTypesTest extends Scope
// Cache before waiting so that if waitForAllAttributes times out,
// subsequent calls don't try to re-create the same columns (causing 409)
static::$setupCache[$cacheKey] = [
self::$setupCache[$cacheKey] = [
'databaseId' => $databaseId,
'tableId' => $tableId,
];
@@ -139,7 +139,7 @@ class DatabasesStringTypesTest extends Scope
// Wait for all columns to be available
$this->waitForAllAttributes($databaseId, $tableId);
return static::$setupCache[$cacheKey];
return self::$setupCache[$cacheKey];
}
public function testCreateDatabase(): void
+25 -25
View File
@@ -28,8 +28,8 @@ trait UsersBase
protected function setupUser(): array
{
$projectId = $this->getProject()['$id'];
if (!empty(static::$cachedUser[$projectId])) {
return static::$cachedUser[$projectId];
if (!empty(self::$cachedUser[$projectId])) {
return self::$cachedUser[$projectId];
}
$user = $this->client->call(Client::METHOD_POST, '/users', array_merge([
@@ -52,16 +52,16 @@ trait UsersBase
]);
if (!empty($response['body']['users'])) {
static::$cachedUser[$projectId] = ['userId' => $response['body']['users'][0]['$id']];
return static::$cachedUser[$projectId];
self::$cachedUser[$projectId] = ['userId' => $response['body']['users'][0]['$id']];
return self::$cachedUser[$projectId];
}
}
if ($user['headers']['status-code'] === 201) {
static::$cachedUser[$projectId] = ['userId' => $user['body']['$id']];
self::$cachedUser[$projectId] = ['userId' => $user['body']['$id']];
}
return static::$cachedUser[$projectId];
return self::$cachedUser[$projectId];
}
/**
@@ -90,7 +90,7 @@ trait UsersBase
protected function setupHashedPasswordUsers(): void
{
$projectId = $this->getProject()['$id'];
if (!empty(static::$cachedHashedPasswordUsers[$projectId])) {
if (!empty(self::$cachedHashedPasswordUsers[$projectId])) {
return;
}
@@ -180,7 +180,7 @@ trait UsersBase
'passwordSignerKey' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==',
]);
static::$cachedHashedPasswordUsers[$projectId] = true;
self::$cachedHashedPasswordUsers[$projectId] = true;
}
/**
@@ -189,8 +189,8 @@ trait UsersBase
protected function setupUserTarget(): array
{
$projectId = $this->getProject()['$id'];
if (!empty(static::$cachedUserTarget[$projectId])) {
return static::$cachedUserTarget[$projectId];
if (!empty(self::$cachedUserTarget[$projectId])) {
return self::$cachedUserTarget[$projectId];
}
$data = $this->setupUser();
@@ -233,10 +233,10 @@ trait UsersBase
]);
if ($response['headers']['status-code'] === 201) {
static::$cachedUserTarget[$projectId] = $response['body'];
self::$cachedUserTarget[$projectId] = $response['body'];
}
return static::$cachedUserTarget[$projectId] ?? [];
return self::$cachedUserTarget[$projectId] ?? [];
}
/**
@@ -247,7 +247,7 @@ trait UsersBase
$data = $this->setupUser();
$projectId = $this->getProject()['$id'];
if (static::$userNameUpdated) {
if (self::$userNameUpdated) {
return $data;
}
@@ -258,7 +258,7 @@ trait UsersBase
'name' => 'Updated name',
]);
static::$userNameUpdated = true;
self::$userNameUpdated = true;
return $data;
}
@@ -270,7 +270,7 @@ trait UsersBase
$data = $this->setupUser();
$projectId = $this->getProject()['$id'];
if (static::$userEmailUpdated) {
if (self::$userEmailUpdated) {
return $data;
}
@@ -281,7 +281,7 @@ trait UsersBase
'email' => 'users.service@updated.com',
]);
static::$userEmailUpdated = true;
self::$userEmailUpdated = true;
return $data;
}
@@ -293,7 +293,7 @@ trait UsersBase
$data = $this->setupUser();
$projectId = $this->getProject()['$id'];
if (static::$userNumberUpdated) {
if (self::$userNumberUpdated) {
return $data;
}
@@ -304,7 +304,7 @@ trait UsersBase
'number' => '+910000000000',
]);
static::$userNumberUpdated = true;
self::$userNumberUpdated = true;
return $data;
}
@@ -474,7 +474,7 @@ trait UsersBase
// Cache the user ID for other tests
$projectId = $this->getProject()['$id'];
static::$cachedUser[$projectId] = ['userId' => $body['$id']];
self::$cachedUser[$projectId] = ['userId' => $body['$id']];
}
/**
@@ -1274,7 +1274,7 @@ trait UsersBase
$this->assertEquals($user['body']['name'], 'Updated name');
// Mark name as updated for search tests
static::$userNameUpdated = true;
self::$userNameUpdated = true;
}
public function testUpdateUserNameSearch(): void
@@ -1357,7 +1357,7 @@ trait UsersBase
$this->assertEquals($user['body']['email'], 'users.service@updated.com');
// Mark email as updated for search tests
static::$userEmailUpdated = true;
self::$userEmailUpdated = true;
}
public function testUpdateUserEmailSearch(): void
@@ -1645,7 +1645,7 @@ trait UsersBase
$this->assertEquals($response['body']['type'], $errorType);
// Mark phone as updated for search tests
static::$userNumberUpdated = true;
self::$userNumberUpdated = true;
}
public function testUpdateTwoUsersPhoneToEmpty(): void
@@ -1954,7 +1954,7 @@ trait UsersBase
// Cache for other tests
$projectId = $this->getProject()['$id'];
static::$cachedUserTarget[$projectId] = $response['body'];
self::$cachedUserTarget[$projectId] = $response['body'];
}
public function testUpdateUserTarget(): void
@@ -1973,7 +1973,7 @@ trait UsersBase
// Update cache with new data
$projectId = $this->getProject()['$id'];
static::$cachedUserTarget[$projectId] = $response['body'];
self::$cachedUserTarget[$projectId] = $response['body'];
}
public function testListUserTarget(): void
@@ -2014,7 +2014,7 @@ trait UsersBase
// Clear cached target since it was deleted
$projectId = $this->getProject()['$id'];
unset(static::$cachedUserTarget[$projectId]);
unset(self::$cachedUserTarget[$projectId]);
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([
'content-type' => 'application/json',
@@ -37,8 +37,8 @@ class VCSConsoleClientTest extends Scope
{
$projectId = $this->getProject()['$id'];
if (!empty(static::$cachedInstallationId[$projectId])) {
return static::$cachedInstallationId[$projectId];
if (!empty(self::$cachedInstallationId[$projectId])) {
return self::$cachedInstallationId[$projectId];
}
$response = $this->client->call(Client::METHOD_GET, '/mock/github/callback', array_merge([
@@ -48,8 +48,8 @@ class VCSConsoleClientTest extends Scope
'projectId' => $projectId,
]);
static::$cachedInstallationId[$projectId] = $response['body']['installationId'];
return static::$cachedInstallationId[$projectId];
self::$cachedInstallationId[$projectId] = $response['body']['installationId'];
return self::$cachedInstallationId[$projectId];
}
/**
@@ -60,8 +60,8 @@ class VCSConsoleClientTest extends Scope
{
$projectId = $this->getProject()['$id'];
if (!empty(static::$cachedFunctionData[$projectId])) {
return static::$cachedFunctionData[$projectId];
if (!empty(self::$cachedFunctionData[$projectId])) {
return self::$cachedFunctionData[$projectId];
}
$installationId = $this->setupInstallation();
@@ -86,12 +86,12 @@ class VCSConsoleClientTest extends Scope
'providerBranch' => 'main',
]);
static::$cachedFunctionData[$projectId] = [
self::$cachedFunctionData[$projectId] = [
'installationId' => $installationId,
'functionId' => $function['body']['$id']
];
return static::$cachedFunctionData[$projectId];
return self::$cachedFunctionData[$projectId];
}
public function testGitHubAuthorize(): void
+3 -3
View File
@@ -25,7 +25,7 @@ class KeyTest extends TestCase
$roleScopes = Config::getParam('roles', [])[User::ROLE_APPS]['scopes'];
$guestRoleScopes = Config::getParam('roles', [])[User::ROLE_GUESTS]['scopes'];
$key = static::generateKey($projectId, $usage, $scopes);
$key = self::generateKey($projectId, $usage, $scopes);
$decoded = Key::decode(
project: new Document(['$id' => $projectId]),
team: new Document(),
@@ -50,7 +50,7 @@ class KeyTest extends TestCase
'previewAuthDisabled' => true,
'deploymentStatusIgnored' => true,
];
$key = static::generateKey($projectId, $usage, $scopes, extra: $extra);
$key = self::generateKey($projectId, $usage, $scopes, extra: $extra);
$decoded = Key::decode(
project: new Document(['$id' => $projectId]),
team: new Document(),
@@ -88,7 +88,7 @@ class KeyTest extends TestCase
$this->assertEquals('UNKNOWN', $decoded->getName());
// Decode expired dynamic key
$expiredKey = static::generateKey($projectId, $usage, $scopes, maxAge: 1, timestamp: time() - 60);
$expiredKey = self::generateKey($projectId, $usage, $scopes, maxAge: 1, timestamp: time() - 60);
\sleep(2);
$decoded = Key::decode(
project: new Document(['$id' => $projectId]),