refactor: use Dto class instead of array

This commit is contained in:
Maël Gangloff
2025-03-03 15:12:38 +01:00
parent f882435b81
commit f0c9b94754
8 changed files with 79 additions and 58 deletions

View File

@@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Serializer\Exception\ExceptionInterface; use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class ConnectorController extends AbstractController class ConnectorController extends AbstractController
{ {
@@ -22,6 +23,7 @@ class ConnectorController extends AbstractController
private readonly LoggerInterface $logger, private readonly LoggerInterface $logger,
#[Autowire(service: 'service_container')] #[Autowire(service: 'service_container')]
private readonly ContainerInterface $locator, private readonly ContainerInterface $locator,
private readonly NormalizerInterface $normalizer,
) { ) {
} }
@@ -74,7 +76,11 @@ class ConnectorController extends AbstractController
/** @var AbstractProvider $providerClient */ /** @var AbstractProvider $providerClient */
$providerClient = $this->locator->get($provider->getConnectorProvider()); $providerClient = $this->locator->get($provider->getConnectorProvider());
$connector->setAuthData($providerClient->authenticate($connector->getAuthData())); $authData = $this->normalizer->normalize($providerClient->authenticate($connector->getAuthData()), 'json');
if (!is_array($authData)) {
throw new BadRequestHttpException('Authentication data cannot be normalized.');
}
$connector->setAuthData((array) $authData);
$this->logger->info('User {username} authentication data with the {provider} provider has been validated.', [ $this->logger->info('User {username} authentication data with the {provider} provider has been validated.', [
'username' => $user->getUserIdentifier(), 'username' => $user->getUserIdentifier(),

View File

@@ -16,4 +16,7 @@ final class AutodnsProviderDto extends DefaultProviderDto
public bool $ownerConfirm; public bool $ownerConfirm;
public int $context = 4; public int $context = 4;
#[Assert\NotBlank]
public string $contactid;
} }

View File

@@ -25,12 +25,9 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
#[Autoconfigure(public: true)] #[Autoconfigure(public: true)]
abstract class AbstractProvider abstract class AbstractProvider
{ {
/** /** @var class-string */
* @var class-string
*/
protected string $dtoClass = DefaultProviderDto::class; protected string $dtoClass = DefaultProviderDto::class;
protected DefaultProviderDto $authData;
protected array $authData;
public function __construct( public function __construct(
protected CacheItemPoolInterface $cacheItemPool, protected CacheItemPoolInterface $cacheItemPool,
@@ -46,12 +43,12 @@ abstract class AbstractProvider
* *
* @param array $authData raw authentication data as supplied by the user * @param array $authData raw authentication data as supplied by the user
* *
* @return array a cleaned up version of the authentication data * @return DefaultProviderDto a cleaned up version of the authentication data
* *
* @throws HttpException when the user does not accept the necessary conditions * @throws HttpException when the user does not accept the necessary conditions
* @throws ExceptionInterface * @throws ExceptionInterface
*/ */
private function verifyAuthData(array $authData): array private function verifyAuthData(array $authData): DefaultProviderDto
{ {
/** @var DefaultProviderDto $data */ /** @var DefaultProviderDto $data */
$data = $this->serializer->denormalize($this->verifyLegalAuthData($authData), $this->dtoClass); $data = $this->serializer->denormalize($this->verifyLegalAuthData($authData), $this->dtoClass);
@@ -61,12 +58,7 @@ abstract class AbstractProvider
throw new BadRequestHttpException((string) $violations); throw new BadRequestHttpException((string) $violations);
} }
return [ return $data;
...$this->serializer->normalize($data),
'acceptConditions' => $authData['acceptConditions'],
'ownerLegalAge' => $authData['ownerLegalAge'],
'waiveRetractationPeriod' => $authData['waiveRetractationPeriod'],
];
} }
/** /**
@@ -135,7 +127,7 @@ abstract class AbstractProvider
* @throws ExceptionInterface * @throws ExceptionInterface
* @throws \Exception * @throws \Exception
*/ */
public function authenticate(array $authData): array public function authenticate(array $authData): DefaultProviderDto
{ {
$this->authData = $this->verifyAuthData($authData); $this->authData = $this->verifyAuthData($authData);
$this->assertAuthentication(); $this->assertAuthentication();

View File

@@ -3,6 +3,7 @@
namespace App\Service\Connector; namespace App\Service\Connector;
use App\Dto\Connector\AutodnsProviderDto; use App\Dto\Connector\AutodnsProviderDto;
use App\Dto\Connector\DefaultProviderDto;
use App\Entity\Domain; use App\Entity\Domain;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemPoolInterface;
@@ -26,6 +27,9 @@ class AutodnsProvider extends AbstractProvider
{ {
protected string $dtoClass = AutodnsProviderDto::class; protected string $dtoClass = AutodnsProviderDto::class;
/** @var AutodnsProviderDto */
protected DefaultProviderDto $authData;
public function __construct( public function __construct(
CacheItemPoolInterface $cacheItemPool, CacheItemPoolInterface $cacheItemPool,
DenormalizerInterface&NormalizerInterface $serializer, DenormalizerInterface&NormalizerInterface $serializer,
@@ -59,22 +63,22 @@ class AutodnsProvider extends AbstractProvider
'POST', 'POST',
'/v1/domain', '/v1/domain',
(new HttpOptions()) (new HttpOptions())
->setAuthBasic($this->authData['username'], $this->authData['password']) ->setAuthBasic($this->authData->username, $this->authData->password)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setHeader('X-Domainrobot-Context', $this->authData['context']) ->setHeader('X-Domainrobot-Context', (string) $this->authData->context)
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->setJson([ ->setJson([
'name' => $ldhName, 'name' => $ldhName,
'ownerc' => [ 'ownerc' => [
'id' => $this->authData['contactid'], 'id' => $this->authData->contactid,
], ],
'adminc' => [ 'adminc' => [
'id' => $this->authData['contactid'], 'id' => $this->authData->contactid,
], ],
'techc' => [ 'techc' => [
'id' => $this->authData['contactid'], 'id' => $this->authData->contactid,
], ],
'confirmOrder' => $this->authData['ownerConfirm'], 'confirmOrder' => $this->authData->ownerConfirm,
'nameServers' => [ 'nameServers' => [
[ [
'name' => 'a.ns14.net', 'name' => 'a.ns14.net',
@@ -115,9 +119,9 @@ class AutodnsProvider extends AbstractProvider
'POST', 'POST',
'/v1/zone/_search?keys=name', '/v1/zone/_search?keys=name',
(new HttpOptions()) (new HttpOptions())
->setAuthBasic($authData['username'], $authData['password']) ->setAuthBasic($authData->username, $authData->password)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setHeader('X-Domainrobot-Context', $authData['context']) ->setHeader('X-Domainrobot-Context', (string) $authData->context)
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->setJson([ ->setJson([
'filters' => [ 'filters' => [
@@ -140,14 +144,14 @@ class AutodnsProvider extends AbstractProvider
'POST', 'POST',
'/v1/zone', '/v1/zone',
(new HttpOptions()) (new HttpOptions())
->setAuthBasic($authData['username'], $authData['password']) ->setAuthBasic($authData->username, $authData->password)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setHeader('X-Domainrobot-Context', $authData['context']) ->setHeader('X-Domainrobot-Context', (string) $authData->context)
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->setJson([ ->setJson([
'origin' => $ldhName, 'origin' => $ldhName,
'main' => [ 'main' => [
'address' => $authData['dns_ip'], 'address' => null, // $authData['dns_ip'],
], ],
'soa' => [ 'soa' => [
'refresh' => 3600, 'refresh' => 3600,
@@ -205,9 +209,9 @@ class AutodnsProvider extends AbstractProvider
'GET', 'GET',
'/v1/hello', '/v1/hello',
(new HttpOptions()) (new HttpOptions())
->setAuthBasic($this->authData['username'], $this->authData['password']) ->setAuthBasic($this->authData->username, $this->authData->password)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setHeader('X-Domainrobot-Context', $this->authData['context']) ->setHeader('X-Domainrobot-Context', (string) $this->authData->context)
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->toArray() ->toArray()
); );

View File

@@ -2,6 +2,7 @@
namespace App\Service\Connector; namespace App\Service\Connector;
use App\Dto\Connector\DefaultProviderDto;
use App\Dto\Connector\GandiProviderDto; use App\Dto\Connector\GandiProviderDto;
use App\Entity\Domain; use App\Entity\Domain;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
@@ -26,6 +27,9 @@ class GandiProvider extends AbstractProvider
{ {
protected string $dtoClass = GandiProviderDto::class; protected string $dtoClass = GandiProviderDto::class;
/** @var GandiProviderDto */
protected DefaultProviderDto $authData;
private const BASE_URL = 'https://api.gandi.net'; private const BASE_URL = 'https://api.gandi.net';
public function __construct( public function __construct(
@@ -52,14 +56,14 @@ class GandiProvider extends AbstractProvider
} }
$user = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions()) $user = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions())
->setAuthBearer($this->authData['token']) ->setAuthBearer($this->authData->token)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->toArray() ->toArray()
)->toArray(); )->toArray();
$httpOptions = (new HttpOptions()) $httpOptions = (new HttpOptions())
->setAuthBearer($this->authData['token']) ->setAuthBearer($this->authData->token)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->setHeader('Dry-Run', $dryRun ? '1' : '0') ->setHeader('Dry-Run', $dryRun ? '1' : '0')
@@ -80,9 +84,9 @@ class GandiProvider extends AbstractProvider
'tld_period' => 'golive', 'tld_period' => 'golive',
]); ]);
if (array_key_exists('sharingId', $this->authData)) { if ($this->authData->sharingId) {
$httpOptions->setQuery([ $httpOptions->setQuery([
'sharing_id' => $this->authData['sharingId'], 'sharing_id' => $this->authData->sharingId,
]); ]);
} }
@@ -100,7 +104,7 @@ class GandiProvider extends AbstractProvider
protected function assertAuthentication(): void protected function assertAuthentication(): void
{ {
$response = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions()) $response = $this->client->request('GET', '/v5/organization/user-info', (new HttpOptions())
->setAuthBearer($this->authData['token']) ->setAuthBearer($this->authData->token)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->toArray() ->toArray()
@@ -121,7 +125,7 @@ class GandiProvider extends AbstractProvider
protected function getSupportedTldList(): array protected function getSupportedTldList(): array
{ {
$response = $this->client->request('GET', '/v5/domain/tlds', (new HttpOptions()) $response = $this->client->request('GET', '/v5/domain/tlds', (new HttpOptions())
->setAuthBearer($this->authData['token']) ->setAuthBearer($this->authData->token)
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->toArray())->toArray(); ->toArray())->toArray();

View File

@@ -2,6 +2,7 @@
namespace App\Service\Connector; namespace App\Service\Connector;
use App\Dto\Connector\DefaultProviderDto;
use App\Dto\Connector\NameComProviderDto; use App\Dto\Connector\NameComProviderDto;
use App\Entity\Domain; use App\Entity\Domain;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
@@ -24,6 +25,9 @@ class NameComProvider extends AbstractProvider
{ {
protected string $dtoClass = NameComProviderDto::class; protected string $dtoClass = NameComProviderDto::class;
/** @var NameComProviderDto */
protected DefaultProviderDto $authData;
public function __construct( public function __construct(
CacheItemPoolInterface $cacheItemPool, CacheItemPoolInterface $cacheItemPool,
private readonly HttpClientInterface $client, private readonly HttpClientInterface $client,
@@ -56,7 +60,7 @@ class NameComProvider extends AbstractProvider
'/v4/domains', '/v4/domains',
(new HttpOptions()) (new HttpOptions())
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setAuthBasic($this->authData['username'], $this->authData['token']) ->setAuthBasic($this->authData->username, $this->authData->token)
->setBaseUri($dryRun ? self::DEV_BASE_URL : self::BASE_URL) ->setBaseUri($dryRun ? self::DEV_BASE_URL : self::BASE_URL)
->setJson([ ->setJson([
'domain' => [ 'domain' => [
@@ -103,7 +107,7 @@ class NameComProvider extends AbstractProvider
'/v4/hello', '/v4/hello',
(new HttpOptions()) (new HttpOptions())
->setHeader('Accept', 'application/json') ->setHeader('Accept', 'application/json')
->setAuthBasic($this->authData['username'], $this->authData['token']) ->setAuthBasic($this->authData->username, $this->authData->token)
->setBaseUri($this->kernel->isDebug() ? self::DEV_BASE_URL : self::BASE_URL) ->setBaseUri($this->kernel->isDebug() ? self::DEV_BASE_URL : self::BASE_URL)
->toArray() ->toArray()
); );

View File

@@ -2,6 +2,7 @@
namespace App\Service\Connector; namespace App\Service\Connector;
use App\Dto\Connector\DefaultProviderDto;
use App\Dto\Connector\NamecheapProviderDto; use App\Dto\Connector\NamecheapProviderDto;
use App\Entity\Domain; use App\Entity\Domain;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
@@ -23,6 +24,9 @@ class NamecheapProvider extends AbstractProvider
{ {
protected string $dtoClass = NamecheapProviderDto::class; protected string $dtoClass = NamecheapProviderDto::class;
/** @var NamecheapProviderDto */
protected DefaultProviderDto $authData;
public const BASE_URL = 'https://api.namecheap.com/xml.response'; public const BASE_URL = 'https://api.namecheap.com/xml.response';
public const SANDBOX_BASE_URL = 'https://api.sandbox.namecheap.com/xml.response'; public const SANDBOX_BASE_URL = 'https://api.sandbox.namecheap.com/xml.response';
@@ -88,9 +92,9 @@ class NamecheapProvider extends AbstractProvider
{ {
$actualParams = array_merge([ $actualParams = array_merge([
'Command' => $command, 'Command' => $command,
'UserName' => $this->authData['ApiUser'], 'UserName' => $this->authData->ApiUser,
'ApiUser' => $this->authData['ApiUser'], 'ApiUser' => $this->authData->ApiUser,
'ApiKey' => $this->authData['ApiKey'], 'ApiKey' => $this->authData->ApiKey,
'ClientIp' => $this->outgoingIp, 'ClientIp' => $this->outgoingIp,
], $parameters); ], $parameters);

View File

@@ -2,6 +2,7 @@
namespace App\Service\Connector; namespace App\Service\Connector;
use App\Dto\Connector\DefaultProviderDto;
use App\Dto\Connector\OvhProviderDto; use App\Dto\Connector\OvhProviderDto;
use App\Entity\Domain; use App\Entity\Domain;
use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ClientException;
@@ -21,6 +22,9 @@ class OvhProvider extends AbstractProvider
{ {
protected string $dtoClass = OvhProviderDto::class; protected string $dtoClass = OvhProviderDto::class;
/** @var OvhProviderDto */
protected DefaultProviderDto $authData;
public const REQUIRED_ROUTES = [ public const REQUIRED_ROUTES = [
[ [
'method' => 'GET', 'method' => 'GET',
@@ -68,19 +72,19 @@ class OvhProvider extends AbstractProvider
throw new \InvalidArgumentException('Domain name cannot be null'); throw new \InvalidArgumentException('Domain name cannot be null');
} }
$acceptConditions = $this->authData['acceptConditions']; $acceptConditions = $this->authData->acceptConditions;
$ownerLegalAge = $this->authData['ownerLegalAge']; $ownerLegalAge = $this->authData->ownerLegalAge;
$waiveRetractationPeriod = $this->authData['waiveRetractationPeriod']; $waiveRetractationPeriod = $this->authData->waiveRetractationPeriod;
$conn = new Api( $conn = new Api(
$this->authData['appKey'], $this->authData->appKey,
$this->authData['appSecret'], $this->authData->appSecret,
$this->authData['apiEndpoint'], $this->authData->apiEndpoint,
$this->authData['consumerKey'] $this->authData->consumerKey,
); );
$cart = $conn->post('/order/cart', [ $cart = $conn->post('/order/cart', [
'ovhSubsidiary' => $this->authData['ovhSubsidiary'], 'ovhSubsidiary' => $this->authData->ovhSubsidiary,
'description' => 'Domain Watchdog', 'description' => 'Domain Watchdog',
]); ]);
$cartId = $cart['cartId']; $cartId = $cart['cartId'];
@@ -90,8 +94,8 @@ class OvhProvider extends AbstractProvider
]); ]);
$pricingModes = ['create-default']; $pricingModes = ['create-default'];
if ('create-default' !== $this->authData['pricingMode']) { if ('create-default' !== $this->authData->pricingMode) {
$pricingModes[] = $this->authData['pricingMode']; $pricingModes[] = $this->authData->pricingMode;
} }
$offer = array_filter($offers, fn ($offer) => 'create' === $offer['action'] $offer = array_filter($offers, fn ($offer) => 'create' === $offer['action']
@@ -140,10 +144,10 @@ class OvhProvider extends AbstractProvider
protected function assertAuthentication(): void protected function assertAuthentication(): void
{ {
$conn = new Api( $conn = new Api(
$this->authData['appKey'], $this->authData->appKey,
$this->authData['appSecret'], $this->authData->appSecret,
$this->authData['apiEndpoint'], $this->authData->apiEndpoint,
$this->authData['consumerKey'], $this->authData->consumerKey,
); );
try { try {
@@ -186,14 +190,14 @@ class OvhProvider extends AbstractProvider
protected function getSupportedTldList(): array protected function getSupportedTldList(): array
{ {
$conn = new Api( $conn = new Api(
$this->authData['appKey'], $this->authData->appKey,
$this->authData['appSecret'], $this->authData->appSecret,
$this->authData['apiEndpoint'], $this->authData->apiEndpoint,
$this->authData['consumerKey'] $this->authData->consumerKey,
); );
return $conn->get('/domain/extensions', [ return $conn->get('/domain/extensions', [
'ovhSubsidiary' => $this->authData['ovhSubsidiary'], 'ovhSubsidiary' => $this->authData->ovhSubsidiary,
]); ]);
} }