diff --git a/app/src/Controller/Profile/ProfileController.php b/app/src/Controller/Profile/ProfileController.php index 98b602f..36c0bd1 100644 --- a/app/src/Controller/Profile/ProfileController.php +++ b/app/src/Controller/Profile/ProfileController.php @@ -8,6 +8,7 @@ use App\Database\Currency; use App\Database\GoogleAccount; use App\Repository\CurrencyRepository; +use App\Repository\GoogleAccountRepository; use App\Request\CheckNickNameRequest; use App\Request\Profile\UpdateBasicRequest; use App\Request\Profile\UpdateLocaleRequest; @@ -33,6 +34,7 @@ public function __construct( protected ResponseWrapper $response, protected CurrencyRepository $currencyRepository, protected UserOptionsService $userOptionsService, + protected GoogleAccountRepository $googleAccountRepository, ) { parent::__construct($auth); } @@ -121,9 +123,11 @@ public function updateLocale(UpdateLocaleRequest $request): ResponseInterface #[Route(route: '/profile/social', name: 'profile.social', methods: 'GET', group: 'auth')] public function socialAccounts(): ResponseInterface { + $googleAccount = $this->googleAccountRepository->findByUser($this->user); + return $this->response->json([ 'data' => [ - 'google' => $this->user->googleAccount instanceof GoogleAccount + 'google' => $googleAccount instanceof GoogleAccount ], ]); } diff --git a/app/src/Database/GoogleAccount.php b/app/src/Database/GoogleAccount.php index c886725..fbab3c1 100644 --- a/app/src/Database/GoogleAccount.php +++ b/app/src/Database/GoogleAccount.php @@ -5,12 +5,12 @@ namespace App\Database; use App\Database\Typecast\EncryptedTypecast; -use App\Repository\ChargeRepository; +use App\Repository\GoogleAccountRepository; use Cycle\Annotated\Annotation as ORM; use Cycle\ORM\Entity\Behavior; use Cycle\ORM\Parser\Typecast; -#[ORM\Entity(repository: ChargeRepository::class, typecast: [ +#[ORM\Entity(repository: GoogleAccountRepository::class, typecast: [ Typecast::class, EncryptedTypecast::class, ])] diff --git a/app/src/Database/User.php b/app/src/Database/User.php index 58f1496..a802b95 100644 --- a/app/src/Database/User.php +++ b/app/src/Database/User.php @@ -64,9 +64,6 @@ class User implements PasswordContainerInterface #[ORM\Relation\BelongsTo(target: Currency::class, innerKey: 'default_currency_code', cascade: true, load: 'eager')] private Currency $defaultCurrency; - #[ORM\Relation\HasOne(target: GoogleAccount::class, outerKey: 'user_id', nullable: true, cascade: true)] - public GoogleAccount|null $googleAccount = null; - #[ORM\Column(type: 'json', name: 'options', typecast: JsonTypecast::RULE)] public array $options = []; diff --git a/app/src/Repository/GoogleAccountRepository.php b/app/src/Repository/GoogleAccountRepository.php index 839d242..7f9db78 100644 --- a/app/src/Repository/GoogleAccountRepository.php +++ b/app/src/Repository/GoogleAccountRepository.php @@ -4,6 +4,7 @@ namespace App\Repository; +use App\Database\User; use Cycle\ORM\Select\Repository; /** @@ -11,4 +12,14 @@ */ class GoogleAccountRepository extends Repository { + /** + * @param \App\Database\User $user + * @return object|null + */ + public function findByUser(User $user): object|null + { + return $this->findOne([ + 'user_id' => $user->id, + ]); + } } diff --git a/app/src/Service/Auth/AuthService.php b/app/src/Service/Auth/AuthService.php index ebe0315..a4f9f6e 100644 --- a/app/src/Service/Auth/AuthService.php +++ b/app/src/Service/Auth/AuthService.php @@ -5,10 +5,12 @@ namespace App\Service\Auth; use App\Database\Currency; +use App\Database\GoogleAccount; use App\Database\User; use App\Repository\CurrencyRepository; use App\Repository\UserRepository; use App\Security\PasswordContainerInterface; +use App\Service\GoogleAccountService; use App\Service\UserOptionsService; use App\Service\UserService; use Psr\Http\Message\ServerRequestInterface; @@ -35,6 +37,7 @@ public function __construct( protected UserOptionsService $userOptionsService, protected CurrencyRepository $currencyRepository, protected RefreshTokenService $refreshTokenService, + protected GoogleAccountService $googleAccountService, protected EmailConfirmationService $emailConfirmationService, ) { } @@ -135,13 +138,6 @@ protected function createUser(User $user, string $locale = null): User $this->userOptionsService->setLocale($user, $locale ?? $this->translator->getLocale()); - if (($googleAccount = $user->googleAccount) !== null) { - // insert user first - $user->googleAccount = null; - $this->storeUser($user); - $user->googleAccount = $googleAccount; - } - $this->storeUser($user); if (! $user->isEmailConfirmed) { @@ -166,6 +162,21 @@ protected function storeUser(User $user): User } } + protected function storeGoogleAccount(GoogleAccount $googleAccount): GoogleAccount + { + try { + return $this->googleAccountService->store($googleAccount); + } catch (\Throwable $exception) { + $this->logger->error('Error while storing googleAccount', [ + 'error' => get_class($exception), + 'message' => $exception->getMessage(), + 'code' => $exception->getCode(), + ]); + + throw new \RuntimeException($exception->getMessage(), (int) $exception->getCode(), $exception); + } + } + protected function initiateEmailConfirmation(User $user): void { try { diff --git a/app/src/Service/Auth/GoogleAuthService.php b/app/src/Service/Auth/GoogleAuthService.php index 795294f..ca1e925 100644 --- a/app/src/Service/Auth/GoogleAuthService.php +++ b/app/src/Service/Auth/GoogleAuthService.php @@ -8,8 +8,10 @@ use App\Database\GoogleAccount; use App\Database\User; use App\Repository\CurrencyRepository; +use App\Repository\GoogleAccountRepository; use App\Repository\UserRepository; use App\Service\Auth\Exception\InvalidTokenException; +use App\Service\GoogleAccountService; use App\Service\PhotoStorageService; use App\Service\UserOptionsService; use App\Service\UserService; @@ -36,7 +38,9 @@ public function __construct( protected CurrencyRepository $currencyRepository, protected PhotoStorageService $photoStorageService, protected RefreshTokenService $refreshTokenService, + protected GoogleAccountService $googleAccountService, protected EmailConfirmationService $emailConfirmationService, + protected readonly GoogleAccountRepository $googleAccountRepository, ) { parent::__construct( $this->auth, @@ -48,6 +52,7 @@ public function __construct( $this->userOptionsService, $this->currencyRepository, $this->refreshTokenService, + $this->googleAccountService, $this->emailConfirmationService, ); } @@ -126,25 +131,23 @@ public function loginOrRegister(string $idToken): Authentication throw new InvalidTokenException($this->say('google_auth_account_not_verified')); } - if ( - $user instanceof User && - $user->googleAccount !== null && - $user->googleAccount->accountId !== (string) ($data['sub'] ?? '') - ) { - $this->logger->error('Unable to attach Google Account to existing user, Google account ID is already attached and different from actual.', [ - 'data' => json_encode($data), - ]); + if ($user instanceof User) { + $googleAccount = $this->googleAccountRepository->findByUser($user); - throw new InvalidTokenException($this->say('google_auth_email_already_claimed')); - } + if ($googleAccount instanceof GoogleAccount && $googleAccount->accountId !== (string) ($data['sub'] ?? '')) { + $this->logger->error('Unable to attach Google Account to existing user, Google account ID is already attached and different from actual.', [ + 'data' => json_encode($data), + ]); - if ($user instanceof User) { - if ($user->googleAccount instanceof GoogleAccount) { + throw new InvalidTokenException($this->say('google_auth_email_already_claimed')); + } + + if ($googleAccount instanceof GoogleAccount) { // Update existing Google Account data - $user->googleAccount->setData($data); + $googleAccount->setData($data); } else { // attach existing user to the new Google Account - $user->googleAccount = $this->makeGoogleAccount($data); + $googleAccount = $this->makeGoogleAccount($user, $data); if ($user->photo === null) { $this->photoStorageService->queueDownloadProfilePhoto((int) $user->id, $data['picture']); @@ -152,10 +155,13 @@ public function loginOrRegister(string $idToken): Authentication } $this->storeUser($user); + $this->storeGoogleAccount($googleAccount); } else { // new user $user = $this->makeUser($data); $user = $this->createUser($user); + $googleAccount = $this->makeGoogleAccount($user, $data); + $this->storeGoogleAccount($googleAccount); $this->photoStorageService->queueDownloadProfilePhoto((int) $user->id, $data['picture']); } @@ -171,14 +177,14 @@ protected function makeUser(array $data): User $user->email = $data['email'] ?? null; $user->defaultCurrencyCode = Currency::DEFAULT_CURRENCY_CODE; $user->isEmailConfirmed = (bool) ($data['email_verified'] ?? false); - $user->googleAccount = $this->makeGoogleAccount($data); return $user; } - protected function makeGoogleAccount(array $data): GoogleAccount + protected function makeGoogleAccount(User $user, array $data): GoogleAccount { $account = new GoogleAccount(); + $account->userId = (int) $user->id; $account->accountId = $data['sub'] ?? null; $account->pictureUrl = $data['picture'] ?? null; $account->setData($data); diff --git a/app/src/Service/GoogleAccountService.php b/app/src/Service/GoogleAccountService.php new file mode 100644 index 0000000..4adeebf --- /dev/null +++ b/app/src/Service/GoogleAccountService.php @@ -0,0 +1,24 @@ +tr->persist($googleAccount); + $this->tr->run(); + + return $googleAccount; + } +} diff --git a/composer.lock b/composer.lock index 53d3831..bc07582 100644 --- a/composer.lock +++ b/composer.lock @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.318.0", + "version": "3.321.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3f9cc3fe95f5dfa9fbd535c4d3bc78e7ac0adf44" + "reference": "c04f8f30891cee8480c132778cd4cc486467e77a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3f9cc3fe95f5dfa9fbd535c4d3bc78e7ac0adf44", - "reference": "3f9cc3fe95f5dfa9fbd535c4d3bc78e7ac0adf44", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c04f8f30891cee8480c132778cd4cc486467e77a", + "reference": "c04f8f30891cee8480c132778cd4cc486467e77a", "shasum": "" }, "require": { @@ -154,9 +154,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.318.0" + "source": "https://github.com/aws/aws-sdk-php/tree/3.321.2" }, - "time": "2024-08-06T18:05:56+00:00" + "time": "2024-08-30T18:14:40+00:00" }, { "name": "beste/clock", @@ -228,20 +228,20 @@ }, { "name": "beste/in-memory-cache", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/beste/in-memory-cache-php.git", - "reference": "6c59a01d667c3fe1e0e746e53bc939fb8950917a" + "reference": "f8299adc8abdaf7d309e8b28e53b4307ea49ebc7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beste/in-memory-cache-php/zipball/6c59a01d667c3fe1e0e746e53bc939fb8950917a", - "reference": "6c59a01d667c3fe1e0e746e53bc939fb8950917a", + "url": "https://api.github.com/repos/beste/in-memory-cache-php/zipball/f8299adc8abdaf7d309e8b28e53b4307ea49ebc7", + "reference": "f8299adc8abdaf7d309e8b28e53b4307ea49ebc7", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "psr/cache": "^2.0 || ^3.0", "psr/clock": "^1.0" }, @@ -250,14 +250,14 @@ }, "require-dev": { "beste/clock": "^3.0", - "beste/php-cs-fixer-config": "^3.1", - "friendsofphp/php-cs-fixer": "^3.60.0", + "beste/php-cs-fixer-config": "^3.2.0", + "friendsofphp/php-cs-fixer": "^3.62.0", "phpstan/extension-installer": "^1.4.1", - "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-deprecation-rules": "^1.2.0", "phpstan/phpstan-phpunit": "^1.4.0", "phpstan/phpstan-strict-rules": "^1.6.0", - "phpunit/phpunit": "^10.5.2 || ^11.2.8", + "phpunit/phpunit": "^10.5.2 || ^11.3.1", "symfony/var-dumper": "^6.4 || ^7.1.3" }, "suggest": { @@ -287,7 +287,7 @@ ], "support": { "issues": "https://github.com/beste/in-memory-cache-php/issues", - "source": "https://github.com/beste/in-memory-cache-php/tree/1.2.0" + "source": "https://github.com/beste/in-memory-cache-php/tree/1.3.1" }, "funding": [ { @@ -295,25 +295,25 @@ "type": "github" } ], - "time": "2024-07-26T22:11:58+00:00" + "time": "2024-08-26T15:51:58+00:00" }, { "name": "beste/json", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/beste/json.git", - "reference": "2d7aea5a7ceeb428350ba450e4a227ac581359b4" + "reference": "3ed7d6be039617e5ea63a835a792a811c7fba0ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beste/json/zipball/2d7aea5a7ceeb428350ba450e4a227ac581359b4", - "reference": "2d7aea5a7ceeb428350ba450e4a227ac581359b4", + "url": "https://api.github.com/repos/beste/json/zipball/3ed7d6be039617e5ea63a835a792a811c7fba0ff", + "reference": "3ed7d6be039617e5ea63a835a792a811c7fba0ff", "shasum": "" }, "require": { "ext-json": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { "phpstan/extension-installer": "^1.3", @@ -346,15 +346,19 @@ ], "support": { "issues": "https://github.com/beste/json/issues", - "source": "https://github.com/beste/json/tree/1.4.0" + "source": "https://github.com/beste/json/tree/1.5.0" }, "funding": [ { "url": "https://github.com/jeromegamez", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/beste/json", + "type": "tidelift" } ], - "time": "2023-11-30T22:41:32+00:00" + "time": "2024-08-16T22:44:02+00:00" }, { "name": "brick/math", @@ -911,16 +915,16 @@ }, { "name": "cycle/entity-behavior", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/cycle/entity-behavior.git", - "reference": "fd6de37bcee0d8e753805f83c574762e82426490" + "reference": "9b7ad13a68a0ea0dca0399b7f44f20b691a18120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cycle/entity-behavior/zipball/fd6de37bcee0d8e753805f83c574762e82426490", - "reference": "fd6de37bcee0d8e753805f83c574762e82426490", + "url": "https://api.github.com/repos/cycle/entity-behavior/zipball/9b7ad13a68a0ea0dca0399b7f44f20b691a18120", + "reference": "9b7ad13a68a0ea0dca0399b7f44f20b691a18120", "shasum": "" }, "require": { @@ -980,7 +984,7 @@ "type": "github" } ], - "time": "2024-02-08T19:35:15+00:00" + "time": "2024-08-09T11:47:14+00:00" }, { "name": "cycle/entity-behavior-uuid", @@ -1097,16 +1101,16 @@ }, { "name": "cycle/orm", - "version": "v2.8.0", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/cycle/orm.git", - "reference": "0677d297878ac8a9fe1254340ef4be7b6172b77c" + "reference": "23023be5e8452c1e5b05417f9c4539db71d60927" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cycle/orm/zipball/0677d297878ac8a9fe1254340ef4be7b6172b77c", - "reference": "0677d297878ac8a9fe1254340ef4be7b6172b77c", + "url": "https://api.github.com/repos/cycle/orm/zipball/23023be5e8452c1e5b05417f9c4539db71d60927", + "reference": "23023be5e8452c1e5b05417f9c4539db71d60927", "shasum": "" }, "require": { @@ -1124,6 +1128,7 @@ "phpunit/phpunit": "^9.5", "ramsey/uuid": "^4.0", "spiral/tokenizer": "^2.8 || ^3.0", + "symfony/var-dumper": "^5.2 || ^6.0 || ^7.0", "vimeo/psalm": "5.21" }, "type": "library", @@ -1168,7 +1173,7 @@ "type": "github" } ], - "time": "2024-05-09T14:50:55+00:00" + "time": "2024-06-05T13:14:36+00:00" }, { "name": "cycle/schema-builder", @@ -2058,16 +2063,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.367.0", + "version": "v0.370.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "edc08087aa3ca63d3b74f24d59f1d2caab39b5d9" + "reference": "25ad8515701dd832313d0f5f0a828670d60e541a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/edc08087aa3ca63d3b74f24d59f1d2caab39b5d9", - "reference": "edc08087aa3ca63d3b74f24d59f1d2caab39b5d9", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/25ad8515701dd832313d0f5f0a828670d60e541a", + "reference": "25ad8515701dd832313d0f5f0a828670d60e541a", "shasum": "" }, "require": { @@ -2096,22 +2101,22 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.367.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.370.0" }, - "time": "2024-07-11T01:08:44+00:00" + "time": "2024-08-26T01:04:18+00:00" }, { "name": "google/auth", - "version": "v1.41.0", + "version": "v1.42.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-auth-library-php.git", - "reference": "1043ea18fe7f5dfbf5b208ce3ee6d6b6ab8cb038" + "reference": "0c25599a91530b5847f129b271c536f75a7563f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/1043ea18fe7f5dfbf5b208ce3ee6d6b6ab8cb038", - "reference": "1043ea18fe7f5dfbf5b208ce3ee6d6b6ab8cb038", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/0c25599a91530b5847f129b271c536f75a7563f5", + "reference": "0c25599a91530b5847f129b271c536f75a7563f5", "shasum": "" }, "require": { @@ -2156,22 +2161,22 @@ "support": { "docs": "https://googleapis.github.io/google-auth-library-php/main/", "issues": "https://github.com/googleapis/google-auth-library-php/issues", - "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.41.0" + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.42.0" }, - "time": "2024-07-10T15:21:07+00:00" + "time": "2024-08-26T18:33:48+00:00" }, { "name": "google/cloud-core", - "version": "v1.59.0", + "version": "v1.59.1", "source": { "type": "git", "url": "https://github.com/googleapis/google-cloud-php-core.git", - "reference": "56d31be2663780a7ed0736bee60d01f047bf15c0" + "reference": "35aae23dc4d0b860b6c3733e5cf381a510b506d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/56d31be2663780a7ed0736bee60d01f047bf15c0", - "reference": "56d31be2663780a7ed0736bee60d01f047bf15c0", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/35aae23dc4d0b860b6c3733e5cf381a510b506d9", + "reference": "35aae23dc4d0b860b6c3733e5cf381a510b506d9", "shasum": "" }, "require": { @@ -2222,9 +2227,9 @@ ], "description": "Google Cloud PHP shared dependency, providing functionality useful to all components.", "support": { - "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.59.0" + "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.59.1" }, - "time": "2024-06-07T22:33:41+00:00" + "time": "2024-08-10T02:24:23+00:00" }, { "name": "google/cloud-storage", @@ -2285,16 +2290,16 @@ }, { "name": "google/common-protos", - "version": "v4.8.0", + "version": "4.8.2", "source": { "type": "git", "url": "https://github.com/googleapis/common-protos-php.git", - "reference": "72567e64f2e1ab209e5b933338d0aaf8abad404b" + "reference": "6f7f8e2f84b65a7d657970ab4727277400efa514" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/common-protos-php/zipball/72567e64f2e1ab209e5b933338d0aaf8abad404b", - "reference": "72567e64f2e1ab209e5b933338d0aaf8abad404b", + "url": "https://api.github.com/repos/googleapis/common-protos-php/zipball/6f7f8e2f84b65a7d657970ab4727277400efa514", + "reference": "6f7f8e2f84b65a7d657970ab4727277400efa514", "shasum": "" }, "require": { @@ -2339,22 +2344,22 @@ ], "support": { "issues": "https://github.com/googleapis/common-protos-php/issues", - "source": "https://github.com/googleapis/common-protos-php/tree/v4.8.0" + "source": "https://github.com/googleapis/common-protos-php/tree/v4.8.2" }, - "time": "2024-08-02T22:35:31+00:00" + "time": "2024-08-19T16:20:29+00:00" }, { "name": "google/gax", - "version": "v1.34.0", + "version": "v1.34.1", "source": { "type": "git", "url": "https://github.com/googleapis/gax-php.git", - "reference": "28aa3e95969a75b278606a88448992a6396a119e" + "reference": "173f0a97323284f91fd453c4ed7ed8317ecf6cfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/gax-php/zipball/28aa3e95969a75b278606a88448992a6396a119e", - "reference": "28aa3e95969a75b278606a88448992a6396a119e", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/173f0a97323284f91fd453c4ed7ed8317ecf6cfa", + "reference": "173f0a97323284f91fd453c4ed7ed8317ecf6cfa", "shasum": "" }, "require": { @@ -2396,9 +2401,9 @@ ], "support": { "issues": "https://github.com/googleapis/gax-php/issues", - "source": "https://github.com/googleapis/gax-php/tree/v1.34.0" + "source": "https://github.com/googleapis/gax-php/tree/v1.34.1" }, - "time": "2024-05-30T00:35:13+00:00" + "time": "2024-08-15T18:00:58+00:00" }, { "name": "google/grpc-gcp", @@ -2966,7 +2971,7 @@ }, { "name": "illuminate/collections", - "version": "v10.48.19", + "version": "v10.48.20", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -3021,7 +3026,7 @@ }, { "name": "illuminate/conditionable", - "version": "v10.48.19", + "version": "v10.48.20", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -3067,7 +3072,7 @@ }, { "name": "illuminate/contracts", - "version": "v10.48.19", + "version": "v10.48.20", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -3115,7 +3120,7 @@ }, { "name": "illuminate/macroable", - "version": "v10.48.19", + "version": "v10.48.20", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -4807,16 +4812,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.39", + "version": "3.0.41", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485" + "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/211ebc399c6e73c225a018435fe5ae209d1d1485", - "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/621c73f7dcb310b61de34d1da4c4204e8ace6ceb", + "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb", "shasum": "" }, "require": { @@ -4897,7 +4902,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.39" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.41" }, "funding": [ { @@ -4913,20 +4918,20 @@ "type": "tidelift" } ], - "time": "2024-06-24T06:27:33+00:00" + "time": "2024-08-12T00:13:54+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.29.1", + "version": "1.30.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + "reference": "5ceb0e384997db59f38774bf79c2a6134252c08f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/5ceb0e384997db59f38774bf79c2a6134252c08f", + "reference": "5ceb0e384997db59f38774bf79c2a6134252c08f", "shasum": "" }, "require": { @@ -4958,9 +4963,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.0" }, - "time": "2024-05-31T08:52:43+00:00" + "time": "2024-08-29T09:54:52+00:00" }, { "name": "psr/cache", @@ -5437,16 +5442,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "79dff0b268932c640297f5208d6298f71855c03e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e", + "reference": "79dff0b268932c640297f5208d6298f71855c03e", "shasum": "" }, "require": { @@ -5481,9 +5486,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.1" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-08-21T13:31:24+00:00" }, { "name": "psr/simple-cache", @@ -5763,16 +5768,16 @@ }, { "name": "rize/uri-template", - "version": "0.3.6", + "version": "0.3.8", "source": { "type": "git", "url": "https://github.com/rize/UriTemplate.git", - "reference": "34efe65c79710eed0883884f2285ae6d4a0aad19" + "reference": "34a5b96d0b65a5dddb7d20f09b6527a43faede24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rize/UriTemplate/zipball/34efe65c79710eed0883884f2285ae6d4a0aad19", - "reference": "34efe65c79710eed0883884f2285ae6d4a0aad19", + "url": "https://api.github.com/repos/rize/UriTemplate/zipball/34a5b96d0b65a5dddb7d20f09b6527a43faede24", + "reference": "34a5b96d0b65a5dddb7d20f09b6527a43faede24", "shasum": "" }, "require": { @@ -5805,7 +5810,7 @@ ], "support": { "issues": "https://github.com/rize/UriTemplate/issues", - "source": "https://github.com/rize/UriTemplate/tree/0.3.6" + "source": "https://github.com/rize/UriTemplate/tree/0.3.8" }, "funding": [ { @@ -5821,7 +5826,7 @@ "type": "open_collective" } ], - "time": "2024-03-10T08:07:49+00:00" + "time": "2024-08-30T07:09:40+00:00" }, { "name": "roadrunner-php/app-logger", @@ -6232,16 +6237,16 @@ }, { "name": "spiral/attributes", - "version": "v3.1.6", + "version": "v3.1.7", "source": { "type": "git", "url": "https://github.com/spiral/attributes.git", - "reference": "02f9b68a57618624029ee3ed165258f9bb7047b3" + "reference": "fc6657de4ed83913c7f02241e5fe4e8e799af8fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spiral/attributes/zipball/02f9b68a57618624029ee3ed165258f9bb7047b3", - "reference": "02f9b68a57618624029ee3ed165258f9bb7047b3", + "url": "https://api.github.com/repos/spiral/attributes/zipball/fc6657de4ed83913c7f02241e5fe4e8e799af8fa", + "reference": "fc6657de4ed83913c7f02241e5fe4e8e799af8fa", "shasum": "" }, "require": { @@ -6306,11 +6311,11 @@ }, "funding": [ { - "url": "https://github.com/sponsors/roadrunner-server", + "url": "https://github.com/sponsors/spiral", "type": "github" } ], - "time": "2024-06-27T10:30:21+00:00" + "time": "2024-08-22T10:18:52+00:00" }, { "name": "spiral/composer-publish-plugin", @@ -7991,16 +7996,16 @@ }, { "name": "symfony/console", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9" + "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", + "url": "https://api.github.com/repos/symfony/console/zipball/1eed7af6961d763e7832e874d7f9b21c3ea9c111", + "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111", "shasum": "" }, "require": { @@ -8064,7 +8069,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.3" + "source": "https://github.com/symfony/console/tree/v7.1.4" }, "funding": [ { @@ -8080,7 +8085,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-08-15T22:48:53+00:00" }, { "name": "symfony/deprecation-contracts", @@ -8307,16 +8312,16 @@ }, { "name": "symfony/finder", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca" + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/717c6329886f32dc65e27461f80f2a465412fdca", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca", + "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", "shasum": "" }, "require": { @@ -8351,7 +8356,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.3" + "source": "https://github.com/symfony/finder/tree/v7.1.4" }, "funding": [ { @@ -8367,20 +8372,20 @@ "type": "tidelift" } ], - "time": "2024-07-24T07:08:44+00:00" + "time": "2024-08-13T14:28:19+00:00" }, { "name": "symfony/http-client", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231" + "reference": "a8f8d60b30b331cf4b743b3632e5acdba3f8285c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/b79858aa7a051ea791b0d50269a234a0b50cb231", - "reference": "b79858aa7a051ea791b0d50269a234a0b50cb231", + "url": "https://api.github.com/repos/symfony/http-client/zipball/a8f8d60b30b331cf4b743b3632e5acdba3f8285c", + "reference": "a8f8d60b30b331cf4b743b3632e5acdba3f8285c", "shasum": "" }, "require": { @@ -8445,7 +8450,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.1.3" + "source": "https://github.com/symfony/http-client/tree/v7.1.4" }, "funding": [ { @@ -8461,7 +8466,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:10:24+00:00" + "time": "2024-08-26T06:32:37+00:00" }, { "name": "symfony/http-client-contracts", @@ -8623,16 +8628,16 @@ }, { "name": "symfony/mime", - "version": "v7.1.2", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "26a00b85477e69a4bab63b66c5dce64f18b0cbfc" + "reference": "ccaa6c2503db867f472a587291e764d6a1e58758" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/26a00b85477e69a4bab63b66c5dce64f18b0cbfc", - "reference": "26a00b85477e69a4bab63b66c5dce64f18b0cbfc", + "url": "https://api.github.com/repos/symfony/mime/zipball/ccaa6c2503db867f472a587291e764d6a1e58758", + "reference": "ccaa6c2503db867f472a587291e764d6a1e58758", "shasum": "" }, "require": { @@ -8687,7 +8692,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.1.2" + "source": "https://github.com/symfony/mime/tree/v7.1.4" }, "funding": [ { @@ -8703,7 +8708,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-08-13T14:28:19+00:00" }, { "name": "symfony/polyfill-ctype", @@ -9558,16 +9563,16 @@ }, { "name": "symfony/property-access", - "version": "v7.1.1", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "74e39e6a6276b8e384f34c6ddbc10a6c9a60193a" + "reference": "6c709f97103355016e5782d0622437ae381012ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/74e39e6a6276b8e384f34c6ddbc10a6c9a60193a", - "reference": "74e39e6a6276b8e384f34c6ddbc10a6c9a60193a", + "url": "https://api.github.com/repos/symfony/property-access/zipball/6c709f97103355016e5782d0622437ae381012ad", + "reference": "6c709f97103355016e5782d0622437ae381012ad", "shasum": "" }, "require": { @@ -9614,7 +9619,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.1.1" + "source": "https://github.com/symfony/property-access/tree/v7.1.4" }, "funding": [ { @@ -9630,7 +9635,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-08-30T16:12:47+00:00" }, { "name": "symfony/property-info", @@ -9718,16 +9723,16 @@ }, { "name": "symfony/serializer", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "0d5ddac365fbfffc30ca9bc944ad3eb9b3763c09" + "reference": "0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/0d5ddac365fbfffc30ca9bc944ad3eb9b3763c09", - "reference": "0d5ddac365fbfffc30ca9bc944ad3eb9b3763c09", + "url": "https://api.github.com/repos/symfony/serializer/zipball/0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb", + "reference": "0158b0e91b7cf7e744a6fb9acaeb613d1ca40dbb", "shasum": "" }, "require": { @@ -9795,7 +9800,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.1.3" + "source": "https://github.com/symfony/serializer/tree/v7.1.4" }, "funding": [ { @@ -9811,7 +9816,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:10:24+00:00" + "time": "2024-08-22T09:39:57+00:00" }, { "name": "symfony/service-contracts", @@ -9898,16 +9903,16 @@ }, { "name": "symfony/string", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07" + "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07", + "url": "https://api.github.com/repos/symfony/string/zipball/6cd670a6d968eaeb1c77c2e76091c45c56bc367b", + "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b", "shasum": "" }, "require": { @@ -9965,7 +9970,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.3" + "source": "https://github.com/symfony/string/tree/v7.1.4" }, "funding": [ { @@ -9981,7 +9986,7 @@ "type": "tidelift" } ], - "time": "2024-07-22T10:25:37+00:00" + "time": "2024-08-12T09:59:40+00:00" }, { "name": "symfony/translation", @@ -10240,16 +10245,16 @@ }, { "name": "symfony/uid", - "version": "v7.1.1", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "bb59febeecc81528ff672fad5dab7f06db8c8277" + "reference": "82177535395109075cdb45a70533aa3d7a521cdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/bb59febeecc81528ff672fad5dab7f06db8c8277", - "reference": "bb59febeecc81528ff672fad5dab7f06db8c8277", + "url": "https://api.github.com/repos/symfony/uid/zipball/82177535395109075cdb45a70533aa3d7a521cdf", + "reference": "82177535395109075cdb45a70533aa3d7a521cdf", "shasum": "" }, "require": { @@ -10294,7 +10299,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.1.1" + "source": "https://github.com/symfony/uid/tree/v7.1.4" }, "funding": [ { @@ -10310,20 +10315,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-08-12T09:59:40+00:00" }, { "name": "symfony/yaml", - "version": "v7.1.1", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2" + "reference": "92e080b851c1c655c786a2da77f188f2dccd0f4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/fa34c77015aa6720469db7003567b9f772492bf2", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/92e080b851c1c655c786a2da77f188f2dccd0f4b", + "reference": "92e080b851c1c655c786a2da77f188f2dccd0f4b", "shasum": "" }, "require": { @@ -10365,7 +10370,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.1.1" + "source": "https://github.com/symfony/yaml/tree/v7.1.4" }, "funding": [ { @@ -10381,7 +10386,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-08-12T09:59:40+00:00" }, { "name": "vlucas/phpdotenv", @@ -11168,26 +11173,26 @@ }, { "name": "composer/pcre", - "version": "3.2.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90" + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90", + "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.8" + "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "^8 || ^9" }, @@ -11227,7 +11232,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.2.0" + "source": "https://github.com/composer/pcre/tree/3.3.1" }, "funding": [ { @@ -11243,7 +11248,7 @@ "type": "tidelift" } ], - "time": "2024-07-25T09:36:02+00:00" + "time": "2024-08-27T18:44:43+00:00" }, { "name": "composer/xdebug-handler", @@ -11451,16 +11456,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -11500,7 +11505,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -11508,7 +11513,7 @@ "type": "github" } ], - "time": "2024-02-07T09:43:46+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -11815,35 +11820,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.31", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -11852,7 +11857,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -11881,7 +11886,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -11889,7 +11894,7 @@ "type": "github" } ], - "time": "2024-03-02T06:37:42+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -13573,16 +13578,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "a71cc3374f5fb9759da1961d28c452373b343dd4" + "reference": "ee14c8254a480913268b1e3b1cba8045ed122694" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a71cc3374f5fb9759da1961d28c452373b343dd4", - "reference": "a71cc3374f5fb9759da1961d28c452373b343dd4", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ee14c8254a480913268b1e3b1cba8045ed122694", + "reference": "ee14c8254a480913268b1e3b1cba8045ed122694", "shasum": "" }, "require": { @@ -13638,7 +13643,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.10" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.11" }, "funding": [ { @@ -13654,7 +13659,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:30:32+00:00" + "time": "2024-08-30T16:03:21+00:00" }, { "name": "theseer/tokenizer", diff --git a/tests/Factories/GoogleAccountFactory.php b/tests/Factories/GoogleAccountFactory.php new file mode 100644 index 0000000..4a335ee --- /dev/null +++ b/tests/Factories/GoogleAccountFactory.php @@ -0,0 +1,53 @@ +persist($googleAccount); + + return $googleAccount; + } + + public static function make(): GoogleAccount + { + $googleAccount = new GoogleAccount; + + $googleAccount->accountId = Fixtures::string(); + $googleAccount->pictureUrl = Fixtures::url(); + $googleAccount->setData([ + 'sub' => $googleAccount->accountId, + 'picture' => $googleAccount->pictureUrl, + ]); + + return $googleAccount; + } + + public static function withUser(User $user, ?array $data = null): GoogleAccount + { + $googleAccount = $data === null ? self::make() : self::withData($data); + $googleAccount->userId = $user->id; + + return $googleAccount; + } + + public static function withData(array $data = []): GoogleAccount + { + $googleAccount = self::make(); + $googleAccount->accountId = $data['sub'] ?? null; + $googleAccount->pictureUrl = $data['picture'] ?? null; + $googleAccount->setData($data); + + return $googleAccount; + } +} diff --git a/tests/Factories/UserFactory.php b/tests/Factories/UserFactory.php index c72a99b..73fe329 100644 --- a/tests/Factories/UserFactory.php +++ b/tests/Factories/UserFactory.php @@ -5,7 +5,6 @@ namespace Tests\Factories; use App\Database\Currency; -use App\Database\GoogleAccount; use App\Database\User; use Tests\Fixtures; @@ -91,20 +90,6 @@ public static function emailNotConfirmed(User $user = null): User return self::emailConfirmed($user, false); } - public static function withGoogleAccount(array $data = [], User $user = null): User - { - if ($user === null) { - $user = self::make(); - } - - $user->googleAccount = new GoogleAccount(); - $user->googleAccount->accountId = $data['sub'] ?? null; - $user->googleAccount->pictureUrl = $data['picture'] ?? null; - $user->googleAccount->setData($data); - - return $user; - } - public static function invalidNickNames(): array { return array_merge([ diff --git a/tests/Feature/Controller/Auth/GoogleProviderControllerTest.php b/tests/Feature/Controller/Auth/GoogleProviderControllerTest.php index e88d5bf..6cd8356 100644 --- a/tests/Feature/Controller/Auth/GoogleProviderControllerTest.php +++ b/tests/Feature/Controller/Auth/GoogleProviderControllerTest.php @@ -5,9 +5,11 @@ namespace Tests\Feature\Controller\Auth; use App\Repository\UserRepository; +use App\Service\GoogleAccountService; use App\Service\PhotoStorageService; use PHPUnit\Framework\MockObject\MockObject; use Tests\DatabaseTransaction; +use Tests\Factories\GoogleAccountFactory; use Tests\Factories\UserFactory; use Tests\Fixtures; use Tests\TestCase; @@ -16,11 +18,14 @@ class GoogleProviderControllerTest extends TestCase implements DatabaseTransacti { protected UserFactory $userFactory; + protected GoogleAccountFactory $googleAccountFactory; + protected function setUp(): void { parent::setUp(); $this->userFactory = $this->getContainer()->get(UserFactory::class); + $this->googleAccountFactory = $this->getContainer()->get(GoogleAccountFactory::class); } protected function googleAccountInfo(): array @@ -167,7 +172,7 @@ public function testLoggedInExistingUserExistingGoogleAccount(): void ]; $user = $this->userFactory->create($user); - $user = $this->userFactory->create(UserFactory::withGoogleAccount($existingData, $user)); + $this->googleAccountFactory->create(GoogleAccountFactory::withUser($user, $existingData)); $googleClient = $this->getMockBuilder(\Google\Client::class)->onlyMethods(['verifyIdToken'])->disableOriginalConstructor()->getMock(); $googleClient->expects($this->once())->method('verifyIdToken')->with($token)->willReturn([ @@ -232,7 +237,7 @@ public function testFailedExistingUserAlreadyHaveDifferentGoogleAccount(): void ]; $user = $this->userFactory->create($user); - $user = $this->userFactory->create(UserFactory::withGoogleAccount($existingData, $user)); + $this->googleAccountFactory->create(GoogleAccountFactory::withUser($user, $existingData)); [ 'token' => $token, @@ -426,4 +431,56 @@ public function testFindUserError(): void $this->assertArrayHasKey('message', $body); $this->assertEquals($message, $body['error']); } + + public function testGoogleAccountStoreError(): void + { + [ + 'token' => $token, + 'googleId' => $googleId, + 'email' => $email, + 'photoUrl' => $photoUrl, + ] = $this->googleAccountInfo(); + + $googleClient = $this->getMockBuilder(\Google\Client::class)->onlyMethods(['verifyIdToken'])->disableOriginalConstructor()->getMock(); + $googleClient->expects($this->once())->method('verifyIdToken')->with($token)->willReturn([ + 'sub' => $googleId, + 'email' => $email, + 'email_verified' => true, + 'picture' => $photoUrl, + 'given_name' => Fixtures::string(), + 'family_name' => Fixtures::string(), + ]); + $this->getContainer()->bind(\Google\Client::class, fn() => $googleClient); + + $this->mock(PhotoStorageService::class, ['queueDownloadProfilePhoto'], function (MockObject $mock) use ($photoUrl) { + $mock->expects($this->never())->method('queueDownloadProfilePhoto')->with($this->anything(), $photoUrl, null, null); + }); + + $mock = $this->getMockBuilder(GoogleAccountService::class) + ->disableOriginalConstructor() + ->onlyMethods(['store']) + ->getMock(); + + $mock->expects($this->once()) + ->method('store') + ->willThrowException(new \RuntimeException('Database exception')); + + $this->getContainer()->bind(GoogleAccountService::class, fn () => $mock); + + $response = $this->post('/auth/provider/google', [ + 'token' => $token, + ]); + + $response->assertStatus(500); + + $body = $this->getJsonResponseBody($response); + + $this->assertArrayHasKey('message', $body); + $this->assertArrayHasKey('error', $body); + + $this->assertDatabaseHas('users', ['email' => $email]); + $this->assertDatabaseMissing('google_accounts', [ + 'account_id' => $googleId, + ]); + } } diff --git a/tests/Feature/Controller/Profile/ProfileControllerTest.php b/tests/Feature/Controller/Profile/ProfileControllerTest.php index ab8dfa0..1cbda92 100644 --- a/tests/Feature/Controller/Profile/ProfileControllerTest.php +++ b/tests/Feature/Controller/Profile/ProfileControllerTest.php @@ -10,22 +10,23 @@ use App\Service\UserService; use Spiral\Testing\Http\TestResponse; use Tests\DatabaseTransaction; +use Tests\Factories\GoogleAccountFactory; use Tests\Factories\UserFactory; use Tests\Fixtures; use Tests\TestCase; class ProfileControllerTest extends TestCase implements DatabaseTransaction { - /** - * @var \Tests\Factories\UserFactory - */ protected UserFactory $userFactory; + protected GoogleAccountFactory $googleAccountFactory; + protected function setUp(): void { parent::setUp(); $this->userFactory = $this->getContainer()->get(UserFactory::class); + $this->googleAccountFactory = $this->getContainer()->get(GoogleAccountFactory::class); } private function userFields(): array @@ -487,7 +488,7 @@ public function testSocialAccountsGoogle(): void ]; $user = $this->userFactory->create($user); - $user = $this->userFactory->create(UserFactory::withGoogleAccount($existingData, $user)); + $this->googleAccountFactory->create(GoogleAccountFactory::withUser($user, $existingData)); $auth = $this->makeAuth($user);