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 src/Bolt/ConnectionPool.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static function create(
): self {
return new self(
$semaphore,
BoltFactory::create($conf->getLogger()),
BoltFactory::create($conf->getLogger(), $conf->getSocketType()),
new ConnectionRequestData(
$uri->getHost(),
$uri,
Expand Down
12 changes: 11 additions & 1 deletion src/Bolt/SystemWideConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use function extension_loaded;

use Laudis\Neo4j\Contracts\BasicConnectionFactoryInterface;
use Laudis\Neo4j\Enum\SocketType;

/**
* Singleton connection factory based on the installed extensions.
Expand All @@ -35,8 +36,17 @@ private function __construct(
/**
* @psalm-suppress InvalidNullableReturnType
*/
public static function getInstance(): SystemWideConnectionFactory
public static function getInstance(?SocketType $preferredSocket = null): SystemWideConnectionFactory
{
// If a specific socket type is requested, create a new instance without caching
if ($preferredSocket === SocketType::SOCKETS() && extension_loaded('sockets')) {
return new self(new SocketConnectionFactory(new StreamConnectionFactory()));
}

if ($preferredSocket === SocketType::STREAM()) {
return new self(new StreamConnectionFactory());
}

if (self::$instance === null) {
$factory = new StreamConnectionFactory();
if (extension_loaded('sockets')) {
Expand Down
5 changes: 3 additions & 2 deletions src/BoltFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Laudis\Neo4j\Databags\SessionConfiguration;
use Laudis\Neo4j\Databags\TransactionConfiguration;
use Laudis\Neo4j\Enum\ConnectionProtocol;
use Laudis\Neo4j\Enum\SocketType;

/**
* Small wrapper around the bolt library to easily guarantee only bolt version 3 and up will be created and authenticated.
Expand All @@ -44,9 +45,9 @@ public function __construct(
) {
}

public static function create(?Neo4jLogger $logger): self
public static function create(?Neo4jLogger $logger, ?SocketType $socketType = null): self
{
return new self(SystemWideConnectionFactory::getInstance(), new ProtocolFactory(), new SslConfigurationFactory(), $logger);
return new self(SystemWideConnectionFactory::getInstance($socketType), new ProtocolFactory(), new SslConfigurationFactory(), $logger);
}

public function createConnection(ConnectionRequestData $data, SessionConfiguration $sessionConfig): BoltConnection
Expand Down
30 changes: 28 additions & 2 deletions src/Databags/DriverConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Laudis\Neo4j\Common\Neo4jLogger;
use Laudis\Neo4j\Common\SemaphoreFactory;
use Laudis\Neo4j\Contracts\SemaphoreFactoryInterface;
use Laudis\Neo4j\Enum\SocketType;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\SimpleCache\CacheInterface;
Expand All @@ -44,11 +45,13 @@ final class DriverConfiguration
/** @var callable():(SemaphoreFactoryInterface|null)|SemaphoreFactoryInterface|null */
private $semaphoreFactory;
private ?Neo4jLogger $logger;
private ?SocketType $socketType;

/**
* @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.
* @param string|null $logLevel The log level to use. If null, LogLevel::INFO is used.
* @param SocketType|null $socketType the socket type to use (SocketType::SOCKETS(), SocketType::STREAM(), or null for auto-detect)
*
* @psalm-external-mutation-free
*/
Expand All @@ -61,6 +64,7 @@ public function __construct(
callable|SemaphoreFactoryInterface|null $semaphore,
?string $logLevel,
?LoggerInterface $logger,
?SocketType $socketType = null,
) {
$this->cache = $cache;
$this->semaphoreFactory = $semaphore;
Expand All @@ -69,6 +73,7 @@ public function __construct(
} else {
$this->logger = null;
}
$this->socketType = $socketType;
}

/**
Expand All @@ -83,6 +88,7 @@ public static function create(
SemaphoreFactoryInterface $semaphore,
?string $logLevel,
?LoggerInterface $logger,
?SocketType $socketType = null,
): self {
return new self(
$userAgent,
Expand All @@ -92,7 +98,8 @@ public static function create(
$acquireConnectionTimeout,
$semaphore,
$logLevel,
$logger
$logger,
$socketType
);
}

Expand Down Expand Up @@ -261,4 +268,23 @@ public function withLogger(?string $logLevel, ?LoggerInterface $logger): self

return $tbr;
}

/**
* @psalm-immutable
*/
public function getSocketType(): ?SocketType
{
return $this->socketType;
}

/**
* @psalm-immutable
*/
public function withSocketType(?SocketType $socketType): self
{
$tbr = clone $this;
$tbr->socketType = $socketType;

return $tbr;
}
}
40 changes: 40 additions & 0 deletions src/Enum/SocketType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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\Enum;

use JsonSerializable;
use Laudis\TypedEnum\TypedEnum;

/**
* Defines the socket type to use for connections.
*
* @method static self SOCKETS()
* @method static self STREAM()
*
* @extends TypedEnum<string>
*
* @psalm-immutable
*
* @psalm-suppress MutableDependency
*/
final class SocketType extends TypedEnum implements JsonSerializable
{
private const SOCKETS = 'sockets';
private const STREAM = 'stream';

public function jsonSerialize(): string
{
return $this->getValue();
}
}
34 changes: 34 additions & 0 deletions tests/Unit/BoltFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
use Laudis\Neo4j\Bolt\Connection;
use Laudis\Neo4j\Bolt\ProtocolFactory;
use Laudis\Neo4j\Bolt\SslConfigurationFactory;
use Laudis\Neo4j\Bolt\SystemWideConnectionFactory;
use Laudis\Neo4j\BoltFactory;
use Laudis\Neo4j\Common\Uri;
use Laudis\Neo4j\Contracts\AuthenticateInterface;
use Laudis\Neo4j\Contracts\BasicConnectionFactoryInterface;
use Laudis\Neo4j\Databags\ConnectionRequestData;
use Laudis\Neo4j\Databags\DriverConfiguration;
use Laudis\Neo4j\Databags\SessionConfiguration;
use Laudis\Neo4j\Databags\SslConfiguration;
use Laudis\Neo4j\Enum\SocketType;
use PHPUnit\Framework\TestCase;

final class BoltFactoryTest extends TestCase
Expand Down Expand Up @@ -73,4 +76,35 @@ public function testCreateBasic(): void
self::assertInstanceOf(Connection::class,
$connection->getImplementation()[1]);
}

public function testSystemWideConnectionFactoryStreamOverride(): void
{
$factory = SystemWideConnectionFactory::getInstance(SocketType::STREAM());
self::assertInstanceOf(SystemWideConnectionFactory::class, $factory);
}

public function testSystemWideConnectionFactorySocketOverride(): void
{
if (!extension_loaded('sockets')) {
self::markTestSkipped('sockets extension not loaded');
}

$factory = SystemWideConnectionFactory::getInstance(SocketType::SOCKETS());
self::assertInstanceOf(SystemWideConnectionFactory::class, $factory);
}

public function testDriverConfigurationWithSocketType(): void
{
$socketType = SocketType::STREAM();
$config = DriverConfiguration::default()
->withSocketType($socketType);

self::assertEquals($socketType, $config->getSocketType());
}

public function testBoltFactoryWithSocketTypeOverride(): void
{
$factory = BoltFactory::create(null, SocketType::STREAM());
self::assertInstanceOf(BoltFactory::class, $factory);
}
}
Loading