diff --git a/app/config/templates/function.php b/app/config/templates/function.php index 6bdfb5ab80..df3a569705 100644 --- a/app/config/templates/function.php +++ b/app/config/templates/function.php @@ -31,9 +31,6 @@ class FunctionUseCases public const DEV_TOOLS = 'dev-tools'; public const AUTH = 'auth'; - /** - * @var array - */ public static function getAll(): array { return [ diff --git a/app/config/templates/site.php b/app/config/templates/site.php index 50a9fb8d5d..26f8e39817 100644 --- a/app/config/templates/site.php +++ b/app/config/templates/site.php @@ -25,9 +25,6 @@ class SiteUseCases public const FORMS = 'forms'; public const DASHBOARD = 'dashboard'; - /** - * @var array - */ public static function getAll(): array { return [ @@ -252,7 +249,7 @@ return [ 'frameworks' => [ getFramework('VITE', [ 'providerRootDirectory' => './vite/vitepress', - 'outputDirectory' => '404.html', + 'fallbackFile' => '404.html', 'installCommand' => 'npm i vitepress && npm install', 'buildCommand' => 'npm run docs:build', 'outputDirectory' => './.vitepress/dist', @@ -275,7 +272,7 @@ return [ 'frameworks' => [ getFramework('VUE', [ 'providerRootDirectory' => './vue/vuepress', - 'outputDirectory' => '404.html', + 'fallbackFile' => '404.html', 'installCommand' => 'npm install', 'buildCommand' => 'npm run build', 'outputDirectory' => './src/.vuepress/dist', @@ -298,7 +295,7 @@ return [ 'frameworks' => [ getFramework('REACT', [ 'providerRootDirectory' => './react/docusaurus', - 'outputDirectory' => '404.html', + 'fallbackFile' => '404.html', 'installCommand' => 'npm install', 'buildCommand' => 'npm run build', 'outputDirectory' => './build', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 3d7db8f457..4cfc4476b6 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -695,6 +695,7 @@ Http::delete('/v1/account/sessions') $protocol = $request->getProtocol(); $sessions = $user->getAttribute('sessions', []); + $currentSession = null; foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); @@ -716,6 +717,7 @@ Http::delete('/v1/account/sessions') ->addCookie($store->getKey(), '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); // Use current session for events. + $currentSession = $session; $queueForEvents ->setPayload($response->output($session, Response::MODEL_SESSION)); @@ -728,9 +730,11 @@ Http::delete('/v1/account/sessions') $dbForProject->purgeCachedDocument('users', $user->getId()); - $queueForEvents - ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + if ($currentSession instanceof Document) { + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('sessionId', $currentSession->getId()); + } $response->noContent(); }); @@ -776,7 +780,8 @@ Http::get('/v1/account/sessions/:sessionId') ->setAttribute('secret', $session->getAttribute('secret', '')) ; - return $response->dynamic($session, Response::MODEL_SESSION); + $response->dynamic($session, Response::MODEL_SESSION); + return; } } @@ -956,7 +961,7 @@ Http::patch('/v1/account/sessions/:sessionId') ->setPayload($response->output($session, Response::MODEL_SESSION)) ; - return $response->dynamic($session, Response::MODEL_SESSION); + $response->dynamic($session, Response::MODEL_SESSION); }); Http::post('/v1/account/sessions/email') @@ -1988,7 +1993,7 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect') ->addCookie($store->getKey(), $encoded, (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')); } - if (isset($sessionUpgrade) && $sessionUpgrade) { + if (isset($sessionUpgrade) && $sessionUpgrade && isset($session)) { foreach ($user->getAttribute('targets', []) as $target) { if ($target->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) { continue; @@ -4715,5 +4720,5 @@ Http::delete('/v1/account/identities/:identityId') ->setParam('identityId', $identity->getId()) ->setPayload($response->output($identity, Response::MODEL_IDENTITY)); - return $response->noContent(); + $response->noContent(); }); diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index d6b4bb814d..c70102a6f1 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -231,6 +231,7 @@ Http::get('/v1/locale/continents') ->inject('locale') ->action(function (Response $response, Locale $locale) { $list = array_keys(Config::getParam('locale-continents')); + $output = []; foreach ($list as $value) { $output[] = new Document([ diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1ba5eb1119..95a8afc963 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -3566,7 +3566,7 @@ Http::post('/v1/messaging/messages/push') $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $endpoint = "$protocol://{$platform['apiHostname']}/v1"; - $scheduleTime = $currentScheduledAt ?? $scheduledAt; + $scheduleTime = $scheduledAt; if (!\is_null($scheduleTime)) { $expiry = (new \DateTime($scheduleTime))->add(new \DateInterval('P15D'))->format('U'); } else { diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 2fc20ba83f..4eb537d923 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1570,7 +1570,7 @@ Http::post('/v1/projects/:projectId/smtp/tests') ->trigger(); } - return $response->noContent(); + $response->noContent(); }); Http::get('/v1/projects/:projectId/templates/sms/:type/:locale') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 3b21d4797d..e4900e6564 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2337,9 +2337,8 @@ Http::post('/v1/users/:userId/sessions') ->setParam('sessionId', $session->getId()) ->setPayload($response->output($session, Response::MODEL_SESSION)); - return $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($session, Response::MODEL_SESSION); + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic($session, Response::MODEL_SESSION); }); Http::post('/v1/users/:userId/tokens') @@ -2402,9 +2401,8 @@ Http::post('/v1/users/:userId/tokens') ->setParam('tokenId', $token->getId()) ->setPayload($response->output($token, Response::MODEL_TOKEN)); - return $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($token, Response::MODEL_TOKEN); + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic($token, Response::MODEL_TOKEN); }); Http::delete('/v1/users/:userId/sessions/:sessionId') @@ -2658,7 +2656,7 @@ Http::delete('/v1/users/identities/:identityId') ->setParam('identityId', $identity->getId()) ->setPayload($response->output($identity, Response::MODEL_IDENTITY)); - return $response->noContent(); + $response->noContent(); }); Http::post('/v1/users/:userId/jwts') diff --git a/app/controllers/general.php b/app/controllers/general.php index 79929816d9..3bf5f027f2 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -166,14 +166,14 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S if ($request->getMethod() !== Request::METHOD_GET) { throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.', view: $errorView); } - return $response->redirect('https://' . $request->getHostname() . $request->getURI()); + $response->redirect('https://' . $request->getHostname() . $request->getURI()); + return false; } } /** @var Database $dbForProject */ $dbForProject = $getProjectDB($project); - /** @var Document $deployment */ if (!empty($rule->getAttribute('deploymentId', ''))) { $deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId'))); } else { @@ -244,6 +244,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S if ($isPreview && $requirePreview) { $cookie = $request->getCookie(COOKIE_NAME_PREVIEW, ''); $authorized = false; + $user = new Document(); // Security checks to mark authorized true if (!empty($cookie)) { @@ -273,7 +274,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S $membershipExists = false; $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId)); - if (!$project->isEmpty() && isset($user)) { + if (!$project->isEmpty() && !$user->isEmpty()) { $teamId = $project->getAttribute('teamId', ''); $membership = $user->find('teamId', $teamId, 'memberships'); if (!empty($membership)) { @@ -379,7 +380,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S $executionId = ID::unique(); $headers = \array_merge([], $requestHeaders); - $headers['x-appwrite-execution-id'] = $executionId ?? ''; + $headers['x-appwrite-execution-id'] = $executionId; $headers['x-appwrite-user-id'] = ''; $headers['x-appwrite-country-code'] = ''; $headers['x-appwrite-continent-code'] = ''; @@ -459,7 +460,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S if ($version === 'v2') { $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_DATA' => $body ?? '', + 'APPWRITE_FUNCTION_DATA' => $body, 'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '', 'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? '' ]); @@ -529,6 +530,11 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S } /** Execute function */ + $executionResponse = [ + 'headers' => [], + 'body' => '', + ]; + try { $version = match ($type) { 'function' => $resource->getAttribute('version', 'v2'), @@ -734,7 +740,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S $execution->setAttribute('responseBody', $executionResponse['body'] ?? ''); $execution->setAttribute('responseHeaders', $headers); - $body = $execution['responseBody'] ?? ''; + $body = $execution['responseBody']; $contentType = 'text/plain'; foreach ($executionResponse['headers'] as $name => $values) { @@ -865,9 +871,9 @@ Http::init() Request::setRoute($route); if ($route === null) { - return $response - ->setStatusCode(404) - ->send('Not Found'); + $response->setStatusCode(404); + $response->send('Not Found'); + return; } $requestFormat = $request->getHeader('x-appwrite-response-format', System::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); @@ -973,7 +979,8 @@ Http::init() throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.'); } - return $response->redirect('https://' . $request->getHostname() . $request->getURI()); + $response->redirect('https://' . $request->getHostname() . $request->getURI()); + return; } } }); diff --git a/app/controllers/mock.php b/app/controllers/mock.php index 712d4b7742..99713af430 100644 --- a/app/controllers/mock.php +++ b/app/controllers/mock.php @@ -244,36 +244,38 @@ Http::get('/v1/mock/github/callback') throw new Exception(Exception::PROJECT_NOT_FOUND, $error); } - if (!empty($providerInstallationId)) { - $privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); - $githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID'); - $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); - $owner = $github->getOwnerName($providerInstallationId) ?? ''; - - $projectInternalId = $project->getSequence(); - - $teamId = $project->getAttribute('teamId', ''); - - $installation = new Document([ - '$id' => ID::unique(), - '$permissions' => [ - Permission::read(Role::team(ID::custom($teamId))), - Permission::update(Role::team(ID::custom($teamId), 'owner')), - Permission::update(Role::team(ID::custom($teamId), 'developer')), - Permission::delete(Role::team(ID::custom($teamId), 'owner')), - Permission::delete(Role::team(ID::custom($teamId), 'developer')), - ], - 'providerInstallationId' => $providerInstallationId, - 'projectId' => $projectId, - 'projectInternalId' => $projectInternalId, - 'provider' => 'github', - 'organization' => $owner, - 'personal' => false - ]); - - $installation = $dbForPlatform->createDocument('installations', $installation); + if (empty($providerInstallationId)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Missing provider installation ID'); } + $privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY'); + $githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID'); + $github->initializeVariables($providerInstallationId, $privateKey, $githubAppId); + $owner = $github->getOwnerName($providerInstallationId) ?? ''; + + $projectInternalId = $project->getSequence(); + + $teamId = $project->getAttribute('teamId', ''); + + $installation = new Document([ + '$id' => ID::unique(), + '$permissions' => [ + Permission::read(Role::team(ID::custom($teamId))), + Permission::update(Role::team(ID::custom($teamId), 'owner')), + Permission::update(Role::team(ID::custom($teamId), 'developer')), + Permission::delete(Role::team(ID::custom($teamId), 'owner')), + Permission::delete(Role::team(ID::custom($teamId), 'developer')), + ], + 'providerInstallationId' => $providerInstallationId, + 'projectId' => $projectId, + 'projectInternalId' => $projectInternalId, + 'provider' => 'github', + 'organization' => $owner, + 'personal' => false + ]); + + $installation = $dbForPlatform->createDocument('installations', $installation); + $response->json([ 'installationId' => $installation->getId(), ]); diff --git a/app/http.php b/app/http.php index 1742bc7cdd..3eb8284ddf 100644 --- a/app/http.php +++ b/app/http.php @@ -3,6 +3,8 @@ require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/init/span.php'; +global $register; + use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Swoole\Constant; @@ -293,7 +295,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $tot go(function () use ($register, $app) { $pools = $register->get('pools'); - /** @var Group $pools */ + /** @var \Utopia\Pools\Group $pools */ Http::setResource('pools', fn () => $pools); /** @var array $collections */ @@ -655,7 +657,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register) { /** @var Utopia\Database\Database $dbForPlatform */ $dbForPlatform = $app->getResource('dbForPlatform'); - /** @var Table $riskyDomains */ + /** @var \Swoole\Table $riskyDomains */ $riskyDomains = $app->getResource('riskyDomains'); Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $riskyDomains, &$lastSyncUpdate, $app) { diff --git a/app/init/registers.php b/app/init/registers.php index 7c2f822fdd..88160aae79 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -56,7 +56,7 @@ $register->set('logger', function () { } try { - $loggingProvider = new DSN($providerConfig ?? ''); + $loggingProvider = new DSN($providerConfig); $providerName = $loggingProvider->getScheme(); $providerConfig = match ($providerName) { @@ -76,7 +76,7 @@ $register->set('logger', function () { }; } - if (empty($providerName) || empty($providerConfig)) { + if (empty($providerName)) { return; } @@ -121,7 +121,7 @@ $register->set('realtimeLogger', function () { default => ['key' => $loggingProvider->getHost()], }; - if (empty($providerName) || empty($providerConfig)) { + if (empty($providerName)) { return; } @@ -242,8 +242,8 @@ $register->set('pools', function () { ], ]; - $maxConnections = System::getEnv('_APP_CONNECTIONS_MAX', 151); - $instanceConnections = $maxConnections / System::getEnv('_APP_POOL_CLIENTS', 14); + $maxConnections = (int) System::getEnv('_APP_CONNECTIONS_MAX', 151); + $instanceConnections = $maxConnections / (int) System::getEnv('_APP_POOL_CLIENTS', 14); $multiprocessing = System::getEnv('_APP_SERVER_MULTIPROCESS', 'disabled') === 'enabled'; @@ -308,7 +308,7 @@ $register->set('pools', function () { ]); }); }, - 'mongodb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase, $dsn) { + 'mongodb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { try { $mongo = new MongoClient($dsnDatabase, $dsnHost, (int)$dsnPort, $dsnUser, $dsnPass, false); @$mongo->connect(); @@ -442,7 +442,7 @@ $register->set('smtp', function () { $mail->XMailer = 'Appwrite Mailer'; $mail->Host = System::getEnv('_APP_SMTP_HOST', 'smtp'); - $mail->Port = System::getEnv('_APP_SMTP_PORT', 25); + $mail->Port = (int) System::getEnv('_APP_SMTP_PORT', 25); $mail->SMTPAuth = !empty($username) && !empty($password); $mail->Username = $username; $mail->Password = $password; diff --git a/app/init/resources.php b/app/init/resources.php index 3481e73e0b..8acecb8e3e 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -696,7 +696,7 @@ Http::setResource('dbForProject', function (Group $pools, Database $dbForPlatfor $cacheKey = \sprintf( '%s-cache-%s:%s:%s:project:%s:functions:events', $dbForProject->getCacheName(), - $hostname ?? '', + $hostname, $dbForProject->getNamespace(), $dbForProject->getTenant(), $project->getId() diff --git a/app/realtime.php b/app/realtime.php index 1c453ce05b..67cfb19e2a 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -237,7 +237,6 @@ if (!function_exists('getTelemetry')) { if (!function_exists('triggerStats')) { function triggerStats(array $event, string $projectId): void { - return; } } @@ -320,14 +319,14 @@ if (!function_exists('logError')) { $server->error(logError(...)); -$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument) { +$server->onStart(function () use ($stats, $containerId, &$statsDocument) { sleep(5); // wait for the initial database schema to be ready Console::success('Server started successfully'); /** * Create document for this worker to share stats across Containers. */ - go(function () use ($register, $containerId, &$statsDocument) { + go(function () use ($containerId, &$statsDocument) { $attempts = 0; $database = getConsoleDB(); @@ -357,7 +356,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume */ // TODO: Remove this if check once it doesn't cause issues for cloud if (System::getEnv('_APP_EDITION', 'self-hosted') === 'self-hosted') { - Timer::tick(5000, function () use ($register, $stats, &$statsDocument) { + Timer::tick(5000, function () use ($stats, &$statsDocument) { $payload = []; foreach ($stats as $projectId => $value) { $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); @@ -396,7 +395,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $attempts = 0; $start = time(); - Timer::tick(5000, function () use ($server, $register, $realtime, $stats) { + Timer::tick(5000, function () use ($server, $realtime, $stats) { /** * Sending current connections to project channels on the console project every 5 seconds. */ @@ -798,7 +797,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, } }); -$server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) { +$server->onMessage(function (int $connection, string $message) use ($server, $realtime, $containerId) { $project = null; $authorization = null; @@ -810,7 +809,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re // Get authorization from connection (stored during onOpen) $authorization = $realtime->connections[$connection]['authorization'] ?? null; if ($authorization === null) { - $authorization = new Authorization(''); + $authorization = new Authorization(); } $database = getConsoleDB(); diff --git a/app/worker.php b/app/worker.php index 71446ee94f..4a0a4870e4 100644 --- a/app/worker.php +++ b/app/worker.php @@ -280,14 +280,14 @@ Server::setResource('abuseRetention', function () { Server::setResource('auditRetention', function (Document $project) { if ($project->getId() === 'console') { - return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE', 15778800)); // 6 months + return DateTime::addSeconds(new \DateTime(), -1 * (int) System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE', 15778800)); // 6 months } - return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600)); // 14 days + return DateTime::addSeconds(new \DateTime(), -1 * (int) System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600)); // 14 days }, ['project']); Server::setResource('executionRetention', function () { - return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600)); // 14 days + return DateTime::addSeconds(new \DateTime(), -1 * (int) System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600)); // 14 days }); Server::setResource('cache', function (Registry $register) { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index 8e9d8a5a38..0000000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,721 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^PHPDoc tag @var above a method has no effect\.$#' - identifier: varTag.misplaced - count: 1 - path: app/config/templates/function.php - - - - message: '#^Array has 2 duplicate keys with value ''outputDirectory'' \(''outputDirectory'', ''outputDirectory''\)\.$#' - identifier: array.duplicateKey - count: 3 - path: app/config/templates/site.php - - - - message: '#^PHPDoc tag @var above a method has no effect\.$#' - identifier: varTag.misplaced - count: 1 - path: app/config/templates/site.php - - - - message: '#^Result of method Appwrite\\Utopia\\Response\:\:dynamic\(\) \(void\) is used\.$#' - identifier: method.void - count: 2 - path: app/controllers/api/account.php - - - - message: '#^Result of method Utopia\\Http\\Response\:\:noContent\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: app/controllers/api/account.php - - - - message: '#^Variable \$session might not be defined\.$#' - identifier: variable.undefined - count: 3 - path: app/controllers/api/account.php - - - - message: '#^Variable \$output might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: app/controllers/api/locale.php - - - - message: '#^Variable \$currentScheduledAt on left side of \?\? is never defined\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/controllers/api/messaging.php - - - - message: '#^Result of method Utopia\\Http\\Response\:\:noContent\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: app/controllers/api/projects.php - - - - message: '#^Result of method Appwrite\\Utopia\\Response\:\:dynamic\(\) \(void\) is used\.$#' - identifier: method.void - count: 2 - path: app/controllers/api/users.php - - - - message: '#^Result of method Utopia\\Http\\Response\:\:noContent\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: app/controllers/api/users.php - - - - message: '#^Result of method Utopia\\Http\\Response\:\:redirect\(\) \(void\) is used\.$#' - identifier: method.void - count: 2 - path: app/controllers/general.php - - - - message: '#^Result of method Utopia\\Http\\Response\:\:send\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$body on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$deployment in PHPDoc tag @var does not exist\.$#' - identifier: varTag.variableNotFound - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$executionId on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$executionResponse might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$user might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: app/controllers/general.php - - - - message: '#^Variable \$installation might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: app/controllers/mock.php - - - - message: '#^Variable \$register might not be defined\.$#' - identifier: variable.undefined - count: 3 - path: app/http.php - - - - message: '#^Variable \$tag on left side of \?\? always exists and is always null\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/init/database/filters.php - - - - message: '#^Anonymous function has an unused use \$dsn\.$#' - identifier: closure.unusedUse - count: 1 - path: app/init/registers.php - - - - message: '#^Binary operation "/" between string and string results in an error\.$#' - identifier: binaryOp.invalid - count: 1 - path: app/init/registers.php - - - - message: '#^Property PHPMailer\\PHPMailer\\PHPMailer\:\:\$Port \(int\) does not accept string\.$#' - identifier: assign.propertyType - count: 1 - path: app/init/registers.php - - - - message: '#^Variable \$providerConfig in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 2 - path: app/init/registers.php - - - - message: '#^Variable \$providerConfig on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/init/registers.php - - - - message: '#^Variable \$hostname on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: app/init/resources.php - - - - message: '#^Anonymous function has an unused use \$register\.$#' - identifier: closure.unusedUse - count: 4 - path: app/realtime.php - - - - message: '#^Class Utopia\\Database\\Validator\\Authorization does not have a constructor and must be instantiated without any parameters\.$#' - identifier: new.noConstructor - count: 1 - path: app/realtime.php - - - - message: '#^Function triggerStats\(\) returns void but does not have any side effects\.$#' - identifier: void.pure - count: 1 - path: app/realtime.php - - - - message: '#^Binary operation "\*" between \-1 and string results in an error\.$#' - identifier: binaryOp.invalid - count: 3 - path: app/worker.php - - - - message: '#^Anonymous function has an unused use \$context\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/GraphQL/Resolvers.php - - - - message: '#^Anonymous function has an unused use \$info\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/GraphQL/Resolvers.php - - - - message: '#^Anonymous function has an unused use \$type\.$#' - identifier: closure.unusedUse - count: 5 - path: src/Appwrite/GraphQL/Resolvers.php - - - - message: '#^Variable \$request in PHPDoc tag @var does not exist\.$#' - identifier: varTag.variableNotFound - count: 1 - path: src/Appwrite/GraphQL/Resolvers.php - - - - message: '#^Variable \$response in PHPDoc tag @var does not exist\.$#' - identifier: varTag.variableNotFound - count: 1 - path: src/Appwrite/GraphQL/Resolvers.php - - - - message: '#^Method Appwrite\\Network\\Cors\:\:headers\(\) should return array\ but returns array\\.$#' - identifier: return.type - count: 5 - path: src/Appwrite/Network/Cors.php - - - - message: '#^Parameter &\$tag by\-ref type of method Appwrite\\OpenSSL\\OpenSSL\:\:encrypt\(\) expects null, string\|null given\.$#' - identifier: parameterByRef.type - count: 1 - path: src/Appwrite/OpenSSL/OpenSSL.php - - - - message: '#^Variable \$output in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Avatars/Http/Action.php - - - - message: '#^Variable \$output in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Avatars/Http/Favicon/Get.php - - - - message: '#^Variable \$output in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Avatars/Http/Image/Get.php - - - - message: '#^Binary operation "%%" between string and 5 results in an error\.$#' - identifier: binaryOp.invalid - count: 1 - path: src/Appwrite/Platform/Modules/Avatars/Http/Initials/Get.php - - - - message: '#^Method Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Action\:\:setHttpPath\(\) should return Appwrite\\Platform\\Action but returns Utopia\\Platform\\Action\.$#' - identifier: return.type - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php - - - - message: '#^Method Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Collections\\Documents\\Action\:\:setHttpPath\(\) should return Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Action but returns Appwrite\\Platform\\Action\.$#' - identifier: return.type - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php - - - - message: '#^Variable \$relations in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php - - - - message: '#^Anonymous function has an unused use \$dbForProject\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php - - - - message: '#^Variable \$document in PHPDoc tag @var does not match assigned variable \$collectionTableId\.$#' - identifier: varTag.differentVariable - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php - - - - message: '#^Variable \$hostname on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php - - - - message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php - - - - message: '#^Offset ''deviceBrand'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php - - - - message: '#^Offset ''deviceModel'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php - - - - message: '#^Offset ''deviceName'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php - - - - message: '#^Method Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Transactions\\Action\:\:setHttpPath\(\) should return Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Action but returns Appwrite\\Platform\\Action\.$#' - identifier: return.type - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php - - - - message: '#^Anonymous function has an unused use \$existing\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php - - - - message: '#^Anonymous function has an unused use \$queueForEvents\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^Anonymous function has an unused use \$queueForFunctions\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^Anonymous function has an unused use \$queueForRealtime\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^Anonymous function has an unused use \$queueForWebhooks\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^Anonymous function has an unused use \$usage\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^PHPDoc tag @throws with type Appwrite\\Platform\\Modules\\Databases\\Http\\Databases\\Transactions\\Structure\|Throwable\|Utopia\\Database\\Validator\\Authorization is not subtype of Throwable$#' - identifier: throws.notThrowable - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php - - - - message: '#^Offset ''deviceBrand'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php - - - - message: '#^Offset ''deviceModel'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php - - - - message: '#^Offset ''deviceName'' does not exist on int\.$#' - identifier: offsetAccess.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php - - - - message: '#^Call to method getAttribute\(\) on an unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#' - identifier: class.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Call to method getId\(\) on an unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#' - identifier: class.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Call to method isEmpty\(\) on an unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#' - identifier: class.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Method Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Create\:\:enqueueDeletes\(\) returns void but does not have any side effects\.$#' - identifier: void.pure - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^PHPDoc tag @var for variable \$session contains unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#' - identifier: class.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Result of method Appwrite\\Utopia\\Response\:\:dynamic\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Variable \$body on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Variable \$executionId on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Variable \$jwt on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php - - - - message: '#^Call to an undefined method Appwrite\\Event\\Event\:\:setSubscribers\(\)\.$#' - identifier: method.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php - - - - message: '#^Undefined variable\: \$cpus$#' - identifier: variable.undefined - count: 3 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Undefined variable\: \$memory$#' - identifier: variable.undefined - count: 3 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Variable \$deployment might not be defined\.$#' - identifier: variable.undefined - count: 4 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Variable \$logsAfter on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Variable \$logsBefore on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Variable \$providerCommitHash on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Variable \$rule in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php - - - - message: '#^Result of method Appwrite\\Utopia\\Response\:\:dynamic\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php - - - - message: '#^Variable \$iv might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php - - - - message: '#^Variable \$tag might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php - - - - message: '#^Caught class Appwrite\\Platform\\Modules\\Teams\\Http\\Memberships\\Throwable not found\.$#' - identifier: class.notFound - count: 1 - path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php - - - - message: '#^Variable \$email in empty\(\) always exists and is always falsy\.$#' - identifier: empty.variable - count: 1 - path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php - - - - message: '#^Variable \$hash might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php - - - - message: '#^Variable \$invitee might not be defined\.$#' - identifier: variable.undefined - count: 14 - path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php - - - - message: '#^Variable \$providerConfig on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Tasks/Doctor.php - - - - message: '#^Variable \$compose in isset\(\) always exists and is not nullable\.$#' - identifier: isset.variable - count: 1 - path: src/Appwrite/Platform/Tasks/Install.php - - - - message: '#^Variable \$prUrls might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Tasks/SDKs.php - - - - message: '#^Anonymous function has an unused use \$dbForPlatform\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Tasks/StatsResources.php - - - - message: '#^PHPDoc tag @param references unknown parameter\: \$getProjectDB$#' - identifier: parameter.notFound - count: 1 - path: src/Appwrite/Platform/Workers/Audits.php - - - - message: '#^Anonymous function has an unused use \$certificates\.$#' - identifier: closure.unusedUse - count: 2 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^Anonymous function has an unused use \$dbForPlatform\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^Anonymous function has an unused use \$dbForProject\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^Anonymous function has an unused use \$project\.$#' - identifier: closure.unusedUse - count: 6 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^Anonymous function has an unused use \$resourceType\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @param references unknown parameter\: \$build$#' - identifier: parameter.notFound - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @param references unknown parameter\: \$dbForPlatform$#' - identifier: parameter.notFound - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @param references unknown parameter\: \$target$#' - identifier: parameter.notFound - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @throws with type Appwrite\\Extend\\Exception\|Utopia\\Database\\Exception\|Utopia\\Database\\Validator\\Authorization is not subtype of Throwable$#' - identifier: throws.notThrowable - count: 2 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @throws with type Appwrite\\Extend\\Exception\|Utopia\\Database\\Validator\\Authorization is not subtype of Throwable$#' - identifier: throws.notThrowable - count: 1 - path: src/Appwrite/Platform/Workers/Deletes.php - - - - message: '#^PHPDoc tag @throws with type Appwrite\\Platform\\Workers\\Exception is not subtype of Throwable$#' - identifier: throws.notThrowable - count: 2 - path: src/Appwrite/Platform/Workers/Functions.php - - - - message: '#^Variable \$body on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 2 - path: src/Appwrite/Platform/Workers/Functions.php - - - - message: '#^Variable \$errorCode might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Workers/Functions.php - - - - message: '#^Variable \$executionId on left side of \?\? always exists and is not nullable\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Workers/Functions.php - - - - message: '#^Binary operation "\+\=" between 0 and array\\|int\|string\>\|int\|string results in an error\.$#' - identifier: assignOp.invalid - count: 1 - path: src/Appwrite/Platform/Workers/Messaging.php - - - - message: '#^Variable \$provider might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Workers/Messaging.php - - - - message: '#^Variable \$aggregatedResources might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: src/Appwrite/Platform/Workers/Migrations.php - - - - message: '#^Anonymous function has an unused use \$dbForLogs\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Workers/StatsResources.php - - - - message: '#^Anonymous function has an unused use \$sequence\.$#' - identifier: closure.unusedUse - count: 1 - path: src/Appwrite/Platform/Workers/StatsUsage.php - - - - message: '#^Callable callable\(\)\: Utopia\\Database\\Database invoked with 1 parameter, 0 required\.$#' - identifier: arguments.count - count: 2 - path: src/Appwrite/Platform/Workers/StatsUsage.php - - - - message: '#^Variable \$curlError on left side of \?\? is never defined\.$#' - identifier: nullCoalesce.variable - count: 1 - path: src/Appwrite/Platform/Workers/Webhooks.php - - - - message: '#^Unsafe usage of new static\(\)\.$#' - identifier: new.static - count: 3 - path: src/Appwrite/Promises/Promise.php - - - - message: '#^Property Appwrite\\SDK\\Method\:\:\$hide on left side of \?\? is not nullable nor uninitialized\.$#' - identifier: nullCoalesce.initializedProperty - count: 1 - path: src/Appwrite/SDK/Method.php - - - - message: '#^PHPDoc tag @param has invalid value \(Document \$this\)\: Unexpected token "\$this", expected variable at offset 69 on line 4$#' - identifier: phpDoc.parseError - count: 1 - path: src/Appwrite/Utopia/Database/Documents/User.php - - - - message: '#^PHPDoc tag @param references unknown parameter\: \$sessions$#' - identifier: parameter.notFound - count: 1 - path: src/Appwrite/Utopia/Database/Documents/User.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: '#^Binary operation "\+" between string and 1 results in an error\.$#' - identifier: binaryOp.invalid - count: 1 - path: tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php - - - - message: '#^Call to an undefined method Utopia\\Queue\\Publisher\:\:getEvents\(\)\.$#' - identifier: method.notFound - count: 1 - path: tests/unit/Event/EventTest.php diff --git a/phpstan.neon b/phpstan.neon index 25fe377ecf..85d18fd44d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,3 @@ -includes: - - phpstan-baseline.neon - parameters: level: 3 tmpDir: .phpstan-cache @@ -15,4 +12,3 @@ parameters: - vendor/swoole/ide-helper excludePaths: - tests/resources - diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index bf6339f8a0..ae75e3924f 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -285,7 +285,7 @@ class Event * * @param string $key * @param Document $context - * @return self + * @return static */ public function setContext(string $key, Document $context): self { @@ -309,7 +309,7 @@ class Event /** * Set class used for this event. * @param string $class - * @return self + * @return static */ public function setClass(string $class): self { @@ -648,10 +648,8 @@ class Event * * @param Event $event * - * @return self - * */ - public function from(Event $event): self + public function from(Event $event): static { $this->project = $event->getProject(); $this->user = $event->getUser(); diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index 484cafb0ab..e422bcbf96 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -25,11 +25,7 @@ class Resolvers ?Route $route, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $route, $args, $context, $info) { - /** @var Http $utopia */ - /** @var Response $response */ - /** @var Request $request */ - + function (callable $resolve, callable $reject) use ($utopia, $route, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -96,7 +92,7 @@ class Resolvers callable $url, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -127,7 +123,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -163,7 +159,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -195,7 +191,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -225,7 +221,7 @@ class Resolvers callable $url, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); diff --git a/src/Appwrite/Network/Cors.php b/src/Appwrite/Network/Cors.php index 9fc47c5808..e21c660a32 100644 --- a/src/Appwrite/Network/Cors.php +++ b/src/Appwrite/Network/Cors.php @@ -57,7 +57,7 @@ final class Cors self::HEADER_ALLOW_HEADERS => implode(', ', $this->allowedHeaders), self::HEADER_EXPOSE_HEADERS => implode(', ', $this->exposedHeaders), self::HEADER_ALLOW_CREDENTIALS => $this->allowCredentials ? 'true' : 'false', - self::HEADER_MAX_AGE => $this->maxAge, + self::HEADER_MAX_AGE => (string) $this->maxAge, ]; // Wildcard allow-all diff --git a/src/Appwrite/OpenSSL/OpenSSL.php b/src/Appwrite/OpenSSL/OpenSSL.php index 1965a3c858..787feb0904 100644 --- a/src/Appwrite/OpenSSL/OpenSSL.php +++ b/src/Appwrite/OpenSSL/OpenSSL.php @@ -18,7 +18,7 @@ class OpenSSL * * @return string */ - public static function encrypt($data, $method, $key, $options = 0, $iv = '', &$tag = null, $aad = '', $tag_length = 16) + public static function encrypt($data, $method, $key, $options = 0, $iv = '', ?string &$tag = null, $aad = '', $tag_length = 16) { return \openssl_encrypt($data, $method, $key, $options, $iv, $tag, $aad, $tag_length); } diff --git a/src/Appwrite/Platform/Modules/Avatars/Http/Action.php b/src/Appwrite/Platform/Modules/Avatars/Http/Action.php index bf7d01764f..d6b58b33dd 100644 --- a/src/Appwrite/Platform/Modules/Avatars/Http/Action.php +++ b/src/Appwrite/Platform/Modules/Avatars/Http/Action.php @@ -49,7 +49,6 @@ class Action extends PlatformAction $image = new Image(\file_get_contents($path)); $image->crop((int) $width, (int) $height); - $output = (empty($output)) ? $type : $output; $data = $image->output($output, $quality); $response ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days diff --git a/src/Appwrite/Platform/Modules/Avatars/Http/Favicon/Get.php b/src/Appwrite/Platform/Modules/Avatars/Http/Favicon/Get.php index 0a4d652d0e..b6cc408dde 100644 --- a/src/Appwrite/Platform/Modules/Avatars/Http/Favicon/Get.php +++ b/src/Appwrite/Platform/Modules/Avatars/Http/Favicon/Get.php @@ -204,7 +204,6 @@ class Get extends Action $image = new Image($data); $image->crop((int) $width, (int) $height); - $output = (empty($output)) ? $type : $output; $data = $image->output($output, $quality); $response diff --git a/src/Appwrite/Platform/Modules/Avatars/Http/Image/Get.php b/src/Appwrite/Platform/Modules/Avatars/Http/Image/Get.php index eb56ddf0b2..77ff9dd8ce 100644 --- a/src/Appwrite/Platform/Modules/Avatars/Http/Image/Get.php +++ b/src/Appwrite/Platform/Modules/Avatars/Http/Image/Get.php @@ -95,7 +95,6 @@ class Get extends Action } $image->crop((int) $width, (int) $height); - $output = (empty($output)) ? $type : $output; $data = $image->output($output, $quality); $response diff --git a/src/Appwrite/Platform/Modules/Avatars/Http/Initials/Get.php b/src/Appwrite/Platform/Modules/Avatars/Http/Initials/Get.php index 8278a43ea3..c73d20fb0c 100644 --- a/src/Appwrite/Platform/Modules/Avatars/Http/Initials/Get.php +++ b/src/Appwrite/Platform/Modules/Avatars/Http/Initials/Get.php @@ -90,7 +90,7 @@ class Get extends Action } } - $rand = \substr($code, -1); + $rand = (int) \substr((string) $code, -1); $rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php index b2417871ed..60449aeab6 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Action.php @@ -17,7 +17,7 @@ class Action extends AppwriteAction return $this->context; } - public function setHttpPath(string $path): AppwriteAction + public function setHttpPath(string $path): self { if (\str_contains($path, '/tablesdb')) { $this->context = DATABASE_TYPE_TABLESDB; @@ -28,7 +28,8 @@ class Action extends AppwriteAction if (\str_contains($path, '/vectorsdb')) { $this->context = DATABASE_TYPE_VECTORSDB; } - return parent::setHttpPath($path); + parent::setHttpPath($path); + return $this; } /** diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php index 0bd4a2e080..91dd9c603c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php @@ -24,7 +24,7 @@ abstract class Action extends DatabasesAction */ abstract protected function getResponseModel(): string; - public function setHttpPath(string $path): DatabasesAction + public function setHttpPath(string $path): self { if (str_contains($path, '/tablesdb/')) { $this->context = ROWS; @@ -47,7 +47,8 @@ abstract class Action extends DatabasesAction ], ]; - return parent::setHttpPath($path); + parent::setHttpPath($path); + return $this; } protected function getDatabasesOperationReadMetric(): string @@ -406,8 +407,6 @@ abstract class Action extends DatabasesAction if (\is_array($related)) { $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); - } elseif (empty($relations)) { - $document->setAttribute($relationship->getAttribute('key'), null); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php index 7f2e895228..38c84c4ae1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php @@ -209,7 +209,7 @@ class Create extends Action throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Bulk create is not supported for ' . $this->getSDKNamespace() . ' with relationship ' . $this->getStructureContext()); } - $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject, $authorization) { + $setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $authorization) { $allowedPermissions = [ Database::PERMISSION_READ, Database::PERMISSION_UPDATE, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php index 27ccaafc71..b86d934ffb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php @@ -122,7 +122,6 @@ class Update extends Action $dbForDatabases = $getDatabasesDB($database); // Read permission should not be required for update - /** @var Document $document */ $collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(); if ($transactionId !== null) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php index 744a4fd922..b3046fe22d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/XList.php @@ -147,7 +147,7 @@ class XList extends Action $cacheKeyBase = \sprintf( '%s-cache-%s:%s:%s:collection:%s:%s:user:%s:%s', $dbForProject->getCacheName(), - $hostname ?? '', + $hostname, $dbForProject->getNamespace(), $dbForProject->getTenant(), $collectionId, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php index 5d9d425d71..1142f38aa9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Update.php @@ -99,8 +99,6 @@ class Update extends Action // Map aggregate permissions into the multiple permissions they represent. $permissions = Permission::aggregate($permissions); - $enabled ??= $collection->getAttribute('enabled', true); - $collection = $dbForProject->updateDocument( 'database_' . $database->getSequence(), $collectionId, diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php index 0c0f5f1273..4763a1611d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Logs/XList.php @@ -103,6 +103,9 @@ class XList extends Action $os = $detector->getOS(); $client = $detector->getClient(); $device = $detector->getDevice(); + $deviceName = \is_array($device) ? ($device['deviceName'] ?? '') : ''; + $deviceBrand = \is_array($device) ? ($device['deviceBrand'] ?? '') : ''; + $deviceModel = \is_array($device) ? ($device['deviceModel'] ?? '') : ''; $output[$i] = new Document([ 'event' => $log['event'], @@ -121,9 +124,9 @@ class XList extends Action 'clientVersion' => $client['clientVersion'], 'clientEngine' => $client['clientEngine'], 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceName' => $device['deviceName'], - 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceName' => $deviceName, + 'deviceBrand' => $deviceBrand, + 'deviceModel' => $deviceModel, ]); $record = $geodb->get($log['ip']); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php index f3edf010d4..91bc1a3ccf 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Action.php @@ -33,7 +33,7 @@ abstract class Action extends DatabasesAction return $this->databaseType.'.'.METRIC_DATABASE_ID_OPERATIONS_WRITES; } - public function setHttpPath(string $path): DatabasesAction + public function setHttpPath(string $path): self { switch (true) { case str_contains($path, '/tablesdb'): @@ -50,7 +50,8 @@ abstract class Action extends DatabasesAction $this->databaseType = VECTORSDB; break; } - return parent::setHttpPath($path); + parent::setHttpPath($path); + return $this; } /** diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php index 30c9b7cb30..f06feccdee 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Operations/Create.php @@ -239,7 +239,7 @@ class Create extends Action } } - $transaction = $authorization->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { + $transaction = $authorization->skip(fn () => $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $operations) { $dbForProject->createDocuments('transactionLogs', $staged); return $dbForProject->increaseDocumentAttribute( 'transactions', diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php index a5d96d5768..0c8c6a8520 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Transactions/Update.php @@ -105,8 +105,7 @@ class Update extends Action * @throws Exception * @throws \Throwable * @throws \Utopia\Database\Exception - * @throws Authorization - * @throws Structure + * @throws StructureException * @throws \Utopia\Http\Exception */ public function action(string $transactionId, bool $commit, bool $rollback, Document $project, UtopiaResponse $response, Database $dbForProject, callable $getDatabasesDB, User $user, TransactionState $transactionState, Delete $queueForDeletes, Event $queueForEvents, Context $usage, Event $queueForRealtime, Event $queueForFunctions, Event $queueForWebhooks, Authorization $authorization, EventProcessor $eventProcessor): void @@ -183,7 +182,7 @@ class Update extends Action $dbForDatabases = $getDatabasesDB($databaseDoc); try { - $dbForDatabases->withTransaction(function () use ($dbForDatabases, $dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, &$currentDocumentId, $queueForEvents, $usage, $queueForRealtime, $queueForFunctions, $queueForWebhooks, $authorization) { + $dbForDatabases->withTransaction(function () use ($dbForDatabases, $dbForProject, $transactionState, $queueForDeletes, $transactionId, &$transaction, &$operations, &$totalOperations, &$databaseOperations, &$currentDocumentId, $authorization) { $authorization->skip(fn () => $dbForProject->updateDocument('transactions', $transactionId, new Document([ 'status' => 'committing', ]))); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php index 6754179425..23541db146 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php @@ -97,6 +97,9 @@ class XList extends Action $os = $detector->getOS(); $client = $detector->getClient(); $device = $detector->getDevice(); + $deviceName = \is_array($device) ? ($device['deviceName'] ?? '') : ''; + $deviceBrand = \is_array($device) ? ($device['deviceBrand'] ?? '') : ''; + $deviceModel = \is_array($device) ? ($device['deviceModel'] ?? '') : ''; $output[$i] = new Document([ 'event' => $log['event'], @@ -115,9 +118,9 @@ class XList extends Action 'clientVersion' => $client['clientVersion'], 'clientEngine' => $client['clientEngine'], 'clientEngineVersion' => $client['clientEngineVersion'], - 'deviceName' => $device['deviceName'], - 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'], + 'deviceName' => $deviceName, + 'deviceBrand' => $deviceBrand, + 'deviceModel' => $deviceModel, ]); $record = $geodb->get($log['ip']); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index c6d25a15fc..37292ce984 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -213,7 +213,10 @@ class Create extends Base $current = new Document(); foreach ($sessions as $session) { - /** @var Utopia\Database\Document $session */ + if (!$session instanceof Document) { + continue; + } + if ($proofForToken->verify($store->getProperty('secret', ''), $session->getAttribute('secret'))) { // Find most recent active session for user ID and JWT headers $current = $session; } @@ -237,11 +240,11 @@ class Create extends Base ]); $executionId = ID::unique(); - $headers['x-appwrite-execution-id'] = $executionId ?? ''; + $headers['x-appwrite-execution-id'] = $executionId; $headers['x-appwrite-key'] = API_KEY_DYNAMIC . '_' . $apiKey; $headers['x-appwrite-trigger'] = 'http'; - $headers['x-appwrite-user-id'] = $user->getId() ?? ''; - $headers['x-appwrite-user-jwt'] = $jwt ?? ''; + $headers['x-appwrite-user-id'] = $user->getId(); + $headers['x-appwrite-user-jwt'] = $jwt; $headers['x-appwrite-country-code'] = ''; $headers['x-appwrite-continent-code'] = ''; $headers['x-appwrite-continent-eu'] = 'false'; @@ -350,16 +353,18 @@ class Create extends Base } } - $this->enqueueDeletes( - $project, - $function->getSequence(), - $executionsRetentionCount, + if ($executionsRetentionCount > 0 && ENABLE_EXECUTIONS_LIMIT_ON_ROUTE) { $queueForDeletes - ); + ->setProject($project) + ->setResource($function->getSequence()) + ->setResourceType(RESOURCE_TYPE_FUNCTIONS) + ->setType(DELETE_TYPE_EXECUTIONS_LIMIT) + ->trigger(); + } - return $response - ->setStatusCode(Response::STATUS_CODE_ACCEPTED) - ->dynamic($execution, Response::MODEL_EXECUTION); + $response->setStatusCode(Response::STATUS_CODE_ACCEPTED); + $response->dynamic($execution, Response::MODEL_EXECUTION); + return; } $durationStart = \microtime(true); @@ -370,7 +375,7 @@ class Create extends Base if ($version === 'v2') { $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_DATA' => $body ?? '', + 'APPWRITE_FUNCTION_DATA' => $body, 'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '', 'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? '' ]); @@ -537,32 +542,18 @@ class Create extends Base } } - $this->enqueueDeletes( - $project, - $function->getSequence(), - $executionsRetentionCount, + if ($executionsRetentionCount > 0 && ENABLE_EXECUTIONS_LIMIT_ON_ROUTE) { $queueForDeletes - ); + ->setProject($project) + ->setResource($function->getSequence()) + ->setResourceType(RESOURCE_TYPE_FUNCTIONS) + ->setType(DELETE_TYPE_EXECUTIONS_LIMIT) + ->trigger(); + } $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($execution, Response::MODEL_EXECUTION); } - private function enqueueDeletes( - Document $project, - string $resourceId, - int $executionsRetentionCount, - DeleteEvent $queueForDeletes - ): void { - /* cleanup */ - if ($executionsRetentionCount > 0 && ENABLE_EXECUTIONS_LIMIT_ON_ROUTE) { - $queueForDeletes - ->setProject($project) - ->setResource($resourceId) - ->setResourceType(RESOURCE_TYPE_FUNCTIONS) - ->setType(DELETE_TYPE_EXECUTIONS_LIMIT) - ->trigger(); - } - } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index d281c64414..8d4ad5d403 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -424,8 +424,8 @@ class Create extends Base /** Trigger Realtime Events */ $queueForRealtime - ->from($ruleCreate) ->setSubscribers(['console', $project->getId()]) + ->from($ruleCreate) ->trigger(); } } diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index bcedeee764..c6c4a0b38c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -450,7 +450,7 @@ class Builds extends Action $providerCommitHash = \trim($stdout); - $deployment->setAttribute('providerCommitHash', $providerCommitHash ?? ''); + $deployment->setAttribute('providerCommitHash', $providerCommitHash); $deployment->setAttribute('providerCommitAuthorUrl', APP_VCS_GITHUB_URL); $deployment->setAttribute('providerCommitAuthor', APP_VCS_GITHUB_USERNAME); $deployment->setAttribute('providerCommitMessage', "Create '" . $resource->getAttribute('name', '') . "' function"); @@ -862,7 +862,7 @@ class Builds extends Action if (\str_contains($logs, '{APPWRITE_DETECTION_SEPARATOR_START}')) { [$logsBefore, $detectionLogsStart] = \explode('{APPWRITE_DETECTION_SEPARATOR_START}', $logs, 2); [$detectionLogs, $logsAfter] = \explode('{APPWRITE_DETECTION_SEPARATOR_END}', $detectionLogsStart, 2); - $logs = ($logsBefore ?? '') . ($logsAfter ?? ''); + $logs = $logsBefore . $logsAfter; } $deployment->setAttribute('buildLogs', $logs); @@ -1203,6 +1203,8 @@ class Builds extends Action protected function sendUsage(Document $resource, Document $deployment, Document $project, Context $usage, UsagePublisher $publisherForUsage): void { $spec = Config::getParam('specifications')[$resource->getAttribute('buildSpecification', APP_COMPUTE_SPECIFICATION_DEFAULT)]; + $cpus = (int) ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT); + $memory = (int) ($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT); switch ($deployment->getAttribute('status')) { case 'ready': @@ -1364,6 +1366,8 @@ class Builds extends Action Realtime $queueForRealtime, array $platform ): void { + $deployment = new Document(); + try { if ($resource->getAttribute('providerSilentMode', false) === true) { return; @@ -1444,7 +1448,7 @@ class Builds extends Action $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $previewUrl = match ($resource->getCollection()) { 'functions' => '', - 'sites' => ! empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '', + 'sites' => !$rule->isEmpty() ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '', default => throw new \Exception('Invalid resource type') }; diff --git a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php index fb83cb34c5..8a0d341132 100644 --- a/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php +++ b/src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php @@ -83,7 +83,8 @@ class Update extends Action // If rule is already verified or in certificate generation state, don't queue for verification again if ($rule->getAttribute('status') === RULE_STATUS_VERIFIED || $rule->getAttribute('status') === RULE_STATUS_CERTIFICATE_GENERATING) { - return $response->dynamic($rule, Response::MODEL_PROXY_RULE); + $response->dynamic($rule, Response::MODEL_PROXY_RULE); + return; } try { diff --git a/src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php b/src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php index c67601dae9..c5f4f3dccd 100644 --- a/src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php +++ b/src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php @@ -286,6 +286,8 @@ class Create extends Action $mimeType = $deviceForFiles->getFileMimeType($path); // Get mime-type before compression and encryption $fileHash = $deviceForFiles->getFileHash($path); // Get file hash before compression and encryption $data = ''; + $iv = ''; + $tag = null; // Compression $algorithm = $bucket->getAttribute('compression', Compression::NONE); if ($fileSize <= APP_STORAGE_READ_BUFFER && $algorithm != Compression::NONE) { diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php b/src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php index 777184f2f2..4a3dbee5c9 100644 --- a/src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php +++ b/src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php @@ -37,6 +37,7 @@ use Utopia\Platform\Scope\HTTP; use Utopia\System\System; use Utopia\Validator\ArrayList; use Utopia\Validator\Text; +use Throwable; class Create extends Action { @@ -102,6 +103,8 @@ class Create extends Action { $isAppUser = $user->isApp($authorization->getRoles()); $isPrivilegedUser = $user->isPrivileged($authorization->getRoles()); + $invitee = new Document(); + $hash = ''; if (empty($url)) { if (! $isAppUser && ! $isPrivilegedUser) { @@ -145,9 +148,6 @@ class Create extends Action } } elseif (! empty($phone)) { $invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if (! $invitee->isEmpty() && ! empty($email) && $invitee->getAttribute('email', '') !== $email) { - throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409); - } } if ($invitee->isEmpty()) { // Create new user if no user with same email found diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 9a9c2fdf73..67b6eb4462 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -124,7 +124,7 @@ class Doctor extends Action $providerConfig = System::getEnv('_APP_LOGGING_CONFIG', ''); try { - $loggingProvider = new DSN($providerConfig ?? ''); + $loggingProvider = new DSN($providerConfig); $providerName = $loggingProvider->getScheme(); diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index 79a052b34a..dd7bed0137 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -227,7 +227,7 @@ class Install extends Action // Fall back to CLI mode $enableAssistant = false; $assistantExistsInOldCompose = false; - if ($existingInstallation && isset($compose)) { + if ($existingInstallation) { try { $assistantService = $compose->getService('appwrite-assistant'); $assistantExistsInOldCompose = $assistantService !== null; diff --git a/src/Appwrite/Platform/Tasks/SDKs.php b/src/Appwrite/Platform/Tasks/SDKs.php index a36959af33..e8a69afddb 100644 --- a/src/Appwrite/Platform/Tasks/SDKs.php +++ b/src/Appwrite/Platform/Tasks/SDKs.php @@ -566,6 +566,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $repoBranch = $language['repoBranch'] ?? 'main'; if ($git && !empty($gitUrl)) { + $prUrls = []; + // Generate commit message: use provided message, AI changelog, or fallback if (! empty($message)) { $commitMessage = $message; diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index 6c0e8da48b..220e377619 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -60,7 +60,7 @@ class StatsResources extends Action $interval = (int) System::getEnv('_APP_STATS_RESOURCES_INTERVAL', '3600'); - Console::loop(function () use ($queueForStatsResources, $dbForPlatform) { + Console::loop(function () use ($queueForStatsResources) { $last24Hours = (new \DateTime())->sub(\DateInterval::createFromDateString('24 hours')); /** diff --git a/src/Appwrite/Platform/Workers/Audits.php b/src/Appwrite/Platform/Workers/Audits.php index 55ec39026b..9588c1a9d3 100644 --- a/src/Appwrite/Platform/Workers/Audits.php +++ b/src/Appwrite/Platform/Workers/Audits.php @@ -51,13 +51,11 @@ class Audits extends Action /** * @param Message $message - * @param callable $getProjectDB * @param Document $project - * @param callable $getAudit + * @param callable(Document): \Utopia\Audit\Audit $getAudit * @return Commit|NoCommit * @throws Throwable * @throws \Utopia\Database\Exception - * @throws Authorization * @throws Structure */ public function action(Message $message, Document $project, callable $getAudit): Commit|NoCommit diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 716969e67a..a4faa64462 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -363,7 +363,6 @@ class Deletes extends Action /** * @param Document $project * @param callable $getProjectDB - * @param Document $target * @return void * @throws Exception */ @@ -438,7 +437,6 @@ class Deletes extends Action * @param string $resource * @param string|null $resourceType * @return void - * @throws Authorization * @throws Exception */ private function deleteCacheByResource(Document $project, callable $getProjectDB, string $resource, ?string $resourceType = null): void @@ -518,7 +516,6 @@ class Deletes extends Action } /** - * @param Database $dbForPlatform * @param callable $getProjectDB * @param string $hourlyUsageRetentionDatetime * @return void @@ -586,7 +583,6 @@ class Deletes extends Action * @param Database $dbForPlatform * @param Document $document * @return void - * @throws Authorization * @throws DatabaseException * @throws Conflict * @throws Restricted @@ -623,7 +619,6 @@ class Deletes extends Action * @param Document $document * @return void * @throws Exception - * @throws Authorization * @throws DatabaseException */ protected function deleteProject(Database $dbForPlatform, callable $getProjectDB, callable $getDatabasesDB, Device $deviceForFiles, Device $deviceForSites, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, Document $document): void @@ -952,7 +947,7 @@ class Deletes extends Action // fast path, no need to list anything! $delete($dbForProject, $resourceInternalId, $resourceType); } else { - $processResource = function (string $type) use ($dbForProject, $delete, $resourceType) { + $processResource = function (string $type) use ($dbForProject, $delete) { $this->listByGroup( collection: $type, queries: [Query::select(['$id', '$sequence'])], @@ -1109,7 +1104,7 @@ class Deletes extends Action Query::equal('resourceInternalId', [$siteInternalId]), Query::equal('resourceType', ['sites']), Query::orderAsc() - ], $dbForProject, function (Document $document) use ($project, $certificates, $deviceForSites, $deviceForBuilds, $deviceForFiles, $dbForPlatform, &$deploymentInternalIds) { + ], $dbForProject, function (Document $document) use ($deviceForSites, $deviceForBuilds, $deviceForFiles, $dbForPlatform, &$deploymentInternalIds, &$deploymentIds) { $deploymentInternalIds[] = $document->getSequence(); $deploymentIds[] = $document->getId(); $this->deleteBuildFiles($deviceForBuilds, $document); @@ -1172,7 +1167,7 @@ class Deletes extends Action Query::equal('deploymentResourceInternalId', [$functionInternalId]), Query::equal('projectInternalId', [$project->getSequence()]), Query::orderAsc() - ], $dbForPlatform, function (Document $document) use ($project, $dbForPlatform, $certificates) { + ], $dbForPlatform, function (Document $document) use ($dbForPlatform, $certificates) { $this->deleteRule($dbForPlatform, $document, $certificates); }); @@ -1196,7 +1191,7 @@ class Deletes extends Action Query::equal('resourceInternalId', [$functionInternalId]), Query::equal('resourceType', ['functions']), Query::orderAsc() - ], $dbForProject, function (Document $document) use ($dbForPlatform, $project, $certificates, $deviceForFunctions, $deviceForBuilds, &$deploymentInternalIds) { + ], $dbForProject, function (Document $document) use ($deviceForFunctions, $deviceForBuilds, &$deploymentInternalIds) { $deploymentInternalIds[] = $document->getSequence(); $this->deleteDeploymentFiles($deviceForFunctions, $document); $this->deleteBuildFiles($deviceForBuilds, $document); @@ -1321,7 +1316,7 @@ class Deletes extends Action /** * @param Device $device - * @param Document $build + * @param Document $deployment * @return void */ private function deleteBuildFiles(Device $device, Document $deployment): void @@ -1631,9 +1626,9 @@ class Deletes extends Action try { $dbForProject->deleteDocuments('transactions', [ Query::lessThan('expiresAt', DateTime::format(new \DateTime())), - ], onNext: function (Document $transaction) use ($dbForProject, $project, &$transactionInternalIds) { + ], onNext: function (Document $transaction) use (&$transactionInternalIds) { $transactionInternalIds[] = $transaction->getSequence(); - }, onError: function (Throwable $th) use ($project) { + }, onError: function (Throwable $th) { // Swallow errors to avoid breaking the cleanup process }); } catch (Throwable $th) { @@ -1646,7 +1641,7 @@ class Deletes extends Action $dbForProject->deleteDocuments('transactionLogs', [ Query::equal('transactionInternalId', $transactionInternalIds), - ], onError: function (Throwable $th) use ($project) { + ], onError: function (Throwable $th) { // Swallow errors to avoid breaking the cleanup process }); } diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index 3f19abdf22..bed28dad1c 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -33,7 +33,7 @@ class Functions extends Action } /** - * @throws Exception + * @throws \Exception */ public function __construct() { @@ -256,7 +256,7 @@ class Functions extends Action * @param Document $user * @param string|null $jwt * @param string|null $event - * @throws Exception + * @throws \Exception */ private function fail( string $message, @@ -271,10 +271,10 @@ class Functions extends Action ?string $event = null, ): void { $executionId = ID::unique(); - $headers['x-appwrite-execution-id'] = $executionId ?? ''; + $headers['x-appwrite-execution-id'] = $executionId; $headers['x-appwrite-trigger'] = $trigger; $headers['x-appwrite-event'] = $event ?? ''; - $headers['x-appwrite-user-id'] = $user->getId() ?? ''; + $headers['x-appwrite-user-id'] = $user->getId(); $headers['x-appwrite-user-jwt'] = $jwt ?? ''; $headersFiltered = []; @@ -458,8 +458,8 @@ class Functions extends Action if ($version === 'v2') { $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_DATA' => $body ?? '', - 'APPWRITE_FUNCTION_EVENT_DATA' => $body ?? '', + 'APPWRITE_FUNCTION_DATA' => $body, + 'APPWRITE_FUNCTION_EVENT_DATA' => $body, 'APPWRITE_FUNCTION_EVENT' => $headers['x-appwrite-event'] ?? '', 'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '', 'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? '' @@ -508,6 +508,9 @@ class Functions extends Action ]); /** Execute function */ + $error = null; + $errorCode = 0; + try { $version = $function->getAttribute('version', 'v2'); $command = $runtime['startCommand']; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index af7d2027e3..ff5eb2417a 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -285,7 +285,7 @@ class Messaging extends Action try { $response = $adapter->send($data); - $deliveredTotal += $response['deliveredTo']; + $deliveredTotal += (int) $response['deliveredTo']; foreach ($response['results'] as $result) { if ($result['status'] === 'failure') { $deliveryErrors[] = "Failed sending to target {$result['recipient']} with error: {$result['error']}"; @@ -380,7 +380,7 @@ class Messaging extends Action ])); // Delete any attachments that were downloaded to local storage - if ($provider->getAttribute('type') === MESSAGE_TYPE_EMAIL) { + if ($providerType === MESSAGE_TYPE_EMAIL) { if ($deviceForFiles->getType() === Storage::DEVICE_LOCAL) { return; } diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index 1080ff066f..6a7f52cb37 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -550,6 +550,8 @@ class Migrations extends Action $destination?->error(); } + $aggregatedResources = []; + if ($migration->getAttribute('status', '') === 'completed') { foreach ($aggregatedResources as $resource) { $this->processMigrationResourceStats( diff --git a/src/Appwrite/Platform/Workers/StatsResources.php b/src/Appwrite/Platform/Workers/StatsResources.php index 0e7a9bb0a7..b2823d3722 100644 --- a/src/Appwrite/Platform/Workers/StatsResources.php +++ b/src/Appwrite/Platform/Workers/StatsResources.php @@ -208,7 +208,7 @@ class StatsResources extends Action { $totalFiles = 0; $totalStorage = 0; - $this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $dbForLogs, $region, &$totalFiles, &$totalStorage) { + $this->foreachDocument($dbForProject, 'buckets', [], function ($bucket) use ($dbForProject, $region, &$totalFiles, &$totalStorage) { try { $files = $dbForProject->count('bucket_' . $bucket->getSequence()); } catch (Throwable $th) { diff --git a/src/Appwrite/Platform/Workers/StatsUsage.php b/src/Appwrite/Platform/Workers/StatsUsage.php index 1e0a2eabba..144c429629 100644 --- a/src/Appwrite/Platform/Workers/StatsUsage.php +++ b/src/Appwrite/Platform/Workers/StatsUsage.php @@ -140,7 +140,7 @@ class StatsUsage extends Action /** * @param Message $message - * @param callable(): Database $getProjectDB + * @param callable(Document): Database $getProjectDB * @param callable(): Database $getLogsDB * @param Registry $register * @return void @@ -212,7 +212,7 @@ class StatsUsage extends Action * @param Document $project * @param Document $document * @param array $metrics - * @param callable(): Database $getProjectDB + * @param callable(Document): Database $getProjectDB * @param string $databaseType Database type from context * @return void */ @@ -394,7 +394,7 @@ class StatsUsage extends Action /** * Commit stats to DB - * @param callable(): Database $getProjectDB + * @param callable(Document): Database $getProjectDB * @return void */ public function commitToDb(callable $getProjectDB): void @@ -459,7 +459,7 @@ class StatsUsage extends Action /** * Sort by unique index key reduce locks/deadlocks */ - usort($projectStats['stats'], function ($a, $b) use ($sequence) { + usort($projectStats['stats'], function ($a, $b) { // Metric DESC $cmp = strcmp($b['metric'], $a['metric']); if ($cmp !== 0) { diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php index fce3c7b149..509f0a6313 100644 --- a/src/Appwrite/Platform/Workers/Webhooks.php +++ b/src/Appwrite/Platform/Workers/Webhooks.php @@ -233,7 +233,7 @@ class Webhooks extends Action $template->setParam('{{webhook}}', $webhook->getAttribute('name')); $template->setParam('{{project}}', $project->getAttribute('name')); $template->setParam('{{url}}', $webhook->getAttribute('url')); - $template->setParam('{{error}}', $curlError ?? 'The server returned ' . $statusCode . ' status code'); + $template->setParam('{{error}}', 'The server returned ' . $statusCode . ' status code'); $template->setParam('{{path}}', "/console/project-$region-$projectId/settings/webhooks/$webhookId"); $template->setParam('{{attempts}}', $attempts); diff --git a/src/Appwrite/Promises/Promise.php b/src/Appwrite/Promises/Promise.php index a6b1aa79d5..a58c7c29a8 100644 --- a/src/Appwrite/Promises/Promise.php +++ b/src/Appwrite/Promises/Promise.php @@ -2,6 +2,7 @@ namespace Appwrite\Promises; +/** @phpstan-consistent-constructor */ abstract class Promise { protected const STATE_PENDING = 1; diff --git a/src/Appwrite/SDK/Method.php b/src/Appwrite/SDK/Method.php index 3cf96b5413..c74406b2a6 100644 --- a/src/Appwrite/SDK/Method.php +++ b/src/Appwrite/SDK/Method.php @@ -197,7 +197,7 @@ class Method public function isHidden(): bool|array { - return $this->hide ?? false; + return $this->hide; } public function isPackaging(): bool diff --git a/src/Appwrite/Utopia/Database/Documents/User.php b/src/Appwrite/Utopia/Database/Documents/User.php index 50e66dac38..211c6449dc 100644 --- a/src/Appwrite/Utopia/Database/Documents/User.php +++ b/src/Appwrite/Utopia/Database/Documents/User.php @@ -86,7 +86,6 @@ class User extends Document /** * Check if user is anonymous. * - * @param Document $this * @return bool */ public function isAnonymous(): bool @@ -153,7 +152,6 @@ class User extends Document /** * Verify session and check that its not expired. * - * @param array $sessions * @param string $secret * * @return bool|string diff --git a/tests/e2e/Services/GraphQL/Legacy/AbuseTest.php b/tests/e2e/Services/GraphQL/Legacy/AbuseTest.php index dfec046f55..39939fdc0e 100644 --- a/tests/e2e/Services/GraphQL/Legacy/AbuseTest.php +++ b/tests/e2e/Services/GraphQL/Legacy/AbuseTest.php @@ -102,7 +102,7 @@ class AbuseTest extends Scope $maxQueries = System::getEnv('_APP_GRAPHQL_MAX_QUERIES', 10); $query = []; - for ($i = 0; $i <= $maxQueries + 1; $i++) { + for ($i = 0; $i <= ((int) $maxQueries) + 1; $i++) { $query[] = ['query' => $this->getQuery(self::LIST_COUNTRIES)]; } diff --git a/tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php b/tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php index 05185149fd..c358882b8b 100644 --- a/tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php +++ b/tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php @@ -102,7 +102,7 @@ class AbuseTest extends Scope $maxQueries = System::getEnv('_APP_GRAPHQL_MAX_QUERIES', 10); $query = []; - for ($i = 0; $i <= $maxQueries + 1; $i++) { + for ($i = 0; $i <= ((int) $maxQueries) + 1; $i++) { $query[] = ['query' => $this->getQuery(self::LIST_COUNTRIES)]; } diff --git a/tests/unit/Event/EventTest.php b/tests/unit/Event/EventTest.php index d5936e4b8f..fcaf1f734d 100644 --- a/tests/unit/Event/EventTest.php +++ b/tests/unit/Event/EventTest.php @@ -13,7 +13,7 @@ class EventTest extends TestCase { protected ?Event $object = null; protected string $queue = ''; - protected Publisher $publisher; + protected MockPublisher $publisher; public function setUp(): void { diff --git a/tests/unit/Functions/Validator/HeadersTest.php b/tests/unit/Functions/Validator/HeadersTest.php index 4a45f57427..563131d480 100644 --- a/tests/unit/Functions/Validator/HeadersTest.php +++ b/tests/unit/Functions/Validator/HeadersTest.php @@ -76,11 +76,6 @@ class HeadersTest extends TestCase ]; $this->assertFalse($this->object->isValid($headers)); - $headers = [ - null => 'value', - ]; - $this->assertFalse($this->object->isValid($headers)); - $headers = [ 'X-Header' => null, ];