@@ -164,6 +164,59 @@ public function get(string $id, ?array $options = null): User
164164 );
165165 }
166166
167+ /**
168+ * Upsert a user (create or update).
169+ *
170+ * @param string $id ID of the user to upsert.
171+ * @param UpdatedUser $request
172+ * @param ?array{
173+ * baseUrl?: string,
174+ * maxRetries?: int,
175+ * } $options
176+ * @return User
177+ * @throws TrophyException
178+ * @throws TrophyApiException
179+ */
180+ public function upsert (string $ id , UpdatedUser $ request , ?array $ options = null ): User
181+ {
182+ $ options = array_merge ($ this ->options , $ options ?? []);
183+ try {
184+ $ response = $ this ->client ->sendRequest (
185+ new JsonApiRequest (
186+ baseUrl: $ options ['baseUrl ' ] ?? $ this ->client ->options ['baseUrl ' ] ?? Environments::Default_->value ,
187+ path: "users/ $ id " ,
188+ method: HttpMethod::PUT ,
189+ body: $ request ,
190+ ),
191+ $ options ,
192+ );
193+ $ statusCode = $ response ->getStatusCode ();
194+ if ($ statusCode >= 200 && $ statusCode < 400 ) {
195+ $ json = $ response ->getBody ()->getContents ();
196+ return User::fromJson ($ json );
197+ }
198+ } catch (JsonException $ e ) {
199+ throw new TrophyException (message: "Failed to deserialize response: {$ e ->getMessage ()}" , previous: $ e );
200+ } catch (RequestException $ e ) {
201+ $ response = $ e ->getResponse ();
202+ if ($ response === null ) {
203+ throw new TrophyException (message: $ e ->getMessage (), previous: $ e );
204+ }
205+ throw new TrophyApiException (
206+ message: "API request failed " ,
207+ statusCode: $ response ->getStatusCode (),
208+ body: $ response ->getBody ()->getContents (),
209+ );
210+ } catch (ClientExceptionInterface $ e ) {
211+ throw new TrophyException (message: $ e ->getMessage (), previous: $ e );
212+ }
213+ throw new TrophyApiException (
214+ message: 'API request failed ' ,
215+ statusCode: $ statusCode ,
216+ body: $ response ->getBody ()->getContents (),
217+ );
218+ }
219+
167220 /**
168221 * Update a user.
169222 *
0 commit comments