Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php  | 
            ||
| 14 | class Desk  | 
            ||
| 15 | { | 
            ||
| 16 | /**  | 
            ||
| 17 | * @var \GuzzleHttp\Client  | 
            ||
| 18 | */  | 
            ||
| 19 | private Client $client;  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 20 | |||
| 21 | /**  | 
            ||
| 22 | * Desk constructor.  | 
            ||
| 23 | *  | 
            ||
| 24 | * @param \GuzzleHttp\Client $client  | 
            ||
| 25 | */  | 
            ||
| 26 | public function __construct(Client $client)  | 
            ||
| 27 |     { | 
            ||
| 28 | $this->client = $client;  | 
            ||
| 29 | }  | 
            ||
| 30 | |||
| 31 | /**  | 
            ||
| 32 | * Return an inbox by name.  | 
            ||
| 33 | *  | 
            ||
| 34 | * @param string $name  | 
            ||
| 35 | *  | 
            ||
| 36 | * @return array  | 
            ||
| 37 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkHttpException  | 
            ||
| 38 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkInboxException  | 
            ||
| 39 | * @throws \GuzzleHttp\Exception\GuzzleException  | 
            ||
| 40 | * @throws \JsonException  | 
            ||
| 41 | */  | 
            ||
| 42 | public function inbox($name): array  | 
            ||
| 43 |     { | 
            ||
| 44 |         try { | 
            ||
| 45 | /** @var Response $response */  | 
            ||
| 46 |             $response = $this->client->get('inboxes.json'); | 
            ||
| 47 | /** @var Stream $body */  | 
            ||
| 48 | $body = $response->getBody();  | 
            ||
| 49 | $inboxes = json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR);  | 
            ||
| 50 | |||
| 51 | $inbox = collect($inboxes['inboxes'])->first(  | 
            ||
| 52 |                 function ($inbox) use ($name) { | 
            ||
| 53 | return $inbox['name'] === $name;  | 
            ||
| 54 | }  | 
            ||
| 55 | );  | 
            ||
| 56 | |||
| 57 |             if (! $inbox) { | 
            ||
| 58 |                 throw new TeamworkInboxException("No inbox found with the name: $name!", 400); | 
            ||
| 59 | }  | 
            ||
| 60 | |||
| 61 | return $inbox;  | 
            ||
| 62 |         } catch (ClientException $e) { | 
            ||
| 63 | throw new TeamworkHttpException($e->getMessage(), 400);  | 
            ||
| 64 | }  | 
            ||
| 65 | }  | 
            ||
| 66 | |||
| 67 | /**  | 
            ||
| 68 | * Get teamwork desk inboxes.  | 
            ||
| 69 | *  | 
            ||
| 70 | * @return array  | 
            ||
| 71 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkHttpException  | 
            ||
| 72 | * @throws \GuzzleHttp\Exception\GuzzleException  | 
            ||
| 73 | * @throws \JsonException  | 
            ||
| 74 | */  | 
            ||
| 75 | public function inboxes(): array  | 
            ||
| 76 |     { | 
            ||
| 77 |         try { | 
            ||
| 78 | /** @var Response $response */  | 
            ||
| 79 |             $response = $this->client->get('inboxes.json'); | 
            ||
| 80 | /** @var Stream $body */  | 
            ||
| 81 | $body = $response->getBody();  | 
            ||
| 82 | |||
| 83 | return json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR);  | 
            ||
| 84 |         } catch (ClientException $e) { | 
            ||
| 85 | throw new TeamworkHttpException($e->getMessage(), 400);  | 
            ||
| 86 | }  | 
            ||
| 87 | }  | 
            ||
| 88 | |||
| 89 | /**  | 
            ||
| 90 | * Return the current client info.  | 
            ||
| 91 | *  | 
            ||
| 92 | * @return array  | 
            ||
| 93 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkHttpException  | 
            ||
| 94 | * @throws \GuzzleHttp\Exception\GuzzleException  | 
            ||
| 95 | * @throws \JsonException  | 
            ||
| 96 | */  | 
            ||
| 97 | public function me(): array  | 
            ||
