Commit 18c61b7f authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Source avec connexion de type API : un ApiService personnel (implémentant...

Source avec connexion de type API : un ApiService personnel (implémentant ApiServiceInterface) peut être spécifié via la clé 'api_service'.
parent 2f3dff74
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
        "laminas/laminas-cli": "^1.14",
        "monolog/monolog": "^2.8",
        "ramsey/uuid": "^3.0",
        "unicaen/api": "dev-master",
        "unicaen/livelog": "^4.0",
        "unicaen/privilege": "^6.0",
        "webmozart/assert": "^1.3"
+85 −193
Original line number Diff line number Diff line
@@ -2,50 +2,14 @@

namespace UnicaenDbImport\Connection;

use Laminas\Hydrator\ClassMethodsHydrator;
use GuzzleHttp\Client;
use Webmozart\Assert\Assert;

class ApiConnection
{
    /**
     * @var string
     */
    private $url;
    /**
     * @var boolean|array
     */
    private $proxy = false;
    /**
     * @var boolean
     */
    private $verify = false;
    /**
     * @var string
     */
    private $user;
    /**
     * @var string
     */
    private $password;

    /**
     * @var string
     */
    private $pageParam = 'page';

    /**
     * @var string
     */
    private $pageSizeParam = 'page_size';

    /**
     * @var int
     */
    private $timeout = 0;

    /**
     * @var int
     */
    private $connectTimeout = 0;
    private ?Client $client = null;
    private string $pageParam = 'page';
    private string $pageSizeParam = 'page_size';

    /**
     * @param array $config
@@ -53,216 +17,144 @@ class ApiConnection
     */
    public static function fromArrayConfig(array $config): self
    {
        $inst = new static();

        $h = new ClassMethodsHydrator();
        $h->hydrate($config, $inst);

        return $inst;
        return new static($config);
    }

    /**
     * @return array
     */
    public function toArray(): array
    protected function __construct(array $config)
    {
        $h = new ClassMethodsHydrator();

        return $h->extract($this);
        if (array_key_exists('page_param', $config)) {
            $this->pageParam = $config['page_param'];
            unset($config['page_param']);
        }

    /**
     * @return string
     */
    public function getUrl(): string
    {
        return $this->url;
        if (array_key_exists('page_size_param', $config)) {
            $this->pageSizeParam = $config['page_size_param'];
            unset($config['page_size_param']);
        }

    /**
     * @param string $url
     * @return ApiConnection
     */
    public function setUrl(string $url): ApiConnection
    {
        $this->url = $url;
        return $this;
        // Client API fourni dans la config ?
        $client = $config['client'] ?? null;
        if ($client !== null) {
            Assert::isInstanceOf($client, Client::class);
            unset($config['client']);
            Assert::isEmpty($config, "Si la clé de config 'client' est présente, aucune autre clé ne peut être spécifiée");
        } else {
            $clientConfig = $this->prepareClientConfig($config);
            $client = new Client($clientConfig);
        }

    /**
     * @return bool|array
     */
    public function getProxy()
    {
        return $this->proxy;
        $this->client = $client;
    }

    /**
     * Met l'option de config sous la forme littérale.
     *
     * Si l'option est un tableau du genre :
     *    ```
     *    ['http' => 'proxy.unicaen.fr:3128', 'https' => 'proxy.unicaen.fr:3128', 'no' => ['localhost', '.unicaen.fr']],
     *    ```
     * le résultat est :
     *    ```
     *    HTTP: proxy.unicaen.fr:3128
     *    HTTPS: proxy.unicaen.fr:3128
     *    NO: localhost, .unicaen.fr
     *    ```
     *
     * @return string
     */
    public function getProxyToString(): string
    public function getClient(): Client
    {
        if (is_array($this->proxy)) {
            $proxy = $this->proxy;

            return array_reduce(array_keys($proxy), function($previous, $key) use ($proxy) {
                $value = is_array($proxy[$key]) ? implode(', ', $proxy[$key]) : $proxy[$key];
                return $previous . strtoupper($key) . ': ' . $value . PHP_EOL;
            }, '');
        }

        return $this->proxy;
        return $this->client;
    }

    /**
     * @param bool|array $proxy
     * @return ApiConnection
     */
    public function setProxy($proxy): ApiConnection
    protected function prepareClientConfig(array $config): array
    {
        $this->proxy = $proxy;
        return $this;
    }
        $baseUri =  $config['base_uri'] ?? $config['url'] ?? null;
        Assert::notNull($baseUri, "Clé 'base_uri' ou 'url' requise");

    /**
     * @return bool
     */
    public function getVerify(): bool
    {
        return $this->verify;
    }
        $preparedConfig = [
            'base_uri' => $baseUri,
            'headers' => [
                'Accept' => 'application/json',
            ],
        ];

    /**
     * @param bool $verify
     * @return ApiConnection
     */
    public function setVerify(bool $verify = true): ApiConnection
    {
        $this->verify = $verify;
        return $this;
        if (array_key_exists('user', $config)) {
            $preparedConfig['auth'] = [
                $config['user'],
                $config['password']
            ];
        }

    /**
     * @return string
     */
    public function getUser(): ?string
    {
        return $this->user;
        if (array_key_exists('verify', $config)) {
            $preparedConfig['verify'] = $config['verify'];
        }

    /**
     * @param string|null $user
     * @return ApiConnection
     */
    public function setUser(string $user = null): ApiConnection
    {
        $this->user = $user;
        return $this;
        if (array_key_exists('timeout', $config)) {
            $preparedConfig['timeout'] = $config['timeout'];
        }

    /**
     * @return string
     */
    public function getPassword(): ?string
    {
        return $this->password;
        if (array_key_exists('connect_timeout', $config)) {
            $preparedConfig['connect_timeout'] = $config['connect_timeout'];
        }
        if (array_key_exists('proxy', $config)) {
            $preparedConfig['proxy'] = $config['proxy'];
        } else {
            $preparedConfig['proxy'] = ['no' => 'localhost'];
        }

    /**
     * @param string|null $password
     * @return ApiConnection
     */
    public function setPassword(string $password = null): ApiConnection
    {
        $this->password = $password;
        return $this;
        return $preparedConfig;
    }

    /**
     * @return string
     */
    public function getPageParam(): string
    {
        return $this->pageParam;
    }

    /**
     * @param string $pageParam
     * @return ApiConnection
     */
    public function setPageParam(string $pageParam): ApiConnection
    public function setPageParam(string $pageParam): static
    {
        $this->pageParam = $pageParam;

        return $this;
    }

    /**
     * @return string
     */
    public function getPageSizeParam(): string
    {
        return $this->pageSizeParam;
    }

    /**
     * @param string $pageSizeParam
     * @return ApiConnection
     */
    public function setPageSizeParam(string $pageSizeParam): ApiConnection
    public function setPageSizeParam(string $pageSizeParam): static
    {
        $this->pageSizeParam = $pageSizeParam;

        return $this;
    }


    /**
     * @return int
     * @return bool|array
     * @deprecated Utiliser$this->client->getConfig('proxy')
     */
    public function getTimeout(): int
    public function getProxy(): bool|array
    {
        return $this->timeout;
        return $this->client->getConfig('proxy');
    }

    /**
     * @param int $timeout
     * @return self
     * Met l'option de config sous la forme littérale.
     *
     * Si l'option est un tableau du genre :
     *    ```
     *    ['http' => 'proxy.unicaen.fr:3128', 'https' => 'proxy.unicaen.fr:3128', 'no' => ['localhost', '.unicaen.fr']],
     *    ```
     * le résultat est :
     *    ```
     *    HTTP: proxy.unicaen.fr:3128
     *    HTTPS: proxy.unicaen.fr:3128
     *    NO: localhost, .unicaen.fr
     *    ```
     *
     * @return string
     */
    public function setTimeout(int $timeout): self
    public function getProxyToString(): string
    {
        $this->timeout = $timeout;
        return $this;
        $proxy = $this->client->getConfig('proxy');

        if (is_array($proxy)) {
            return array_reduce(array_keys($proxy), function($previous, $key) use ($proxy) {
                $value = is_array($proxy[$key]) ? implode(', ', $proxy[$key]) : $proxy[$key];
                return $previous . strtoupper($key) . ': ' . $value . PHP_EOL;
            }, '');
        }

    /**
     * @return int
     */
    public function getConnectTimeout(): int
    {
        return $this->connectTimeout;
        return $proxy;
    }

    /**
     * @param int $connectTimeout
     * @return self
     */
    public function setConnectTimeout(int $connectTimeout): self
    public function getUser(): ?string
    {
        $this->connectTimeout = $connectTimeout;
        return $this;
    }
        $auth = $this->client->getConfig('auth') ?? [];

        return $auth[0] ?? null;
    }
}
 No newline at end of file
+28 −5
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ use Assert\AssertionFailedException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Connection as DbConnection;
use Psr\Container\ContainerInterface;
use UnicaenApi\ApiClientPluginManager;
use UnicaenDbImport\Config\ColumnValueFilterConfigFactoryTrait;
use UnicaenDbImport\Config\ConfigException;
use UnicaenDbImport\Connection\ApiConnection;
@@ -18,6 +19,7 @@ use UnicaenDbImport\Domain\Source;
use UnicaenDbImport\Domain\SynchroInterface;
use UnicaenDbImport\Filter\ColumnName\ArrayMapColumnNameFilter;
use UnicaenDbImport\Filter\ColumnName\ColumnNameFilterInterface;
use UnicaenDbImport\Service\Api\ApiServiceInterface;
use UnicaenDbImport\Service\Api\Response\DataExtractor\ResponseDataExtractorInterface;
use UnicaenDbImport\Service\Api\Response\DataExtractor\ResponseDataExtractorPluginManager;
use Webmozart\Assert\Assert;
@@ -133,6 +135,20 @@ abstract class AbstractPluginManager extends \Laminas\ServiceManager\AbstractPlu
            $sourceConfig[$key] = $service->getSelects();
        }

        // Un ApiService autonome peut être spécifié via la clé 'api_service'
        $apiService = $sourceConfig[$key = 'api_service'] ?? null;
        if ($apiService && is_string($apiService) && $this->container->has($apiService)) {
            $serviceName = $apiService;
            $service = $this->container->get($serviceName);
            if (!$service instanceof ApiServiceInterface) {
                throw ConfigException::invalidValueForKey(
                    $key,
                    "Service implémentant " . ApiServiceInterface::class
                );
            }
            $sourceConfig[$key] = $service;
        }

        $dataExtractor = $sourceConfig['data_extractor'] ?? null;
        if ($dataExtractor && is_string($dataExtractor)) {
            $sourceConfig['data_extractor'] = $this->getDataExtractorInstance($dataExtractor, 'data_extractor');
@@ -250,18 +266,25 @@ abstract class AbstractPluginManager extends \Laminas\ServiceManager\AbstractPlu
    private function createConnection(array|string $value): DbConnection|ApiConnection
    {
        if (!is_string($value) && !is_array($value)) {
            throw new ConfigException("Une connection ne peut être créée qu partir d'une string ou d'un array");
            throw new ConfigException("Une connection ne peut être spécifiée que par une string ou un array");
        }

        if (is_string($value)) {
            $connectionName = $value;
            /** @var DbConnection $conn */
            $conn = $this->container->get($connectionName);
        } else {
            $conn = ApiConnection::fromArrayConfig($value);
            return $this->container->get($connectionName);
        }

        return $conn;
        $config = $value;
        if (array_key_exists('client', $config) && is_string($config['client'])) {
            // un client API peut être spécifié dans la config (par son nom)
            /** @var \UnicaenApi\ApiClientPluginManager $apiClientPluginManager */
            $apiClientPluginManager = $this->container->get(ApiClientPluginManager::class);
            $client = $apiClientPluginManager->getClient($config['client']);
            $config['client'] = $client;
        }

        return ApiConnection::fromArrayConfig($config);
    }

    /**
+19 −2
Original line number Diff line number Diff line
@@ -15,7 +15,9 @@ use UnicaenDbImport\Connection\ApiConnection;
use UnicaenDbImport\Connection\NoConnection;
use UnicaenDbImport\Filter\ColumnName\ColumnNameFilterInterface;
use UnicaenDbImport\Filter\ColumnValue\ColumnValueFilterInterface;
use UnicaenDbImport\Service\Api\ApiServiceInterface;
use UnicaenDbImport\Service\Api\Response\DataExtractor\ResponseDataExtractorInterface;
use Webmozart\Assert\Assert;

class Source implements SourceInterface
{
@@ -89,6 +91,14 @@ class Source implements SourceInterface
        return $this->config->get('code');
    }

    /**
     * {@inheritDoc}
     */
    public function getApiService(): ?ApiServiceInterface
    {
        return $this->config->get('api_service');
    }

    /**
     * {@inheritDoc}
     */
@@ -274,6 +284,10 @@ class Source implements SourceInterface
            }
        }

        if ($apiService = $this->config->get($key = 'api_service')) {
            Assert::implementsInterface($apiService, ApiServiceInterface::class, "Une instance de %s est requise pour la clé suivante : $key");
        }

        if ($this->config->offsetExists($key = 'columns')) {
            (new AssertionChain($this->config->get($key), "Un tableau non vide contenant uniquement des chaînes de caractères est requis pour la clé suivante: $key"))
                ->isArray()
@@ -292,8 +306,11 @@ class Source implements SourceInterface
        if ($table && $select) {
            throw ConfigException::exclusiveKeys(['table', 'select']);
        }
        if (!$table && !$select) {
            throw ConfigException::atLeastOneKey(['table', 'select']);
        if (($table && $apiService) || ($select && $apiService)) {
            throw ConfigException::exclusiveKeys(['table', 'select', 'api_service']);
        }
        if (!$table && !$select && !$apiService) {
            throw ConfigException::atLeastOneKey(['table', 'select', 'api_service']);
        }

        if ($where = $this->config->get($key = 'where'))
+6 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ use UnicaenDbImport\Connection\ApiConnection;
use UnicaenDbImport\Connection\NoConnection;
use UnicaenDbImport\Filter\ColumnName\ColumnNameFilterInterface;
use UnicaenDbImport\Filter\ColumnValue\ColumnValueFilterInterface;
use UnicaenDbImport\Service\Api\ApiServiceInterface;
use UnicaenDbImport\Service\Api\Response\DataExtractor\ResponseDataExtractorInterface;

interface SourceInterface
@@ -30,6 +31,11 @@ interface SourceInterface
     */
    public function getCode(): string;

    /**
     * Retourne l'éventuel ApiService personnel de cette source.
     */
    public function getApiService(): ?ApiServiceInterface;

    /**
     * Lorsque la source est une table de base de données, retourne le nom de la table source.
     *
Loading