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
3 changes: 3 additions & 0 deletions .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ jobs:
- name: Check release environment
run: |
bash ./bin/check-release-environment
env:
PACKAGIST_USERNAME: ${{ secrets.LEGALESIGN_SDK_PACKAGIST_USERNAME || secrets.PACKAGIST_USERNAME }}
PACKAGIST_SAFE_KEY: ${{ secrets.LEGALESIGN_SDK_PACKAGIST_SAFE_KEY || secrets.PACKAGIST_SAFE_KEY }}
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.0.2"
".": "0.1.0"
}
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## 0.1.0 (2025-11-05)

Full Changelog: [v0.0.2...v0.1.0](https://github.com/legalesign/legalesign-rest-php/compare/v0.0.2...v0.1.0)

### ⚠ BREAKING CHANGES

* remove confusing `toArray()` alias to `__serialize()` in favour of `toProperties()`

### Features

* remove confusing `toArray()` alias to `__serialize()` in favour of `toProperties()` ([bf37591](https://github.com/legalesign/legalesign-rest-php/commit/bf3759140c9a01bcb0fbe3146c287dc2b017b5dd))


### Bug Fixes

* **ci:** release doctor workflow ([310295d](https://github.com/legalesign/legalesign-rest-php/commit/310295d4faf056e60db3bea642b56ede1fbe94ae))
* ensure auth methods return non-nullable arrays ([50fd6a3](https://github.com/legalesign/legalesign-rest-php/commit/50fd6a367f425117f47c55fc4c45d1d484b2f2ae))
* inverted retry condition ([4dc29ef](https://github.com/legalesign/legalesign-rest-php/commit/4dc29ef02033890b21b15568dc0ddc46c2720d04))


### Chores

* add license ([3260f92](https://github.com/legalesign/legalesign-rest-php/commit/3260f921032f819561e6f7d92c4b22e2efb88604))
* **client:** send metadata headers ([e8c30b5](https://github.com/legalesign/legalesign-rest-php/commit/e8c30b5349cae440f50c79ed0a5652dbaf546baa))
* refactor methods ([9db1cb8](https://github.com/legalesign/legalesign-rest-php/commit/9db1cb856e0e6a5aac3e724c16f95f10ac28762e))
* use pascal case for phpstan typedefs ([be21370](https://github.com/legalesign/legalesign-rest-php/commit/be213708da8645553228ed4814d20d1b9292b443))

## 0.0.2 (2025-09-23)

Full Changelog: [v0.0.1...v0.0.2](https://github.com/legalesign/legalesign-rest-php/compare/v0.0.1...v0.0.2)
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"$schema": "https://getcomposer.org/schema.json",
"license": "Apache-2.0",
"autoload": {
"files": ["src/Core.php", "src/Client.php"],
"files": [
"src/Core.php",
"src/Client.php"
],
"psr-4": {
"LegalesignSDK\\": "src/"
}
Expand Down
3 changes: 2 additions & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
],
"release-type": "php",
"extra-files": [
"README.md"
"README.md",
"src/Client.php"
]
}
2 changes: 1 addition & 1 deletion scripts/lint
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ set -e
cd -- "$(dirname -- "$0")/.."

echo "==> Running PHPStan"
exec -- ./vendor/bin/phpstan analyse --memory-limit=1G
exec -- ./vendor/bin/phpstan analyse --memory-limit=2G
18 changes: 14 additions & 4 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
{
$this->apiKey = (string) ($apiKey ?? getenv('LEGALESIGN_SDK_API_KEY'));

$base = $baseUrl ?? getenv(
$baseUrl ??= getenv(
'LEGALESIGN_SDK_BASE_URL'
) ?: 'https://eu-api.legalesign.com/api/v1';

Expand All @@ -70,10 +70,20 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
);

parent::__construct(
// x-release-please-start-version
headers: [
'Content-Type' => 'application/json', 'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'User-Agent' => sprintf('legalesign-sdk/PHP %s', '0.1.0'),
'X-Stainless-Lang' => 'php',
'X-Stainless-Package-Version' => '0.1.0',
'X-Stainless-OS' => $this->getNormalizedOS(),
'X-Stainless-Arch' => $this->getNormalizedArchitecture(),
'X-Stainless-Runtime' => 'php',
'X-Stainless-Runtime-Version' => phpversion(),
],
baseUrl: $base,
// x-release-please-end
baseUrl: $baseUrl,
options: $options,
);

Expand All @@ -89,6 +99,6 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
/** @return array<string, string> */
protected function authHeaders(): array
{
return ['Authorization' => $this->apiKey];
return $this->apiKey ? ['Authorization' => $this->apiKey] : [];
}
}
68 changes: 57 additions & 11 deletions src/Core/BaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
* body: mixed,
* }
*/
class BaseClient
abstract class BaseClient
{
protected UriInterface $baseUrl;

Expand Down Expand Up @@ -77,14 +77,11 @@ public function request(
// @phpstan-ignore-next-line
$rsp = $this->sendRequest($opts, req: $request, data: $body, redirectCount: 0, retryCount: 0);

$decoded = Util::decodeContent($rsp);

if (!is_null($stream)) {
return new $stream(
convert: $convert,
request: $request,
response: $rsp,
stream: $decoded
response: $rsp
);
}

Expand All @@ -93,22 +90,69 @@ public function request(
convert: $convert,
client: $this,
request: $req,
response: $rsp,
options: $opts,
data: $decoded,
);
}

if (!is_null($convert)) {
return Conversion::coerce($convert, value: $decoded);
return Conversion::coerceResponse($convert, response: $rsp);
}

return $decoded;
return Util::decodeContent($rsp);
}

/** @return array<string, string> */
protected function authHeaders(): array
abstract protected function authHeaders(): array;

protected function getNormalizedOS(): string
{
return [];
$os = strtolower(PHP_OS_FAMILY);

switch ($os) {
case 'windows':
return 'Windows';

case 'darwin':
return 'MacOS';

case 'linux':
return 'Linux';

case 'bsd':
case 'freebsd':
case 'openbsd':
return 'BSD';

case 'solaris':
return 'Solaris';

case 'unix':
case 'unknown':
return 'Unknown';

default:
return 'Other:'.$os;
}
}

protected function getNormalizedArchitecture(): string
{
$arch = php_uname('m');
if (false !== strpos($arch, 'x86_64') || false !== strpos($arch, 'amd64')) {
return 'x64';
}
if (false !== strpos($arch, 'i386') || false !== strpos($arch, 'i686')) {
return 'x32';
}
if (false !== strpos($arch, 'aarch64') || false !== strpos($arch, 'arm64')) {
return 'arm64';
}
if (false !== strpos($arch, 'arm')) {
return 'arm';
}

return 'unknown';
}

/**
Expand Down Expand Up @@ -244,6 +288,8 @@ protected function sendRequest(
): ResponseInterface {
assert(null !== $opts->streamFactory && null !== $opts->transporter);

$req = $req->withHeader('X-Stainless-Retry-Count', strval($retryCount));

$req = Util::withSetBody($opts->streamFactory, req: $req, body: $data);

$rsp = null;
Expand All @@ -270,7 +316,7 @@ protected function sendRequest(
}

if ($code >= 400 || is_null($rsp)) {
if ($this->shouldRetry($opts, retryCount: $retryCount, rsp: $rsp)) {
if (!$this->shouldRetry($opts, retryCount: $retryCount, rsp: $rsp)) {
$exn = is_null($rsp) ? new APIConnectionException($req, previous: $err) : APIStatusException::from(request: $req, response: $rsp);

throw $exn;
Expand Down
12 changes: 7 additions & 5 deletions src/Core/Concerns/SdkModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ trait SdkModel
*/
public function __serialize(): array
{
$rows = [...Util::get_object_vars($this), ...$this->_data]; // @phpstan-ignore-line
$properties = $this->toProperties(); // @phpstan-ignore-line

return array_map(static fn ($v) => self::serialize($v), array: $rows);
return array_map(static fn ($v) => self::serialize($v), array: $properties);
}

/**
Expand Down Expand Up @@ -98,11 +98,13 @@ public function __get(string $key): mixed
}

/**
* @internal
*
* @return Shape
*/
public function toArray(): array
public function toProperties(): array
{
return $this->__serialize(); // @phpstan-ignore-line
return [...Util::get_object_vars($this), ...$this->_data]; // @phpstan-ignore-line
}

/**
Expand Down Expand Up @@ -257,7 +259,7 @@ private function initialize(): void
private static function serialize(mixed $value): mixed
{
if ($value instanceof BaseModel) {
return $value->toArray();
return $value->toProperties();
}

if (is_array($value)) {
Expand Down
29 changes: 29 additions & 0 deletions src/Core/Concerns/SdkResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace LegalesignSDK\Core\Concerns;

use LegalesignSDK\Core\Util;
use Psr\Http\Message\ResponseInterface;

/**
* @internal
* SdkResponse must only be used in conjunction with classes that use the SdkModel trait
*/
trait SdkResponse
{
private ?ResponseInterface $_rawResponse;

public static function fromResponse(ResponseInterface $response): static
{
$instance = new static;
$instance->_rawResponse = $response;
$instance->__unserialize(Util::decodeContent($response)); // @phpstan-ignore-line

return $instance;
}

public function getRawResponse(): ?ResponseInterface
{
return $this->_rawResponse;
}
}
2 changes: 1 addition & 1 deletion src/Core/Contracts/BaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
interface BaseModel extends \ArrayAccess, \JsonSerializable, \Stringable, ConverterSource
{
/** @return array<string, mixed> */
public function toArray(): array;
public function toProperties(): array;
}
3 changes: 2 additions & 1 deletion src/Core/Contracts/BasePage.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use LegalesignSDK\Core\Conversion\Contracts\Converter;
use LegalesignSDK\Core\Conversion\Contracts\ConverterSource;
use LegalesignSDK\RequestOptions;
use Psr\Http\Message\ResponseInterface;

/**
* @internal
Expand All @@ -30,7 +31,7 @@ public function __construct(
Client $client,
array $request,
RequestOptions $options,
mixed $data,
ResponseInterface $response,
);

public function hasNextPage(): bool;
Expand Down
4 changes: 0 additions & 4 deletions src/Core/Contracts/BaseStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@
*/
interface BaseStream extends \IteratorAggregate
{
/**
* @param \Generator<TInner> $stream
*/
public function __construct(
Converter|ConverterSource|string $convert,
RequestInterface $request,
ResponseInterface $response,
\Generator $stream,
);

/**
Expand Down
14 changes: 14 additions & 0 deletions src/Core/Conversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
use LegalesignSDK\Core\Conversion\CoerceState;
use LegalesignSDK\Core\Conversion\Contracts\Converter;
use LegalesignSDK\Core\Conversion\Contracts\ConverterSource;
use LegalesignSDK\Core\Conversion\Contracts\ResponseConverter;
use LegalesignSDK\Core\Conversion\DumpState;
use Psr\Http\Message\ResponseInterface;

/**
* @internal
*/
final class Conversion
{
public static function dump_unknown(mixed $value, DumpState $state): mixed
Expand Down Expand Up @@ -38,6 +43,15 @@ public static function dump_unknown(mixed $value, DumpState $state): mixed
return $value;
}

public static function coerceResponse(Converter|ConverterSource|string $target, ResponseInterface $response): mixed
{
if (is_a($target, ResponseConverter::class, allow_string: true)) {
return $target::fromResponse($response);
}

return self::coerce($target, Util::decodeContent($response));
}

public static function coerce(Converter|ConverterSource|string $target, mixed $value, CoerceState $state = new CoerceState): mixed
{
if ($value instanceof $target) {
Expand Down
18 changes: 18 additions & 0 deletions src/Core/Conversion/Contracts/ResponseConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace LegalesignSDK\Core\Conversion\Contracts;

use Psr\Http\Message\ResponseInterface;

/**
* @internal
*/
interface ResponseConverter
{
/**
* @internal
*/
public static function fromResponse(ResponseInterface $response): static;
}
2 changes: 1 addition & 1 deletion src/Core/Conversion/ModelOf.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function from(array $data): BaseModel
public function dump(mixed $value, DumpState $state): mixed
{
if ($value instanceof BaseModel) {
$value = $value->toArray();
$value = $value->toProperties();
}

if (is_array($value)) {
Expand Down
Loading
Loading