Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A PHP SDK for integrating with the [Veeam Service Provider Console (VSPC)](https
- Guzzle-based HTTP client preconfigured for the VSPC REST endpoints.
- Repository classes mirroring the API tags (Alarms, Authentication, Backup Agents, Backup Policies, Backup Server Jobs, Backup Servers, Cloud Connect, Companies, Licensing, Locations, Management Agents, Misc, Organizations, Provider, Pulse, Microsoft 365, and more).
- Fluent payload builders to compose request bodies for complex operations.
- `GenericPayload` helper to quickly serialize ad-hoc request bodies when a dedicated builder is not required.
- `GenericPayload` helper (via static factories) to quickly serialize ad-hoc request bodies when a dedicated builder is not required.
- Helpers for filters, pagination, and query parameters.
- Returns PSR-7 responses or decoded JSON payloads for convenience.

Expand Down Expand Up @@ -38,14 +38,19 @@ $client = new VeeamSPCClient(
```

### Authenticate and Fetch a Token
Use the `AuthenticationRepository` with the `OAuthPayload` helper to request an access token.
Use the `AuthenticationRepository` with the `CreateAuthenticationOAuthTokenPayload` helper to request an access token.

```php
use Shellrent\VeeamVspcApiClient\Payloads\OAuthPayload;
use Shellrent\VeeamVspcApiClient\Payloads\CreateAuthenticationOAuthTokenPayload;
use Shellrent\VeeamVspcApiClient\Repositories\AuthenticationRepository;

$authRepository = new AuthenticationRepository();
$request = $authRepository->postOAuthAuthentication(new OAuthPayload('username', 'password'));
$request = $authRepository->oAuth2IssueToken(
new CreateAuthenticationOAuthTokenPayload(
username: 'username',
password: 'password'
)
);

$tokenResponse = $client->jsonResponse($request);
$token = $tokenResponse->access_token ?? null;
Expand All @@ -68,13 +73,13 @@ $response = $client->jsonResponse($request);
Repositories accept optional filters and query parameters when executed through `VeeamSPCClient::send()` or `VeeamSPCClient::jsonResponse()`. You can build complex filters using `Filter` and `FilterCollection` helpers located under `Shellrent\VeeamVspcApiClient\Support`.

### Send an Ad-hoc JSON Body
When an endpoint requires a request body that does not yet have a dedicated payload builder, you can rely on the `GenericPayload` helper. Pass an array (automatically encoded as JSON) or a raw string together with the desired content type.
When an endpoint requires a request body that does not yet have a dedicated payload builder, you can rely on the `GenericPayload` helper. Use the provided static factories to pass an array (automatically encoded as JSON) or a raw string together with the desired content type.

```php
use Shellrent\VeeamVspcApiClient\Payloads\GenericPayload;
use Shellrent\VeeamVspcApiClient\Repositories\BackupPolicyRepository;

$payload = new GenericPayload([
$payload = GenericPayload::fromArray([
'Name' => 'My Custom Policy',
'Description' => 'Created through the SDK',
]);
Expand Down
2 changes: 2 additions & 0 deletions src/Payloads/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ Le classi in questa directory rappresentano i corpi delle richieste (`POST`, `PA
## Serializzazione
- Se crei nuovi payload assicurati che implementino `jsonSerialize()` oppure un metodo equivalente previsto dall'interfaccia.
- Quando un campo richiede una struttura annidata, usa array PHP standard rispettando esattamente la struttura definita nello swagger.
- Per payload JSON riutilizzabili preferisci estendere `AbstractJsonPayload` o `JsonPatchPayload`; sfrutta i factory method di `GenericPayload` solo per casi estremamente puntuali.
- Per i form `application/x-www-form-urlencoded` o `multipart/form-data` estendi rispettivamente `AbstractFormUrlEncodedPayload` o `AbstractMultipartFormDataPayload`.
22 changes: 22 additions & 0 deletions src/Payloads/AbstractFormUrlEncodedPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

abstract class AbstractFormUrlEncodedPayload extends GenericPayload {
public function __construct() {
parent::__construct('application/x-www-form-urlencoded');
}

final protected function serializeBody(): string {
return http_build_query($this->filterNullFields($this->formFields()));
}

abstract protected function formFields(): array;

protected function filterNullFields(array $fields): array {
return array_filter(
$fields,
static fn ($value): bool => $value !== null
);
}
}
17 changes: 17 additions & 0 deletions src/Payloads/AbstractJsonPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

use JsonSerializable;

abstract class AbstractJsonPayload extends GenericPayload implements JsonSerializable {
public function __construct() {
parent::__construct('application/json');
}

final protected function serializeBody(): string {
return self::encodeJson($this->jsonSerialize());
}

abstract public function jsonSerialize(): array;
}
40 changes: 40 additions & 0 deletions src/Payloads/AbstractLicenseUploadPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

abstract class AbstractLicenseUploadPayload extends AbstractMultipartFormDataPayload {
private ?string $licenseContents = null;
private ?string $licenseFilename = null;
private ?string $licenseContentType = null;

/**
* @param string $licenseContents Binary contents of the license file.
* @param string|null $filename Optional filename advertised in the multipart part.
* @param string|null $contentType Optional content type advertised in the multipart part.
*/
public function withLicense(string $licenseContents, ?string $filename = null, ?string $contentType = null): self {
$this->licenseContents = $licenseContents;
$this->licenseFilename = $filename;
$this->licenseContentType = $contentType;

return $this;
}

protected function formFields(): array {
if ($this->licenseContents === null) {
return [];
}

$field = ['contents' => $this->licenseContents];

if ($this->licenseFilename !== null) {
$field['filename'] = $this->licenseFilename;
}

if ($this->licenseContentType !== null) {
$field['contentType'] = $this->licenseContentType;
}

return ['license' => $field];
}
}
69 changes: 69 additions & 0 deletions src/Payloads/AbstractMultipartFormDataPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

abstract class AbstractMultipartFormDataPayload extends GenericPayload {
private string $boundary;

public function __construct(?string $boundary = null) {
$this->boundary = $boundary ?? $this->generateBoundary();

parent::__construct('multipart/form-data; boundary=' . $this->boundary);
}

final protected function serializeBody(): string {
$lines = [];

foreach ($this->formFields() as $name => $value) {
if ($value === null) {
continue;
}

$lines[] = '--' . $this->boundary;

$disposition = 'Content-Disposition: form-data; name="' . $name . '"';

if (is_array($value)) {
$contents = $value['contents'] ?? null;

if ($contents === null) {
continue;
}

if (isset($value['filename'])) {
$disposition .= '; filename="' . $value['filename'] . '"';
}

$lines[] = $disposition;

if (isset($value['contentType'])) {
$lines[] = 'Content-Type: ' . $value['contentType'];
}

$lines[] = '';
$lines[] = (string) $contents;

continue;
}

$lines[] = $disposition;
$lines[] = '';
$lines[] = (string) $value;
}

$lines[] = '--' . $this->boundary . '--';
$lines[] = '';

return implode("\r\n", $lines);
}

abstract protected function formFields(): array;

public function getBoundary(): string {
return $this->boundary;
}

private function generateBoundary(): string {
return '----shellrent-sdk-' . bin2hex(random_bytes(8));
}
}
114 changes: 0 additions & 114 deletions src/Payloads/AddLicenseToVCSPPulsePayload.php

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Shellrent\VeeamVspcApiClient\Payloads;

class CreateAuthenticationAsymmetricAlgorithmChallengePayload extends GenericPayload {
private string $publicKey;

public function __construct(string $publicKey, string $contentType = 'application/octet-stream') {
parent::__construct($contentType);
$this->publicKey = $publicKey;
}

public function setPublicKey(string $publicKey): self {
$this->publicKey = $publicKey;

return $this;
}

protected function serializeBody(): string {
return $this->publicKey;
}
}
Loading