Skip to content

Commit ac11370

Browse files
authored
Merge pull request #13 from codebar-ag/feature-adding-exception-handling
Implemented Exceptions
2 parents 020f830 + 931ce74 commit ac11370

File tree

10 files changed

+442
-0
lines changed

10 files changed

+442
-0
lines changed

src/DTO/MFilesError.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodebarAg\MFiles\DTO;
6+
7+
use Illuminate\Support\Arr;
8+
9+
final class MFilesError
10+
{
11+
public function __construct(
12+
public readonly string $errorCode,
13+
public readonly int $status,
14+
public readonly string $url,
15+
public readonly string $method,
16+
public readonly string $exceptionName,
17+
public readonly string $exceptionMessage,
18+
public readonly ?string $stack,
19+
) {}
20+
21+
public static function fromArray(array $data): self
22+
{
23+
$exceptionData = Arr::get($data, 'Exception', []);
24+
25+
return new self(
26+
errorCode: Arr::get($data, 'ErrorCode', ''),
27+
status: Arr::get($data, 'Status', 0),
28+
url: Arr::get($data, 'URL', ''),
29+
method: Arr::get($data, 'Method', ''),
30+
exceptionName: Arr::get($exceptionData, 'Name', ''),
31+
exceptionMessage: Arr::get($exceptionData, 'Message', ''),
32+
stack: Arr::get($data, 'Stack'),
33+
);
34+
}
35+
36+
public function toArray(): array
37+
{
38+
return [
39+
'errorCode' => $this->errorCode,
40+
'status' => $this->status,
41+
'url' => $this->url,
42+
'method' => $this->method,
43+
'exceptionName' => $this->exceptionName,
44+
'exceptionMessage' => $this->exceptionMessage,
45+
'stack' => $this->stack,
46+
];
47+
}
48+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodebarAg\MFiles\Exceptions;
6+
7+
use CodebarAg\MFiles\DTO\MFilesError;
8+
use Exception as BaseException;
9+
10+
final class MFilesErrorException extends BaseException
11+
{
12+
public function __construct(
13+
public readonly MFilesError $error
14+
) {
15+
parent::__construct($error->exceptionMessage, $error->status);
16+
}
17+
}

src/Responses/DownloadFileResponse.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
namespace CodebarAg\MFiles\Responses;
66

77
use CodebarAg\MFiles\DTO\DownloadedFile;
8+
use CodebarAg\MFiles\Exceptions\MFilesErrorException;
89
use Saloon\Http\Response;
910

1011
final class DownloadFileResponse
1112
{
1213
public static function createDtoFromResponse(Response $response): DownloadedFile
1314
{
15+
if (! $response->successful()) {
16+
throw new MFilesErrorException(ErrorResponse::createDtoFromResponse($response));
17+
}
1418
$headers = $response->headers();
1519
$fileContentType = $headers->get('Content-Type');
1620
$fileSize = (int) $headers->get('Content-Length', 0);

src/Responses/ErrorResponse.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodebarAg\MFiles\Responses;
6+
7+
use CodebarAg\MFiles\DTO\MFilesError;
8+
use Saloon\Http\Response;
9+
10+
final class ErrorResponse
11+
{
12+
public static function createDtoFromResponse(Response $response): MFilesError
13+
{
14+
return MFilesError::fromArray($response->json());
15+
}
16+
}

src/Responses/LogInToVaultResponse.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44

55
namespace CodebarAg\MFiles\Responses;
66

7+
use CodebarAg\MFiles\Exceptions\MFilesErrorException;
78
use Illuminate\Support\Arr;
89
use Saloon\Http\Response;
910

1011
final class LogInToVaultResponse
1112
{
1213
public static function createDtoFromResponse(Response $response): ?string
1314
{
15+
if (! $response->successful()) {
16+
throw new MFilesErrorException(ErrorResponse::createDtoFromResponse($response));
17+
}
18+
1419
return Arr::get($response->json(), 'Value');
1520
}
1621
}

src/Responses/ObjectPropertiesResponse.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
namespace CodebarAg\MFiles\Responses;
66

77
use CodebarAg\MFiles\DTO\ObjectProperties;
8+
use CodebarAg\MFiles\Exceptions\MFilesErrorException;
89
use Saloon\Http\Response;
910

1011
final class ObjectPropertiesResponse
1112
{
1213
public static function createDtoFromResponse(Response $response): ObjectProperties
1314
{
15+
if (! $response->successful()) {
16+
throw new MFilesErrorException(ErrorResponse::createDtoFromResponse($response));
17+
}
18+
1419
return ObjectProperties::fromArray($response->json());
1520
}
1621
}

src/Responses/UploadFileResponse.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace CodebarAg\MFiles\Responses;
66

7+
use CodebarAg\MFiles\Exceptions\MFilesErrorException;
78
use Illuminate\Support\Arr;
89
use Illuminate\Support\Str;
910
use Saloon\Http\Response;
@@ -12,6 +13,10 @@ final class UploadFileResponse
1213
{
1314
public static function createDtoFromResponse(Response $response, string $fileName): array
1415
{
16+
if (! $response->successful()) {
17+
throw new MFilesErrorException(ErrorResponse::createDtoFromResponse($response));
18+
}
19+
1520
$data = $response->json();
1621
$data = Arr::add($data, 'Title', Str::beforeLast($fileName, '.'));
1722
$data = Arr::add($data, 'Extension', Str::afterLast($fileName, '.'));

tests/Unit/DTO/MFilesErrorTest.php

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use CodebarAg\MFiles\DTO\MFilesError;
6+
7+
it('creates instance with all properties', function () {
8+
$error = new MFilesError(
9+
errorCode: 'ERROR_001',
10+
status: 403,
11+
url: '/session/vaults',
12+
method: 'GET',
13+
exceptionName: 'UnauthorizedAccessException',
14+
exceptionMessage: 'Login to application failed',
15+
stack: 'Stack trace here'
16+
);
17+
18+
expect($error->errorCode)->toBe('ERROR_001');
19+
expect($error->status)->toBe(403);
20+
expect($error->url)->toBe('/session/vaults');
21+
expect($error->method)->toBe('GET');
22+
expect($error->exceptionName)->toBe('UnauthorizedAccessException');
23+
expect($error->exceptionMessage)->toBe('Login to application failed');
24+
expect($error->stack)->toBe('Stack trace here');
25+
});
26+
27+
it('creates instance with null stack', function () {
28+
$error = new MFilesError(
29+
errorCode: 'ERROR_002',
30+
status: 404,
31+
url: '/objects/123',
32+
method: 'GET',
33+
exceptionName: 'NotFoundException',
34+
exceptionMessage: 'Object not found',
35+
stack: null
36+
);
37+
38+
expect($error->stack)->toBeNull();
39+
});
40+
41+
it('creates instance from array with all properties', function () {
42+
$data = [
43+
'ErrorCode' => 'ERROR_003',
44+
'Status' => 500,
45+
'URL' => '/api/endpoint',
46+
'Method' => 'POST',
47+
'Exception' => [
48+
'Name' => 'InternalServerError',
49+
'Message' => 'Internal server error occurred',
50+
],
51+
'Stack' => 'Detailed stack trace',
52+
];
53+
54+
$error = MFilesError::fromArray($data);
55+
56+
expect($error->errorCode)->toBe('ERROR_003');
57+
expect($error->status)->toBe(500);
58+
expect($error->url)->toBe('/api/endpoint');
59+
expect($error->method)->toBe('POST');
60+
expect($error->exceptionName)->toBe('InternalServerError');
61+
expect($error->exceptionMessage)->toBe('Internal server error occurred');
62+
expect($error->stack)->toBe('Detailed stack trace');
63+
});
64+
65+
it('creates instance from array with missing optional fields', function () {
66+
$data = [
67+
'Status' => 400,
68+
'URL' => '/test',
69+
'Method' => 'GET',
70+
'Exception' => [
71+
'Name' => 'BadRequest',
72+
'Message' => 'Bad request',
73+
],
74+
];
75+
76+
$error = MFilesError::fromArray($data);
77+
78+
expect($error->errorCode)->toBe('');
79+
expect($error->status)->toBe(400);
80+
expect($error->url)->toBe('/test');
81+
expect($error->method)->toBe('GET');
82+
expect($error->exceptionName)->toBe('BadRequest');
83+
expect($error->exceptionMessage)->toBe('Bad request');
84+
expect($error->stack)->toBeNull();
85+
});
86+
87+
it('creates instance from array with empty exception object', function () {
88+
$data = [
89+
'ErrorCode' => 'ERROR_004',
90+
'Status' => 401,
91+
'URL' => '/auth',
92+
'Method' => 'POST',
93+
'Exception' => [],
94+
'Stack' => null,
95+
];
96+
97+
$error = MFilesError::fromArray($data);
98+
99+
expect($error->exceptionName)->toBe('');
100+
expect($error->exceptionMessage)->toBe('');
101+
});
102+
103+
it('converts instance to array correctly', function () {
104+
$error = new MFilesError(
105+
errorCode: 'ERROR_005',
106+
status: 422,
107+
url: '/validate',
108+
method: 'PUT',
109+
exceptionName: 'ValidationError',
110+
exceptionMessage: 'Validation failed',
111+
stack: 'Error stack'
112+
);
113+
114+
$array = $error->toArray();
115+
116+
expect($array)->toBe([
117+
'errorCode' => 'ERROR_005',
118+
'status' => 422,
119+
'url' => '/validate',
120+
'method' => 'PUT',
121+
'exceptionName' => 'ValidationError',
122+
'exceptionMessage' => 'Validation failed',
123+
'stack' => 'Error stack',
124+
]);
125+
});
126+
127+
it('converts instance to array with null stack', function () {
128+
$error = new MFilesError(
129+
errorCode: 'ERROR_006',
130+
status: 500,
131+
url: '/test',
132+
method: 'DELETE',
133+
exceptionName: 'ServerError',
134+
exceptionMessage: 'Server error',
135+
stack: null
136+
);
137+
138+
$array = $error->toArray();
139+
140+
expect($array['stack'])->toBeNull();
141+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use CodebarAg\MFiles\DTO\MFilesError;
6+
use CodebarAg\MFiles\Exceptions\MFilesErrorException;
7+
8+
it('creates exception with MFilesError', function () {
9+
$error = new MFilesError(
10+
errorCode: 'ERROR_001',
11+
status: 403,
12+
url: '/session/vaults',
13+
method: 'GET',
14+
exceptionName: 'UnauthorizedAccessException',
15+
exceptionMessage: 'Login to application failed',
16+
stack: 'Stack trace here'
17+
);
18+
19+
$exception = new MFilesErrorException($error);
20+
21+
expect($exception->error)->toBe($error);
22+
expect($exception->getMessage())->toBe('Login to application failed');
23+
expect($exception->getCode())->toBe(403);
24+
});
25+
26+
it('extends base Exception class', function () {
27+
$error = new MFilesError(
28+
errorCode: 'ERROR_002',
29+
status: 404,
30+
url: '/objects/123',
31+
method: 'GET',
32+
exceptionName: 'NotFoundException',
33+
exceptionMessage: 'Object not found',
34+
stack: null
35+
);
36+
37+
$exception = new MFilesErrorException($error);
38+
39+
expect($exception)->toBeInstanceOf(Exception::class);
40+
});
41+
42+
it('can access error properties through exception', function () {
43+
$error = new MFilesError(
44+
errorCode: 'ERROR_003',
45+
status: 500,
46+
url: '/api/endpoint',
47+
method: 'POST',
48+
exceptionName: 'InternalServerError',
49+
exceptionMessage: 'Internal server error occurred',
50+
stack: 'Detailed stack trace'
51+
);
52+
53+
$exception = new MFilesErrorException($error);
54+
55+
expect($exception->error->errorCode)->toBe('ERROR_003');
56+
expect($exception->error->status)->toBe(500);
57+
expect($exception->error->url)->toBe('/api/endpoint');
58+
expect($exception->error->method)->toBe('POST');
59+
expect($exception->error->exceptionName)->toBe('InternalServerError');
60+
expect($exception->error->exceptionMessage)->toBe('Internal server error occurred');
61+
expect($exception->error->stack)->toBe('Detailed stack trace');
62+
});

0 commit comments

Comments
 (0)