| 98 |     { | 
            ||
| 99 |         try { | 
            ||
| 100 | /** @var Response $response */  | 
            ||
| 101 |             $response = $this->client->get('me.json'); | 
            ||
| 102 | /** @var Stream $body */  | 
            ||
| 103 | $body = $response->getBody();  | 
            ||
| 104 | |||
| 105 | return json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR);  | 
            ||
| 106 |         } catch (ClientException $e) { | 
            ||
| 107 | throw new TeamworkHttpException($e->getMessage(), 400);  | 
            ||
| 108 | }  | 
            ||
| 109 | }  | 
            ||
| 110 | |||
| 111 | /**  | 
            ||
| 112 | * Update the customer, based on customerId.  | 
            ||
| 113 | *  | 
            ||
| 114 | * @param array $data = ['customerId', 'email', 'firstName', 'lastName', 'phone', 'mobile'];  | 
            ||
| 115 | *  | 
            ||
| 116 | * @return array  | 
            ||
| 117 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkHttpException  | 
            ||
| 118 | * @throws \GuzzleHttp\Exception\GuzzleException  | 
            ||
| 119 | * @throws \JsonException  | 
            ||
| 120 | */  | 
            ||
| 121 | public function postCustomer(array $data): array  | 
            ||
| 122 |     { | 
            ||
| 123 |         try { | 
            ||
| 124 | /** @var Response $response */  | 
            ||
| 125 |             $response = $this->client->put('customers/'.$data['customerId'].'.json', [ | 
            ||
| 126 | 'json' => $data,  | 
            ||
| 127 | ]);  | 
            ||
| 128 | |||
| 129 | /** @var Stream $body */  | 
            ||
| 130 | $body = $response->getBody();  | 
            ||
| 131 | |||
| 132 | return json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR);  | 
            ||
| 133 |         } catch (ClientException $e) { | 
            ||
| 134 | throw new TeamworkHttpException($e->getMessage(), 400);  | 
            ||
| 135 | }  | 
            ||
| 136 | }  | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * Upload file to teamwork desk.  | 
            ||
| 140 | *  | 
            ||
| 141 | * @param $userId  | 
            ||
| 142 | * @param $file  | 
            ||
| 143 | *  | 
            ||
| 144 | * @return array  | 
            ||
| 145 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkHttpException  | 
            ||
| 146 | * @throws \DigitalEquation\Teamwork\Exceptions\TeamworkUploadException  | 
            ||
| 147 | * @throws \GuzzleHttp\Exception\GuzzleException  | 
            ||
| 148 | * @throws \JsonException  | 
            ||
| 149 | */  | 
            ||
| 150 | public function upload($userId, $file): array  | 
            ||
| 151 |     { | 
            ||
| 152 |         if (empty($file)) { | 
            ||
| 153 |             throw new TeamworkUploadException('No file provided.', 400); | 
            ||
| 154 | }  | 
            ||
| 155 | |||
| 156 | $filename = $file->getClientOriginalName();  | 
            ||
| 157 | $extension = $file->getClientOriginalExtension();  | 
            ||
| 158 | $path = sys_get_temp_dir();  | 
            ||
| 159 | $temp = $file->move($path, $filename);  | 
            ||
| 160 | $stream = fopen($temp->getPathName(), 'rb');  | 
            ||
| 161 | |||
| 162 |         try { | 
            ||
| 163 | /** @var Response $response */  | 
            ||
| 164 |             $response = $this->client->post('upload/attachment', [ | 
            ||
| 165 | 'multipart' => [  | 
            ||
| 166 | [  | 
            ||
| 167 | 'name' => 'file',  | 
            ||
| 168 | 'contents' => $stream,  | 
            ||
| 169 | ], [  | 
            ||
| 170 | 'name' => 'userId',  | 
            ||
| 171 | 'contents' => $userId,  | 
            ||
| 172 | ],  | 
            ||
| 173 | ],  | 
            ||
| 174 | ]);  | 
            ||
| 175 | /** @var Stream $body */  | 
            ||
| 176 | $body = $response->getBody();  | 
            ||
| 177 | $body = json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR);  | 
            ||
| 178 | |||
| 179 |             if (! empty($stream)) { | 
            ||
| 180 | File::delete($temp->getPathName());  | 
            ||
| 181 | }  | 
            ||
| 182 | |||
| 183 | return [  | 
            ||
| 184 | 'id' => $body['attachment']['id'],  | 
            ||
| 185 | 'url' => $body['attachment']['downloadURL'],  | 
            ||
| 195 |