Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ test-integration export-ignore
CHANGELOG.md export-ignore
docker-compose.yml export-ignore
indocker export-ignore
phpcs.xml export-ignore
mago.toml export-ignore
phpunit.xml.dist export-ignore
phpunit-integration.xml export-ignore
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]
## [3.2.0] - 2026-05-22
### Added
* *Nothing*

### Changed
* Update to PHPUnit 13
* Migrate form PHP_CodeSniffer to Mago for code linting and formatting.

### Deprecated
* *Nothing*
Expand Down
11 changes: 8 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
"psr/http-factory": "^1.1"
},
"require-dev": {
"carthage-software/mago": "^1.28",
"devster/ubench": "^2.1",
"guzzlehttp/guzzle": "^7.10",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpcov": "^12.0",
"phpunit/phpunit": "^13.0",
"shlinkio/php-coding-standard": "~2.5.0",
"shlinkio/shlink-mago-config": "^1.0",
"symfony/var-dumper": "^8.0"
},
"autoload": {
Expand All @@ -42,8 +43,12 @@
"@stan",
"@test:unit"
],
"cs": "phpcs",
"cs:fix": "phpcbf",
"lint": "mago lint",
"lint:fix": "mago lint --fix",
"format": "mago format",
"format:check": "mago format --check",
"cs": ["@lint", "@format:check"],
"cs:fix": ["@lint:fix", "@format"],
"stan": "phpstan analyse",
"test:unit": "phpunit --order-by=random --testdox --testdox-summary",
"test:unit:ci": [
Expand Down
20 changes: 20 additions & 0 deletions mago.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#:schema https://mago.carthage.software/1.27.1/schema.json
# Welcome to Mago!
# For full documentation, see https://mago.carthage.software/tools/overview
version = "1"
php-version = "8.4.0"
extends = "vendor/shlinkio/shlink-mago-config/mago.toml"

[source]
workspace = "."
paths = ["src", "test", "test-integration"]
excludes = ["vendor"]

[source.glob]
literal-separator = true

[linter.rules]
no-literal-password = { exclude = ["test"] }
no-empty-catch-clause = { exclude = ["test"] }
no-empty-loop = { exclude = ["test"] }
loop-does-not-iterate = { exclude = ["test"] }
16 changes: 0 additions & 16 deletions phpcs.xml

This file was deleted.

3 changes: 1 addition & 2 deletions src/Builder/ShlinkClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public function __construct(
private RequestFactoryInterface $requestFactory,
private StreamFactoryInterface $streamFactory,
private HttpDebuggerInterface|null $debugger = null,
) {
}
) {}

