Skip to content

Commit a274140

Browse files
authored
Merge pull request #101 from dcblogdev/add-email-folders-endpoints
Add email folders endpoints
2 parents 8396b7c + 62460bd commit a274140

15 files changed

+464
-3
lines changed

src/MsGraph.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Dcblogdev\MsGraph\Events\NewMicrosoft365SignInEvent;
1010
use Dcblogdev\MsGraph\Models\MsGraphToken;
1111
use Dcblogdev\MsGraph\Resources\Contacts;
12-
use Dcblogdev\MsGraph\Resources\Emails;
12+
use Dcblogdev\MsGraph\Resources\Emails\Emails;
1313
use Dcblogdev\MsGraph\Resources\Files;
1414
use Dcblogdev\MsGraph\Resources\Sites;
1515
use Dcblogdev\MsGraph\Resources\Tasks\TaskLists;
@@ -340,7 +340,8 @@ protected function guzzle(string $type, string $request, array $data = [], array
340340
return $responseObject;
341341

342342
} catch (ClientException $e) {
343-
return json_decode(($e->getResponse()->getBody()->getContents()));
343+
throw new Exception($e->getMessage());
344+
//return json_decode(($e->getResponse()->getBody()->getContents()));
344345
} catch (Exception $e) {
345346
throw new Exception($e->getMessage());
346347
}

src/Resources/Emails.php renamed to src/Resources/Emails/Emails.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
<?php
22

3-
namespace Dcblogdev\MsGraph\Resources;
3+
namespace Dcblogdev\MsGraph\Resources\Emails;
44

55
use Dcblogdev\MsGraph\Facades\MsGraph;
66
use Exception;
77

