Skip to content

Commit 36ce190

Browse files
authored
Merge pull request #117 from microsoftgraph/dev
2.0.0-RC9
2 parents 3ff351e + b2dafe4 commit 36ce190

File tree

10 files changed

+209
-21
lines changed

10 files changed

+209
-21
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @ddyett @MichaelMainer @nikithauc @zengin @silaskenneth @Ndiritu @shemogumbe
1+
* @microsoftgraph/msgraph-devx-php-write

src/GraphConstants.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class GraphConstants
2525
const REST_ENDPOINT = "https://graph.microsoft.com/";
2626

2727
// Define HTTP request constants
28-
const SDK_VERSION = "2.0.0-RC7";
28+
const SDK_VERSION = "2.0.0-RC8";
2929

3030
// Define error constants
3131
const MAX_PAGE_SIZE = 999;

src/Models/PageResult.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
namespace Microsoft\Graph\Core\Models;
44

5-
class PageResult
5+
use Microsoft\Kiota\Abstractions\Serialization\Parsable;
6+
use Microsoft\Kiota\Abstractions\Serialization\ParseNode;
7+
use Microsoft\Kiota\Abstractions\Serialization\SerializationWriter;
8+
9+
class PageResult implements Parsable
610
{
711
/** @var string|null $odataNextLink */
8-
private ?string $odataNextLink;
12+
private ?string $odataNextLink = null;
913
/** @var array<mixed>|null $value */
10-
private ?array $value;
14+
private ?array $value = null;
1115

1216
/**
1317
* @return string|null
@@ -36,4 +40,23 @@ public function setOdataNextLink(?string $nextLink): void{
3640
public function setValue(?array $value): void {
3741
$this->value = $value;
3842
}
43+
44+
public function createFromDiscriminatorValue(ParseNode $parseNode): PageResult
45+
{
46+
return new PageResult();
47+
}
48+
49+
public function getFieldDeserializers(): array
50+
{
51+
return [
52+
'@odata.nextLink' => fn (ParseNode $parseNode) => $this->setOdataNextLink($parseNode->getStringValue()),
53+
'value' => fn (ParseNode $parseNode) => $this->setValue($parseNode->getCollectionOfPrimitiveValues())
54+
];
55+
}
56+
57+
public function serialize(SerializationWriter $writer): void
58+
{
59+
$writer->writeStringValue('@odata.nextLink', $this->getOdataNextLink());
60+
$writer->writeAnyValue('value', $this->getValue());
61+
}
3962
}

src/Tasks/PageIterator.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class PageIterator
2626
private bool $hasNext = false;
2727
private int $pauseIndex;
2828
/**
29-
* @var array{class-string<T>, string} $constructorCallable
29+
* @var array{class-string<Parsable>, string} $constructorCallable
3030
*/
3131
private array $constructorCallable;
3232
/** @var RequestHeaders */
@@ -37,12 +37,18 @@ class PageIterator
3737
/**
3838
* @param Parsable|array<mixed>|object|null $response paged collection response
3939
* @param RequestAdapter $requestAdapter
40-
* @param array{class-string<T>,string} $constructorCallable The method to construct a paged response object.
40+
* @param array{class-string<Parsable>,string}|null $constructorCallable
41+
* The method to construct a paged response object.
4142
* @throws JsonException
4243
*/
43-
public function __construct($response, RequestAdapter $requestAdapter, array $constructorCallable)
44+
public function __construct($response, RequestAdapter $requestAdapter, ?array $constructorCallable = null)
4445
{
4546
$this->requestAdapter = $requestAdapter;
47+
if ($response instanceof Parsable && !$constructorCallable) {
48+
$constructorCallable = [get_class($response), 'createFromDiscriminatorValue'];
49+
} elseif ($constructorCallable === null) {
50+
$constructorCallable = [PageResult::class, 'createFromDiscriminatorValue'];
51+
}
4652
$this->constructorCallable = $constructorCallable;
4753
$this->pauseIndex = 0;
4854
$this->headers = new RequestHeaders();
@@ -131,8 +137,8 @@ public static function convertToPage($response): ?PageResult
131137

132138
$value = null;
133139
if (is_array($response)) {
134-
$value = $response['value'];
135-
} elseif (is_object($response) && is_a($response, Parsable::class) &&
140+
$value = $response['value'] ?? ['value' => []];
141+
} elseif ($response instanceof Parsable &&
136142
method_exists($response, 'getValue')) {
137143
$value = $response->getValue();
138144
} elseif (is_object($response)) {
@@ -143,11 +149,10 @@ public static function convertToPage($response): ?PageResult
143149
throw new InvalidArgumentException('The response does not contain a value.');
144150
}
145151

146-
$parsablePage = (is_object($response) && is_a($response, Parsable::class)) ? $response : json_decode(json_encode($response,JSON_THROW_ON_ERROR), true);
152+
$parsablePage = ($response instanceof Parsable) ? $response : json_decode(json_encode($response, JSON_THROW_ON_ERROR), true);
147153
if (is_array($parsablePage)) {
148154
$page->setOdataNextLink($parsablePage['@odata.nextLink'] ?? '');
149-
} elseif (is_object($parsablePage) &&
150-
is_a($parsablePage, Parsable::class) &&
155+
} elseif ($parsablePage instanceof Parsable &&
151156
method_exists($parsablePage, 'getOdataNextLink')) {
152157
$page->setOdataNextLink($parsablePage->getOdataNextLink());
153158
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Microsoft\Graph\Core\Test\Authentication;
4+
5+
use Microsoft\Graph\Core\Authentication\GraphPhpLeagueAccessTokenProvider;
6+
use Microsoft\Kiota\Authentication\Oauth\ClientCredentialContext;
7+
use PHPUnit\Framework\TestCase;
8+
9+
class GraphPhpLeagueAccessTokenProviderTest extends TestCase
10+
{
11+
public function testSuccessfullyInitializesClass(): void
12+
{
13+
$context = new ClientCredentialContext('tenant', 'clientId', 'secret');
14+
$leagueAccessTokenProvider = new GraphPhpLeagueAccessTokenProvider($context, []);
15+
$this->assertNotEmpty($leagueAccessTokenProvider->getAllowedHostsValidator()->getAllowedHosts());
16+
}
17+
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Microsoft\Graph\Core\Test\Authentication;
4+
5+
use Microsoft\Graph\Core\Authentication\GraphPhpLeagueAccessTokenProvider;
6+
use Microsoft\Graph\Core\Authentication\GraphPhpLeagueAuthenticationProvider;
7+
use Microsoft\Kiota\Authentication\Oauth\ClientCredentialContext;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class GraphPhpLeagueAuthenticationProviderTest extends TestCase
11+
{
12+
public function testSuccessfullyInitializesClass(): void
13+
{
14+
$context = new ClientCredentialContext('tenant', 'clientId', 'secret');
15+
$leagueAuthProvider = new GraphPhpLeagueAuthenticationProvider($context, []);
16+
$this->assertNotEmpty($leagueAuthProvider->getAccessTokenProvider()->getAllowedHostsValidator()->getAllowedHosts());
17+
}
18+
}

tests/Middleware/GraphTelemetryHandlerTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22

33
namespace Microsoft\Graph\Core\Core\Test\Middleware;
44

5+
use GuzzleHttp\Exception\GuzzleException;
56
use GuzzleHttp\Handler\MockHandler;
67
use GuzzleHttp\HandlerStack;
78
use GuzzleHttp\Psr7\Response;
9+
use GuzzleHttp\Psr7\Utils;
810
use Microsoft\Graph\Core\GraphConstants;
911
use Microsoft\Graph\Core\GraphClientFactory;
1012
use Microsoft\Graph\Core\Middleware\GraphMiddleware;
1113
use Microsoft\Graph\Core\Middleware\Option\GraphTelemetryOption;
14+
use Microsoft\Kiota\Http\Middleware\Options\CompressionOption;
1215
use PHPUnit\Framework\TestCase;
1316
use Psr\Http\Message\RequestInterface;
17+
use Psr\Http\Message\ResponseInterface;
1418

1519
class GraphTelemetryHandlerTest extends TestCase
1620
{
@@ -107,4 +111,39 @@ private function executeMockRequestWithGraphTelemetryHandler(array $mockResponse
107111
$guzzleClient = GraphClientFactory::createWithMiddleware($handlerStack);
108112
return $guzzleClient->get("/", $requestOptions);
109113
}
114+
/**
115+
* @throws GuzzleException
116+
*/
117+
public function testRequestOptionsOverrideForCompression(): void
118+
{
119+
$compressionOption = new CompressionOption([CompressionOption::gzip()]);
120+
$requestOptions = [
121+
CompressionOption::class => $compressionOption,
122+
'body' => Utils::streamFor("{Some JSOn}")
123+
];
124+
$mockResponse = [
125+
function (RequestInterface $request) {
126+
$this->assertTrue($request->hasHeader('Content-Encoding'));
127+
$this->assertEquals("gzip", $request->getHeaderLine('Content-Encoding'));
128+
return new Response(200);
129+
}
130+
];
131+
$this->executeMockRequestWithCompressionHandler($mockResponse, $compressionOption, $requestOptions);
132+
}
133+
/**
134+
* @param array<mixed> $mockResponses
135+
* @param CompressionOption|null $compressionOption
136+
* @param array<string, mixed> $requestOptions
137+
* @return ResponseInterface
138+
* @throws GuzzleException
139+
*/
140+
private function executeMockRequestWithCompressionHandler(array $mockResponses, ?CompressionOption $compressionOption = null, array $requestOptions = []): ResponseInterface
141+
{
142+
$mockHandler = new MockHandler($mockResponses);
143+
$handlerStack = new HandlerStack($mockHandler);
144+
$handlerStack->push(GraphMiddleware::compression($compressionOption));
145+
146+
$guzzleClient = GraphClientFactory::createWithMiddleware($handlerStack);
147+
return $guzzleClient->post("/", $requestOptions);
148+
}
110149
}

tests/Models/PageResultTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Microsoft\Graph\Core\Test\Models;
4+
5+
use Microsoft\Graph\Core\Models\PageResult;
6+
use Microsoft\Kiota\Serialization\Json\JsonSerializationWriter;
7+
use Microsoft\Kiota\Serialization\Json\JsonSerializationWriterFactory;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class PageResultTest extends TestCase
11+
{
12+
public function testCanSetAndGetValues(): void {
13+
$pageResult = new PageResult();
14+
$writer = (new JsonSerializationWriterFactory())->getSerializationWriter('application/json');
15+
$pageResult->setValue([['name' => 'Kenny'], ['name' => 'James']]);
16+
$this->assertCount(2, $pageResult->getValue());
17+
$pageResult->setOdataNextLink('nextPage');
18+
$this->assertEquals('nextPage', $pageResult->getOdataNextLink());
19+
$pageResult->serialize($writer);
20+
21+
$this->assertEquals('"@odata.nextLink":"nextPage","value":[{"name":"Kenny"},{"name":"James"}]', $writer->getSerializedContent()->getContents());
22+
}
23+
}

tests/Tasks/PageIteratorTest.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use GuzzleHttp\Exception\GuzzleException;
77
use GuzzleHttp\Handler\MockHandler;
88
use GuzzleHttp\HandlerStack;
9+
use GuzzleHttp\Promise\Promise;
910
use GuzzleHttp\Psr7\Response;
1011
use GuzzleHttp\Psr7\Utils;
1112
use Http\Promise\FulfilledPromise;
@@ -24,6 +25,7 @@ class PageIteratorTest extends TestCase
2425
private Client $testClient;
2526
private RequestAdapter $mockRequestAdapter;
2627
private RequestInformation $requestInfoMock;
28+
private ?array $nextPageContent = null;
2729
private $firstPageContent;
2830

2931
/**
@@ -104,7 +106,7 @@ protected function setUp(): void {
104106
}
105107
';
106108
$this->mockRequestAdapter->method('sendAsync')
107-
->willReturn($usersPage);
109+
->willReturn(($this->nextPageContent !== null ? new FulfilledPromise($this->nextPageContent) : $usersPage));
108110
$this->mock = new MockHandler([
109111
new Response(200, ['X-Foo' => 'Bar'], $firstPageData),
110112
]);
@@ -119,7 +121,7 @@ protected function setUp(): void {
119121
public function testHandlerCanWork(): void {
120122
$pageIterator = new PageIterator($this->firstPageContent, $this->mockRequestAdapter, [UsersResponse::class, 'createFromDiscriminator']);
121123
$count = 0;
122-
$pageIterator->iterate(function ($value) use (&$count) {
124+
$pageIterator->iterate(function () use (&$count) {
123125
$count++;
124126
return true;
125127
});
@@ -147,6 +149,10 @@ public function testCanResumeIteration(): void{
147149
$this->assertEquals(4, $count);
148150
}
149151

152+
/**
153+
* @throws \JsonException
154+
* @throws \Exception
155+
*/
150156
public function testCanPauseIteration(): void {
151157
$pageIterator = new PageIterator($this->firstPageContent, $this->mockRequestAdapter, [UsersResponse::class, 'createFromDiscriminator']);
152158
$count = 0;
@@ -179,4 +185,43 @@ public function testCanDeserializeUsingCallback(): void {
179185

180186
$this->assertInstanceOf(User::class, $usersArray[0]);
181187
}
188+
189+
/**
190+
* @throws \Exception
191+
*/
192+
public function testCanPaginateWithoutCallableClass(): void {
193+
$pageIterator = new PageIterator($this->firstPageContent, $this->mockRequestAdapter);
194+
$count = 0;
195+
$usersArray = [];
196+
$pageIterator->iterate(function ($value) use (&$count,&$usersArray) {
197+
$parseNode = new JsonParseNode($value);
198+
/** @var User $user */
199+
$user = $parseNode->getObjectValue([User::class, 'createFromDiscriminator']);
200+
$usersArray []= $user;
201+
$count++;
202+
return true;
203+
});
204+
205+
$this->assertInstanceOf(User::class, $usersArray[0]);
206+
}
207+
208+
/**
209+
* @throws \JsonException
210+
* @throws \Exception
211+
*/
212+
public function testCanGetFromParsablePageObject(): void
213+
{
214+
$parsable = (new JsonParseNode($this->firstPageContent))->getObjectValue([UsersResponse::class, 'createFromDiscriminator']);
215+
$pageIterator = new PageIterator($parsable, $this->mockRequestAdapter, [UsersResponse::class, 'createFromDiscriminator']);
216+
$count = 0;
217+
$this->nextPageContent = [];
218+
$data = [];
219+
$pageIterator->iterate(static function($value) use (&$count, &$data) {
220+
$data []= $value;
221+
$count++;
222+
return $count < 2;
223+
});
224+
$this->assertEquals(2, $count);
225+
$this->assertInstanceOf(User::class, $data[0]);
226+
}
182227
}

tests/Tasks/UsersResponse.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,32 @@
88

99
class UsersResponse implements Parsable
1010
{
11-
public ?string $nextLink = null;
11+
public ?string $odataNextLink = null;
12+
/** @phpstan-ignore-next-line */
1213
public ?array $value = null;
1314
public function getFieldDeserializers(): array
1415
{
1516
return [
16-
'@odata.nextLink' => fn (ParseNode $p) => $this->setNextLink($p->getStringValue()),
17+
'@odata.nextLink' => fn (ParseNode $p) => $this->setOdataNextLink($p->getStringValue()),
1718
'value' => fn (ParseNode $p) => $this->setValue($p->getCollectionOfObjectValues([User::class, 'createFromDiscriminator']))
1819
];
1920
}
2021

2122
public function serialize(SerializationWriter $writer): void
2223
{
23-
$writer->writeStringValue('@odata.nextLink', $this->nextLink);
24+
$writer->writeStringValue('@odata.nextLink', $this->odataNextLink);
2425
$writer->writeCollectionOfObjectValues('value', $this->value);
2526
}
2627

2728
/**
2829
* @param string|null $nextLink
2930
*/
30-
public function setNextLink(?string $nextLink): void {
31-
$this->nextLink = $nextLink;
31+
public function setOdataNextLink(?string $nextLink): void {
32+
$this->odataNextLink = $nextLink;
3233
}
3334

3435
/**
35-
* @param array|null $value
36+
* @param array<mixed>|null $value
3637
*/
3738
public function setValue(?array $value): void {
3839
$this->value = $value;
@@ -41,4 +42,20 @@ public function setValue(?array $value): void {
4142
public static function createFromDiscriminator(ParseNode $parseNode): UsersResponse {
4243
return new UsersResponse();
4344
}
45+
46+
/**
47+
* @return string|null
48+
*/
49+
public function getOdataNextLink(): ?string
50+
{
51+
return $this->odataNextLink;
52+
}
53+
54+
/**
55+
* @return array<mixed>|null
56+
*/
57+
public function getValue(): ?array
58+
{
59+
return $this->value;
60+
}
4461
}

0 commit comments

Comments
 (0)