public function buildShortUrlsClient(ShlinkConfigInterface $config): ShortUrlsClientInterface
{
Expand Down
33 changes: 18 additions & 15 deletions src/Builder/SingletonShlinkClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,52 @@ class SingletonShlinkClientBuilder implements ShlinkClientBuilderInterface
{
private array $instances = [];

public function __construct(private readonly ShlinkClientBuilderInterface $wrapped)
{
}
public function __construct(private readonly ShlinkClientBuilderInterface $wrapped) {}

public function buildShortUrlsClient(ShlinkConfigInterface $config): ShortUrlsClientInterface
{
$key = $this->configToKey($config);
return $this->instances[ShortUrlsClientInterface::class][$key] ?? (
$this->instances[ShortUrlsClientInterface::class][$key] = $this->wrapped->buildShortUrlsClient($config)
return (
$this->instances[ShortUrlsClientInterface::class][$key] ?? ($this->instances[ShortUrlsClientInterface::class][$key] =
$this->wrapped->buildShortUrlsClient($config))
);
}

public function buildVisitsClient(ShlinkConfigInterface $config): VisitsClientInterface
{
$key = $this->configToKey($config);
return $this->instances[VisitsClientInterface::class][$key] ?? (
$this->instances[VisitsClientInterface::class][$key] = $this->wrapped->buildVisitsClient($config)
return (
$this->instances[VisitsClientInterface::class][$key] ?? ($this->instances[VisitsClientInterface::class][$key] =
$this->wrapped->buildVisitsClient($config))
);
}

public function buildTagsClient(ShlinkConfigInterface $config): TagsClientInterface
{
$key = $this->configToKey($config);
return $this->instances[TagsClientInterface::class][$key] ?? (
$this->instances[TagsClientInterface::class][$key] = $this->wrapped->buildTagsClient($config)
return (
$this->instances[TagsClientInterface::class][$key] ?? ($this->instances[TagsClientInterface::class][$key] =
$this->wrapped->buildTagsClient($config))
);
}

public function buildDomainsClient(ShlinkConfigInterface $config): DomainsClientInterface
{
$key = $this->configToKey($config);
return $this->instances[DomainsClientInterface::class][$key] ?? (
$this->instances[DomainsClientInterface::class][$key] = $this->wrapped->buildDomainsClient($config)
return (
$this->instances[DomainsClientInterface::class][$key] ?? ($this->instances[DomainsClientInterface::class][$key] =
$this->wrapped->buildDomainsClient($config))
);
}

public function buildRedirectRulesClient(ShlinkConfigInterface $config): RedirectRulesClientInterface
{
$key = $this->configToKey($config);
return $this->instances[RedirectRulesClientInterface::class][$key] ?? (
$this->instances[RedirectRulesClientInterface::class][$key] = $this->wrapped->buildRedirectRulesClient(
$config,
)
return (
$this->instances[RedirectRulesClientInterface::class][$key] ?? ($this->instances[RedirectRulesClientInterface::class][$key] =
$this->wrapped->buildRedirectRulesClient(
$config,
))
);
}

Expand Down
10 changes: 3 additions & 7 deletions src/Config/ArrayShlinkConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,15 @@
public const API_KEY_PROP = 'apiKey';
public const VERSION_PROP = 'version';

private function __construct(private ShlinkConfigInterface $wrapped)
{
}
private function __construct(private ShlinkConfigInterface $wrapped) {}

/**
* @throws InvalidConfigException
*/
public static function fromArray(array $config): self
{
return new self(ShlinkConfig::fromRawConfig(new class ($config) implements RawConfigInterface {
public function __construct(private readonly array $config)
{
}
return new self(ShlinkConfig::fromRawConfig(new class($config) implements RawConfigInterface {
public function __construct(private readonly array $config) {}

public function baseUrl(): string
{
Expand Down
10 changes: 3 additions & 7 deletions src/Config/EnvShlinkConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,16 @@
public const API_KEY_ENV_VAR = 'SHLINK_API_KEY';
public const VERSION_ENV_VAR = 'SHLINK_API_VERSION';

private function __construct(private ShlinkConfigInterface $wrapped)
{
}
private function __construct(private ShlinkConfigInterface $wrapped) {}

/**
* @throws InvalidConfigException
*/
public static function fromEnv(): self
{
$env = getenv();
return new self(ShlinkConfig::fromRawConfig(new class ($env) implements RawConfigInterface {
public function __construct(private readonly array $env)
{
}
return new self(ShlinkConfig::fromRawConfig(new class($env) implements RawConfigInterface {
public function __construct(private readonly array $env) {}

public function baseUrl(): string
{
Expand Down
4 changes: 1 addition & 3 deletions src/Config/ShlinkConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

final readonly class ShlinkConfig implements ShlinkConfigInterface
{
private function __construct(private string $baseUrl, private string $apiKey, private ApiVersion $version)
{
}
private function __construct(private string $baseUrl, private string $apiKey, private ApiVersion $version) {}

public static function fromBaseUrlAndApiKey(string $baseUrl, string $apiKey): ShlinkConfigInterface
{
Expand Down
4 changes: 1 addition & 3 deletions src/Domains/DomainsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

readonly class DomainsClient implements DomainsClientInterface
{
public function __construct(private HttpClientInterface $httpClient)
{
}
public function __construct(private HttpClientInterface $httpClient) {}

/**
* @inheritDoc
Expand Down
4 changes: 1 addition & 3 deletions src/Domains/Model/Domain.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@

final readonly class Domain
{
private function __construct(public string $domain, public bool $isDefault, public DomainRedirects $redirects)
{
}
private function __construct(public string $domain, public bool $isDefault, public DomainRedirects $redirects) {}

public static function fromArray(array $payload): self
{
Expand Down
3 changes: 1 addition & 2 deletions src/Domains/Model/DomainRedirects.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ private function __construct(
public string|null $baseUrlRedirect,
public string|null $regularNotFoundRedirect,
public string|null $invalidShortUrlRedirect,
) {
}
) {}

public static function fromArray(array $payload): self
{
Expand Down
4 changes: 1 addition & 3 deletions src/Domains/Model/DomainRedirectsConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

final class DomainRedirectsConfig implements JsonSerializable
{
private function __construct(private array $payload = [])
{
}
private function __construct(private array $payload = []) {}

public static function forDomain(string $domain): self
{
Expand Down
4 changes: 1 addition & 3 deletions src/Exception/ExceptionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@

use Throwable;

interface ExceptionInterface extends Throwable
{
}
interface ExceptionInterface extends Throwable {}
2 changes: 2 additions & 0 deletions src/Http/ApiVersion.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Shlinkio\Shlink\SDK\Http;

use function array_map;
Expand Down
2 changes: 2 additions & 0 deletions src/Http/ErrorType.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Shlinkio\Shlink\SDK\Http;

enum ErrorType: string
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Exception/HttpException.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static function fromPayload(array $payload): self
{
$additional = array_filter(
$payload,
static fn (string $key) => ! in_array($key, self::STANDARD_PROBLEM_DETAILS_PROPS, true),
static fn (string $key) => !in_array($key, self::STANDARD_PROBLEM_DETAILS_PROPS, true),
ARRAY_FILTER_USE_KEY,
);

Expand Down
9 changes: 4 additions & 5 deletions src/Http/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public function __construct(
private StreamFactoryInterface $streamFactory,
private ShlinkConfigInterface $config,
private HttpDebuggerInterface|null $debugger = null,
) {
}
) {}

/**
* @throws HttpException
Expand Down Expand Up @@ -63,16 +62,16 @@ private function callShlink(
array $query = [],
): array {
$uri = sprintf('%s/rest/v%s%s', $this->config->baseUrl(), $this->config->version()->value, $path);
if (! empty($query)) {
if (!empty($query)) {
$uri = sprintf('%s?%s', $uri, http_build_query($query));
}

$req = $this->requestFactory->createRequest($method, $uri)
->withHeader('X-Api-Key', $this->config->apiKey());
->withHeader('X-Api-Key', $this->config->apiKey());

if ($body !== null) {
$req = $req->withHeader('Content-Type', 'application/json')
->withBody($this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR)));
->withBody($this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR)));
}

$this->debugger?->debugRequest($req);
Expand Down
4 changes: 2 additions & 2 deletions src/Model/ListEndpointIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ private function getFullList(): iterable
}

$isLastPage = $currentPage < 0 || $currentPage === $this->currentPagination['pagesCount'];
if (! $isLastPage) {
if (!$isLastPage) {
$this->loadPage($currentPage + 1);
yield from $this->getFullList();
}
}

private function calculateIndex(int $index, int $currentPage): int
{
return ($currentPage - 1) * $this->itemsPerPage + $index;
return (($currentPage - 1) * $this->itemsPerPage) + $index;
}

public function count(): int
Expand Down
5 changes: 2 additions & 3 deletions src/RedirectRules/Model/RedirectCondition.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ private function __construct(
public string|null $matchValue = null,
public string|null $matchKey = null,
private string|null $originalType = null,
) {
}
) {}

public static function forQueryParam(string $param, string $value): self
{
Expand Down Expand Up @@ -77,7 +76,7 @@ public static function fromArray(array $payload): self
$originalType = $payload['type'] ?? '';
return new self(
type: RedirectConditionType::tryFrom($originalType) ?? RedirectConditionType::UNKNOWN,
matchValue: $payload['matchValue'] ?? null,
matchValue: $payload['matchValue'] ?? null,
matchKey: $payload['matchKey'] ?? null,
originalType: $originalType,
);
Expand Down
2 changes: 2 additions & 0 deletions src/RedirectRules/Model/RedirectConditionType.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Shlinkio\Shlink\SDK\RedirectRules\Model;

enum RedirectConditionType: string
Expand Down
6 changes: 2 additions & 4 deletions src/RedirectRules/Model/RedirectRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@
* @param RedirectCondition[] $conditions
* @param positive-int $priority
*/
private function __construct(public string $longUrl, public int $priority, public array $conditions)
{
}
private function __construct(public string $longUrl, public int $priority, public array $conditions) {}

public static function fromArray(array $payload): self
{
return new self(
longUrl: $payload['longUrl'] ?? '',
priority: max((int) ($payload['priority'] ?? 1), 1),
conditions: array_map(
static fn (array $condition) => RedirectCondition::fromArray($condition),
RedirectCondition::fromArray(...),
$payload['conditions'] ?? [],
),
);
Expand Down
Loading
Loading