88
class Emails extends MsGraph
99
{
10+
public function folders(): Folders
11+
{
12+
return new Folders;
13+
}
14+
1015
private string $top = '';
1116

1217
private string $skip = '';

src/Resources/Emails/Folders.php

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
namespace Dcblogdev\MsGraph\Resources\Emails;
4+
5+
use Dcblogdev\MsGraph\Facades\MsGraph;
6+
use Dcblogdev\MsGraph\Validators\EmailFolderCopyValidator;
7+
use Dcblogdev\MsGraph\Validators\EmailFolderStoreValidator;
8+
use Dcblogdev\MsGraph\Validators\EmailFolderUpdateValidator;
9+
use Dcblogdev\MsGraph\Validators\GraphQueryValidator;
10+
11+
class Folders extends MsGraph
12+
{
13+
public function get(array $params = [], bool $sort = false, array $priorityOrder = []): array
14+
{
15+
GraphQueryValidator::validate($params);
16+
17+
$queryString = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
18+
$url = 'me/mailFolders'.(! empty($queryString) ? "?$queryString" : '');
19+
20+
$folders = MsGraph::get($url);
21+
22+
if (! isset($folders['value'])) {
23+
return $folders;
24+
}
25+
26+
$allFolders = $this->fetchSubfolders($folders['value']);
27+
28+
if ($sort) {
29+
$allFolders = $this->sortFolders($allFolders, $priorityOrder);
30+
}
31+
32+
return array_merge($folders, ['value' => $allFolders]);
33+
}
34+
35+
public function find(string $id): array
36+
{
37+
return MsGraph::get('me/mailFolders/'.$id);
38+
}
39+
40+
public function store(array $data): array
41+
{
42+
EmailFolderStoreValidator::validate($data);
43+
44+
return MsGraph::post('me/mailFolders', $data);
45+
}
46+
47+
public function update(array $data, string $id): array
48+
{
49+
EmailFolderUpdateValidator::validate($data);
50+
51+
return MsGraph::patch('me/mailFolders/'.$id, $data);
52+
}
53+
54+
public function copy(array $data, string $id): array
55+
{
56+
EmailFolderCopyValidator::validate($data);
57+
58+
return MsGraph::post('me/mailFolders/'.$id.'/copy', $data);
59+
}
60+
61+
public function move(array $data, string $id): array
62+
{
63+
EmailFolderCopyValidator::validate($data);
64+
65+
return MsGraph::post('me/mailFolders/'.$id.'/copy', $data);
66+
}
67+
68+
public function delete(string $id): void
69+
{
70+
MsGraph::delete('me/mailFolders/'.$id);
71+
}
72+
73+
protected function fetchSubfolders(array $folders): array
74+
{
75+
foreach ($folders as &$folder) {
76+
$subfolders = MsGraph::get("me/mailFolders/{$folder['id']}/childFolders?\$top=500");
77+
$folder['subfolders'] = ! empty($subfolders['value']) ? $this->fetchSubfolders($subfolders['value']) : [];
78+
}
79+
80+
return $folders;
81+
}
82+
83+
protected function sortFolders(array $folders, array $priorityOrder = []): array
84+
{
85+
// Default folder priority if none provided
86+
$defaultPriority = [
87+
'Inbox' => 1,
88+
'Archive' => 2,
89+
'Drafts' => 3,
90+
'Sent Items' => 4,
91+
'Deleted Items' => 5,
92+
'Conversation History' => 6,
93+
'Junk Email' => 7,
94+
];
95+
96+
// Use provided priority order or fallback to default
97+
$priority = ! empty($priorityOrder) ? $priorityOrder : $defaultPriority;
98+
99+
usort($folders, function ($a, $b) use ($priority) {
100+
$aPriority = $priority[$a['displayName']] ?? 100;
101+
$bPriority = $priority[$b['displayName']] ?? 100;
102+
103+
return $aPriority === $bPriority
104+
? strcmp($a['displayName'], $b['displayName'])
105+
: $aPriority <=> $bPriority;
106+
});
107+
108+
// Sort subfolders recursively
109+
foreach ($folders as &$folder) {
110+
if (! empty($folder['subfolders'])) {
111+
$folder['subfolders'] = $this->sortFolders($folder['subfolders']);
112+
}
113+
}
114+
115+
return $folders;
116+
}
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class EmailFolderCopyValidator extends Validator
10+
{
11+
protected static array $allowedParams = [
12+
'destinationId',
13+
];
14+
15+
public static function validate(array $params): array
16+
{
17+
$validParams = parent::validate($params);
18+
19+
if (isset($validParams['destinationId']) && ! is_string($validParams['destinationId'])) {
20+
throw new InvalidArgumentException('The destinationId must be a string.');
21+
}
22+
23+
return $validParams;
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class EmailFolderMoveValidator extends Validator
10+
{
11+
protected static array $allowedParams = [
12+
'destinationId',
13+
];
14+
15+
public static function validate(array $params): array
16+
{
17+
$validParams = parent::validate($params);
18+
19+
if (isset($validParams['destinationId']) && ! is_string($validParams['destinationId'])) {
20+
throw new InvalidArgumentException('The destinationId must be a string.');
21+
}
22+
23+
return $validParams;
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class EmailFolderStoreValidator extends Validator
10+
{
11+
protected static array $allowedParams = [
12+
'displayName', 'isHidden',
13+
];
14+
15+
public static function validate(array $params): array
16+
{
17+
$validParams = parent::validate($params);
18+
19+
if (isset($validParams['displayName']) && ! is_string($validParams['displayName'])) {
20+
throw new InvalidArgumentException('The displayName must be a string.');
21+
}
22+
23+
if (isset($validParams['isHidden']) && ! is_bool($validParams['isHidden'])) {
24+
throw new InvalidArgumentException('The isHidden must be a boolean.');
25+
}
26+
27+
return $validParams;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class EmailFolderUpdateValidator extends Validator
10+
{
11+
protected static array $allowedParams = [
12+
'displayName',
13+
];
14+
15+
public static function validate(array $params): array
16+
{
17+
$validParams = parent::validate($params);
18+
19+
if (isset($validParams['displayName']) && ! is_string($validParams['displayName'])) {
20+
throw new InvalidArgumentException('The displayName must be a string.');
21+
}
22+
23+
return $validParams;
24+
}
25+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class GraphQueryValidator extends Validator
10+
{
11+
protected static array $allowedParams = [
12+
'$top', '$skip', '$filter', '$orderby', '$select', '$expand', '$count', '$search', '$format',
13+
];
14+
}

src/Validators/Validator.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dcblogdev\MsGraph\Validators;
6+
7+
use InvalidArgumentException;
8+
9+
class Validator
10+
{
11+
protected static array $allowedParams = [];
12+
13+
/**
14+
* Validate and filter parameters.
15+
*
16+
* @param array $params parameters to validate.
17+
* @return array Valid parameters.
18+
*
19+
* @throws InvalidArgumentException If invalid parameters are present.
20+
*/
21+
public static function validate(array $params): array
22+
{
23+
$allowedParams = static::$allowedParams;
24+
25+
// Filter out invalid parameters
26+
$validParams = array_intersect_key($params, array_flip($allowedParams));
27+
28+
// Identify invalid parameters
29+
$invalidParams = array_diff_key($params, $validParams);
30+
if (! empty($invalidParams)) {
31+
throw new InvalidArgumentException(sprintf(
32+
'Invalid parameters: %s. Allowed parameters: %s.',
33+
implode(', ', array_keys($invalidParams)),
34+
implode(', ', $allowedParams)
35+
));
36+
}
37+
38+
return $validParams;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use Dcblogdev\MsGraph\Validators\EmailFolderCopyValidator;
4+
5+
test('valid parameters are accepted', function () {
6+
$response = EmailFolderCopyValidator::validate([
7+
'destinationId' => 'demo'
8+
]);
9+
10+
expect($response)->toEqual([
11+
'destinationId' => 'demo'
12+
]);
13+
});
14+
15+
test('throws exception for unrecognized parameters', function () {
16+
EmailFolderCopyValidator::validate([
17+
'$top' => 10,
18+
]);
19+
})->throws(InvalidArgumentException::class, 'Invalid parameters: $top. Allowed parameters: destinationId.');
20+
21+
test('throws exception if destinationId is not a string', function () {
22+
EmailFolderCopyValidator::validate(['destinationId' => 1]);
23+
})->throws(InvalidArgumentException::class, 'The destinationId must be a string.');
24+
25+
test('allows empty input without throwing an exception', function () {
26+
$response = EmailFolderCopyValidator::validate([]);
27+
expect($response)->toBe([]);
28+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use Dcblogdev\MsGraph\Validators\EmailFolderMoveValidator;
4+
5+
test('valid parameters are accepted', function () {
6+
$response = EmailFolderMoveValidator::validate([
7+
'destinationId' => 'demo',
8+
]);
9+
10+
expect($response)->toEqual([
11+
'destinationId' => 'demo',
12+
]);
13+
});
14+
15+
test('throws exception for unrecognized parameters', function () {
16+
EmailFolderMoveValidator::validate([
17+
'$top' => 10,
18+
]);
19+
})->throws(InvalidArgumentException::class, 'Invalid parameters: $top. Allowed parameters: destinationId.');
20+
21+
test('throws exception if destinationId is not a string', function () {
22+
EmailFolderMoveValidator::validate(['destinationId' => 1]);
23+
})->throws(InvalidArgumentException::class, 'The destinationId must be a string.');
24+
25+
test('allows empty input without throwing an exception', function () {
26+
$response = EmailFolderMoveValidator::validate([]);
27+
expect($response)->toBe([]);
28+
});

0 commit comments

Comments
 (0)