Skip to content

Commit

Permalink
Merge pull request #138 from microsoft/dev
Browse files Browse the repository at this point in the history
v1.2.0
  • Loading branch information
SilasKenneth authored Mar 25, 2024
2 parents fd6b016 + ed31996 commit e065420
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @ddyett @MichaelMainer @nikithauc @zengin @silaskenneth @Ndiritu @shemogumbe
* @microsoft/kiota-write
2 changes: 1 addition & 1 deletion .github/workflows/auto-merge-dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1.6.0
uses: dependabot/fetch-metadata@v2.0.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3']
php-versions: ['7.4', '8.1', '8.2', '8.3']
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v4.1.1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

## [1.2.0]

### Added
- Add support for multipart request body. [#132](https://github.com/microsoft/kiota-abstractions-php/pull/132)

### Changed

## [1.1.0]

### Added
- Update stduritemplate/stduritemplate requirement from ^0.0.48 to ^0.0.48 || ^0.0.49 [#118](https://github.com/microsoft/kiota-abstractions-php/pull/118)
- Fix the promise dependency to promises v1.2 [#121](https://github.com/microsoft/kiota-abstractions-php/pull/121)
### Changed

## [1.0.2]

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ run `composer require microsoft/kiota-abstractions` or add the following to your
```Shell
{
"require": {
"microsoft/kiota-abstractions": "^1.0.2"
"microsoft/kiota-abstractions": "^1.2.0"
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"doctrine/annotations": "^1.13 || ^2.0",
"open-telemetry/sdk": "^1.0.0",
"ramsey/uuid": "^3 || ^4",
"stduritemplate/stduritemplate": "^0.0.53 || ^0.0.54",
"stduritemplate/stduritemplate": "^0.0.53 || ^0.0.54 || ^0.0.55",
"psr/http-message": "^1.1 || ^2.0"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion src/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

final class Constants
{
public const VERSION = '1.0.2';
public const VERSION = '1.2.0';
}
38 changes: 36 additions & 2 deletions src/Enum.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

use InvalidArgumentException;
use ReflectionException;
use RuntimeException;
use StdUriTemplate\StdUriTemplate;

/**
* Class Enum
Expand Down Expand Up @@ -67,7 +69,39 @@ public function __construct(string $value)
*/
public static function has($value): bool
{
return in_array($value, self::toArray(), true);
if (!is_string($value)) {
throw new InvalidArgumentException('The value is expected to be a string type.');
}
$array = array_values(self::toArray());

$isList = self::isList($array);
if (!$isList) {
throw new RuntimeException('Expect all values for the enums to be of the same type.');
}
if (count($array) > 0 && !is_string($array[0])) {
throw new RuntimeException('Enum values should be strings only.');
}
/** @phpstan-ignore-next-line */
return in_array(strtolower($value), array_map(fn ($item) => strtolower($item), self::toArray()), true);
}

/**
* @param array<mixed> $values
* @return bool
*/
private static function isList(array $values): bool
{
if (count($values) === 1 || empty($values)) {
return true;
}
$types = [];
foreach ($values as $value) {
$types[gettype($value)] = true;
}
if (count(array_keys($types)) > 1) {
return false;
}
return true;
}

/**
Expand Down Expand Up @@ -109,4 +143,4 @@ public function value(): string
{
return $this->_value;
}
}
}
149 changes: 149 additions & 0 deletions src/MultiPartBody.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

namespace Microsoft\Kiota\Abstractions;

use Exception;
use InvalidArgumentException;
use Microsoft\Kiota\Abstractions\Serialization\Parsable;
use Microsoft\Kiota\Abstractions\Serialization\SerializationWriter;
use Psr\Http\Message\StreamInterface;
use RuntimeException;

class MultiPartBody implements Parsable
{

/**
* @var array<string, array{string, mixed}>
*/
private array $parts = [];

private string $boundary;

private ?RequestAdapter $requestAdapter = null;

/**
* @throws Exception
*/
public function __construct()
{
$this->boundary = random_bytes(32);
}

/**
* @param RequestAdapter $requestAdapter
*/
public function setRequestAdapter(RequestAdapter $requestAdapter): void
{
$this->requestAdapter = $requestAdapter;
}

/**
* @inheritDoc
*/
public function getFieldDeserializers(): array
{
return [];
}

/**
* @inheritDoc
*/
public function serialize(SerializationWriter $writer): void
{
$first = count($this->parts) > 0;

foreach ($this->parts as $key => $value) {
if (!$first) {
$this->addNewLine($writer);
}
$partName = $key;
$partValue = $value[1];
$contentType = $value[0];
$writer->writeStringValue("", "--$this->boundary");
$writer->writeStringValue("Content-Type", $contentType);
$writer->writeStringValue("Content-Disposition", "form-data; name=\"$partName\"");
$this->addNewLine($writer);
if ($partValue instanceof Parsable) {
$this->writeParsable($writer, $contentType, $partValue);
}
elseif (is_string($partValue)) {
$writer->writeStringValue("", $partValue);
}
elseif ($partValue instanceof StreamInterface) {
$writer->writeBinaryContent("", $partValue);
$partValue->rewind();
}
else {
$type = gettype($partValue);
throw new InvalidArgumentException("Unsupported type {$type} for part {$partName}");
}
$first = false;
}
$this->addNewLine($writer);
$writer->writeStringValue("", "--$this->boundary--");
}

/**
* @param SerializationWriter $writer
* @param string $contentType
* @param Parsable $value
* @return void
*/

public function writeParsable(SerializationWriter $writer, string $contentType, Parsable $value): void
{
if ($this->requestAdapter === null) {
throw new RuntimeException('Request adapter cannot be null.');
}
$partWriter = $this->requestAdapter->getSerializationWriterFactory()->getSerializationWriter($contentType);
$partWriter->writeObjectValue("", $value);
$partContent = $partWriter->getSerializedContent();
$writer->writeBinaryContent('', $partContent);
$partContent->rewind();
}

private function addNewLine(SerializationWriter $writer): void
{
$writer->writeStringValue('', '');
}

/**
* @param string $partName
* @param string $contentType
* @param mixed $partValue
* @return void
*/
public function addOrReplacePart(string $partName, string $contentType, $partValue): void
{
if ($partValue === null) {
throw new RuntimeException('Part value can not be null.');
}
$this->parts[$partName] = [$contentType, $partValue];
}

/**
* @param string $partName
* @return mixed|null
*/
public function getPartValue(string $partName)
{
return $this->parts[$partName][1] ?? null;
}

public function removePart(string $partName): bool
{
if (array_key_exists($partName, $this->parts)) {
unset($this->parts[$partName]);
return true;
}
return false;
}

/**
* @return string
*/
public function getBoundary(): string
{
return $this->boundary;
}
}
6 changes: 6 additions & 0 deletions src/RequestInformation.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ public function setContentFromParsable(RequestAdapter $requestAdapter, string $c
$scope = $span->activate();
try {
$writer = $requestAdapter->getSerializationWriterFactory()->getSerializationWriter($contentType);

if (is_a($value, MultiPartBody::class)) {
$contentType = "$contentType; boundary={$value->getBoundary()}";
$value->setRequestAdapter($requestAdapter);
}

$writer->writeObjectValue(null, $value);
$span->setAttribute(ObservabilityOptions::REQUEST_TYPE_KEY, get_class($value));
$this->headers->tryAdd(self::$contentTypeHeader, $contentType);
Expand Down
43 changes: 43 additions & 0 deletions tests/MultiPartBodyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Microsoft\Kiota\Abstractions\Tests;

use Microsoft\Kiota\Abstractions\MultiPartBody;
use PHPUnit\Framework\TestCase;

class MultiPartBodyTest extends TestCase
{

public function testAddOrReplacePart(): void
{
$mpBody = new MultiPartBody();
$mpBody->addOrReplacePart('hello', 'text/plain', 'Hello world');
$this->assertEquals('Hello world', $mpBody->getPartValue('hello'));
$mpBody->addOrReplacePart('hello', 'text/plain', 'Second Hello World');
$this->assertEquals('Second Hello World', $mpBody->getPartValue('hello'));
}

public function testGetPartValue(): void
{
$mpBody = new MultiPartBody();
$mpBody->addOrReplacePart('hello', 'text/plain', 'Hello world');
$mpBody->addOrReplacePart('hello2', 'text/plain', 29102);
$this->assertEquals('Hello world', $mpBody->getPartValue('hello'));
$this->assertEquals(29102, $mpBody->getPartValue('hello2'));
}

public function testRemovePart(): void
{
$mpBody = new MultiPartBody();
$mpBody->addOrReplacePart('hello', 'text/plain', 'Hello world');
$mpBody->addOrReplacePart('hello2', 'text/plain', 29102);
$this->assertEquals('Hello world', $mpBody->getPartValue('hello'));
$mpBody->removePart('hello');
$this->assertNull($mpBody->getPartValue('hello'));
}
public function testGetFieldDeserializers(): void
{
$mpBody = new MultiPartBody();
$this->assertEmpty($mpBody->getFieldDeserializers());
}
}
3 changes: 2 additions & 1 deletion tests/RequestInformationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Microsoft\Kiota\Abstractions\Tests;
use DateTime;
use DateTimeZone;
use Exception;
use InvalidArgumentException;
use Microsoft\Kiota\Abstractions\Enum;
use Microsoft\Kiota\Abstractions\HttpMethod;
Expand Down Expand Up @@ -69,7 +70,7 @@ public function testWillThrowExceptionWhenNoBaseUrl(): void {

/**
* @throws InvalidArgumentException
* @throws \Exception
* @throws Exception
*/
public function testPathParametersOfDateTimeOffsetType(): void
{
Expand Down

0 comments on commit e065420

Please sign in to comment.