laudis-technologies/neo4j-php-client

View on GitHub
src/Databags/DriverConfiguration.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types=1);

/*
 * This file is part of the Neo4j PHP Client and Driver package.
 *
 * (c) Nagels <https://nagels.tech>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Laudis\Neo4j\Databags;

use function call_user_func;

use Composer\InstalledVersions;

use function function_exists;
use function is_callable;

use Laudis\Neo4j\Common\Cache;
use Laudis\Neo4j\Common\Neo4jLogger;
use Laudis\Neo4j\Common\SemaphoreFactory;
use Laudis\Neo4j\Contracts\SemaphoreFactoryInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\SimpleCache\CacheInterface;

use function sprintf;

/**
 * Configuration object for the driver.
 */
final class DriverConfiguration
{
    public const DEFAULT_USER_AGENT = 'neo4j-php-client/%s';
    public const DEFAULT_POOL_SIZE = 0x2F;
    public const DEFAULT_CACHE_IMPLEMENTATION = Cache::class;
    public const DEFAULT_ACQUIRE_CONNECTION_TIMEOUT = 2.0;
    /** @var callable():(HttpPsrBindings|null)|HttpPsrBindings|null */
    private $httpPsrBindings;
    /** @var callable():(CacheInterface|null)|CacheInterface|null */
    private $cache;
    /** @var callable():(SemaphoreFactoryInterface|null)|SemaphoreFactoryInterface|null */
    private $semaphoreFactory;
    private ?Neo4jLogger $logger;

    /**
     * @param callable():(HttpPsrBindings|null)|HttpPsrBindings|null $httpPsrBindings
     * @param callable():(CacheInterface|null)|CacheInterface|null $cache
     * @param callable():(SemaphoreFactoryInterface|null)|SemaphoreFactoryInterface|null $semaphore
     * @param string|null $logLevel The log level to use. If null, LogLevel::INFO is used.
     *
     * @psalm-external-mutation-free
     */
    public function __construct(
        private string|null $userAgent,
        callable|HttpPsrBindings|null $httpPsrBindings,
        private SslConfiguration $sslConfig,
        private int|null $maxPoolSize,
        CacheInterface|callable|null $cache,
        private float|null $acquireConnectionTimeout,
        callable|SemaphoreFactoryInterface|null $semaphore,
        ?string $logLevel,
        ?LoggerInterface $logger
    ) {
        $this->httpPsrBindings = $httpPsrBindings;
        $this->cache = $cache;
        $this->semaphoreFactory = $semaphore;
        if ($logger !== null) {
            $this->logger = new Neo4jLogger($logLevel ?? LogLevel::INFO, $logger);
        } else {
            $this->logger = null;
        }
    }

    /**
     * @param callable():(HttpPsrBindings|null)|HttpPsrBindings|null $httpPsrBindings
     *
     * @pure
     */
    public static function create(
        ?string $userAgent,
        callable|HttpPsrBindings|null $httpPsrBindings,
        SslConfiguration $sslConfig,
        int $maxPoolSize,
        CacheInterface $cache,
        float $acquireConnectionTimeout,
        SemaphoreFactoryInterface $semaphore,
        ?string $logLevel,
        ?LoggerInterface $logger,
    ): self {
        return new self(
            $userAgent,
            $httpPsrBindings,
            $sslConfig,
            $maxPoolSize,
            $cache,
            $acquireConnectionTimeout,
            $semaphore,
            $logLevel,
            $logger
        );
    }

    /**
     * Creates a default configuration with a user agent based on the driver version
     * and HTTP PSR implementation auto-detected from the environment.
     *
     * @pure
     */
    public static function default(): self
    {
        return new self(
            null,
            HttpPsrBindings::default(),
            SslConfiguration::default(),
            null,
            null,
            null,
            null,
            null,
            null
        );
    }

    /**
     * @psalm-mutation-free
     */
    public function getUserAgent(): string
    {
        if ($this->userAgent === null) {
            if (function_exists('InstalledVersions::getPrettyVersion')) {
                /** @psalm-suppress ImpureMethodCall */
                $version = InstalledVersions::getPrettyVersion('laudis/neo4j-php-client') ?? 'provided/replaced';
            } else {
                $version = '2';
            }

            return sprintf(self::DEFAULT_USER_AGENT, $version);
        }

        return $this->userAgent;
    }

    /**
     * Creates a new configuration with the provided user agent.
     *
     * @param string|null $userAgent
     *
     * @psalm-immutable
     */
    public function withUserAgent($userAgent): self
    {
        $tbr = clone $this;
        $tbr->userAgent = $userAgent;

        return $tbr;
    }

    /**
     * Creates a new configuration with the provided bindings.
     *
     * @param callable():(HttpPsrBindings|null)|HttpPsrBindings|null $bindings
     *
     * @psalm-immutable
     */
    public function withHttpPsrBindings($bindings): self
    {
        $tbr = clone $this;
        $tbr->httpPsrBindings = $bindings;

        return $tbr;
    }

    /**
     * @psalm-immutable
     */
    public function withSslConfiguration(SslConfiguration $config): self
    {
        $tbr = clone $this;
        $tbr->sslConfig = $config;

        return $tbr;
    }

    /**
     * @psalm-immutable
     */
    public function getSslConfiguration(): SslConfiguration
    {
        return $this->sslConfig;
    }

    public function getHttpPsrBindings(): HttpPsrBindings
    {
        $this->httpPsrBindings = (is_callable($this->httpPsrBindings)) ? call_user_func(
            $this->httpPsrBindings
        ) : $this->httpPsrBindings;

        return $this->httpPsrBindings ??= HttpPsrBindings::default();
    }

    public function getMaxPoolSize(): int
    {
        return $this->maxPoolSize ?? self::DEFAULT_POOL_SIZE;
    }

    /**
     * @psalm-immutable
     */
    public function withMaxPoolSize(?int $maxPoolSize): self
    {
        $tbr = clone $this;
        $tbr->maxPoolSize = $maxPoolSize;

        return $tbr;
    }

    /**
     * @param callable():(CacheInterface|null)|CacheInterface|null $cache
     *
     * @psalm-immutable
     */
    public function withCache($cache): self
    {
        $tbr = clone $this;
        $tbr->cache = $cache;

        return $tbr;
    }

    public function getCache(): CacheInterface
    {
        $this->cache = (is_callable($this->cache)) ? call_user_func($this->cache) : $this->cache;

        return $this->cache ??= Cache::getInstance();
    }

    public function getSemaphoreFactory(): SemaphoreFactoryInterface
    {
        $this->semaphoreFactory = (is_callable($this->semaphoreFactory)) ? call_user_func(
            $this->semaphoreFactory
        ) : $this->semaphoreFactory;

        return $this->semaphoreFactory ??= SemaphoreFactory::getInstance();
    }

    /**
     * @psalm-immutable
     */
    public function getAcquireConnectionTimeout(): float
    {
        return $this->acquireConnectionTimeout ??= self::DEFAULT_ACQUIRE_CONNECTION_TIMEOUT;
    }

    /**
     * @psalm-immutable
     */
    public function withAcquireConnectionTimeout(?float $acquireConnectionTimeout): self
    {
        $tbr = clone $this;
        $tbr->acquireConnectionTimeout = $acquireConnectionTimeout;

        return $tbr;
    }

    /**
     * @param callable():(SemaphoreFactoryInterface|null)|SemaphoreFactoryInterface|null $factory
     *
     * @psalm-immutable
     */
    public function withSemaphoreFactory($factory): self
    {
        $tbr = clone $this;
        $tbr->semaphoreFactory = $factory;

        return $tbr;
    }

    /**
     * @psalm-immutable
     */
    public function getLogger(): ?Neo4jLogger
    {
        return $this->logger;
    }

    public function withLogger(?string $logLevel, ?LoggerInterface $logger): self
    {
        $tbr = clone $this;
        $tbr->logger = new Neo4jLogger($logLevel ?? LogLevel::INFO, $logger);

        return $tbr;
    }
}