laudis / neo4j-php-client

Neo4j-PHP-Client 是最先进的 Neo4j PHP 客户端

3.1.2 2024-08-09 12:55 UTC

README

GitHub Code Climate maintainability Packagist PHP Version Support (custom server) Latest Stable Version

Packagist Downloads Packagist Downloads

控制全球最强大的图数据库

  • 轻松配置,挑选您想要的驱动程序
  • 直观的 API
  • 可扩展
  • 在官方 Neo4j 驱动团队紧密监督下设计、构建和测试
  • 通过 testkit 验证
  • 使用 psalm 完全类型化
  • 提供 Bolt、HTTP 和自动路由的驱动程序

看看驱动程序的实际应用

有关更详细的说明,您可以参考以下博客文章

或者观看以下 视频

三步轻松开始您的驾驶体验

步骤 1:通过 composer 安装

composer require laudis/neo4j-php-client

更多详细信息请参阅 此处

步骤 2:创建客户端

use Laudis\Neo4j\Authentication\Authenticate;
use Laudis\Neo4j\ClientBuilder;

$client = ClientBuilder::create()
    ->withDriver('bolt', 'bolt+s://user:password@localhost') // creates a bolt driver
    ->withDriver('https', 'https://test.com', Authenticate::basic('user', 'password')) // creates an http driver
    ->withDriver('neo4j', 'neo4j://neo4j.test.com?database=my-database', Authenticate::oidc('token')) // creates an auto routed driver with an OpenID Connect token
    ->withDefaultDriver('bolt')
    ->build();

您现在已创建了一个包含 bolt、HTTPS 和 neo4j 驱动程序 的客户端。客户端将默认使用 bolt 驱动程序。

有关 URL 和如何使用它们来配置驱动程序的更多信息,请参阅 此处

步骤 3:运行事务

use Laudis\Neo4j\Contracts\TransactionInterface;

$result = $client->writeTransaction(static function (TransactionInterface $tsx) {
    $result = $tsx->run('MERGE (x {y: "z"}:X) return x');
    return $result->first()->get('x')['y'];
});

echo $result; // echos 'z'

决定如何发送您的 Cypher 查询

您可以使用三种不同的方法来控制驱动程序

  • 自动提交查询(最简单且最直观)
  • 事务函数(最便携)
  • 未管理的事务(对控制程度最高)

自动提交查询

自动提交查询是最简单且最直观的,但在运行复杂业务逻辑或在高可用性环境中具有许多缺点。

运行一个简单的 Cypher 查询

$client->run(
    'MERGE (user {email: $email})', //The query is a required parameter
    ['email' => '[email protected]'],  //Requests can be optionally added
    'backup' //The default connection can be overridden
);

运行语句对象

use Laudis\Neo4j\Databags\Statement;

$statement = new Statement('MERGE (user {email: $email})', ['email' => '[email protected]']);
$client->runStatement($statement, 'default');

同时运行多个查询

runStatements 方法将一次性运行所有语句。此方法是减少数据库调用次数的必要工具,尤其是在使用 HTTP 协议时。

use Laudis\Neo4j\Databags\Statement;

$results = $client->runStatements([
    Statement::create('MATCH (x) RETURN x LIMIT 100'),
    Statement::create('MERGE (x:Person {email: $email})', ['email' => '[email protected]'])
]);

事务函数

事务函数是使用驱动程序时的实际标准。它是最可移植的,因为它能够抵抗在高可用性解决方案(如Neo4j aura集群)初期开发时遇到的大部分陷阱。

驱动程序管理事务函数

  • 如果发生暂时性错误,它会重新执行该函数。
  • 在成功执行后,它会提交事务。
  • 如果发生超时,它会回滚事务。
  • 当启用neo4j协议时,它会路由执行到相关从属或主服务器。

注意:由于自动重试功能,函数应在后续召回时产生相同的结果,或者说,在更技术性的术语中:应该是幂等的。始终记得在设计函数内的执行逻辑时要记住这一点。

一些示例

use Laudis\Neo4j\Contracts\TransactionInterface;

// Do a simple merge and return the result
$result = $client->writeTransaction(static function (TransactionInterface $tsx) {
    $result = $tsx->run('MERGE (x {y: "z"}:X) return x');
    return $result->first()->get('x')['y'];
});

// Will result in an error
$client->readTransaction(static function (TransactionInterface $tsx) {
    $tsx->run('MERGE (x {y: "z"}:X) return x');
});

// This is a poorly designed transaction function
$client->writeTransaction(static function (TransactionInterface $tsx) use ($externalCounter) {
    $externalCounter->incrementNodesCreated();
    $tsx->run('MERGE (x {y: $id}:X) return x', ['id' => Uuid::v4()]);
});

// This achieves the same effect but is safe in case it should be retried. The function is now idempotent.
$id = Uuid::v4();
$client->writeTransaction(static function (TransactionInterface $tsx) use ($id) {
    $tsx->run('MERGE (x {y: $id}:X) return x', ['id' => $id]);
});
$externalCounter->incrementNodesCreated();

未管理的事务

如果您需要访问驱动程序的底层功能,则希望使用未管理的事务。它们允许完全控制提交和回滚。

开启事务

beginTransaction方法将使用相关驱动程序启动一个事务。

use Laudis\Neo4j\Databags\Statement;

$tsx = $client->beginTransaction(
    // This is an optional set of statements to execute while opening the transaction
    [Statement::create('MERGE (x:Person({email: $email})', ['email' => '[email protected]'])],
    'backup' // This is the optional connection alias
);

请注意,beginTransaction只返回事务对象,而不是提供的语句的结果。

在事务中运行语句

只要事务仍然打开,事务就可以像客户端对象一样运行语句。

$result = $tsx->run('MATCH (x) RETURN x LIMIT 100');
$result = $tsx->runStatement(Statement::create('MATCH (x) RETURN x LIMIT 100'));
$results = $tsx->runStatements([Statement::create('MATCH (x) RETURN x LIMIT 100')]);

完成事务

回滚事务

$tsx->rollback();

提交事务

$tsx->commit([Statement::create('MATCH (x) RETURN x LIMIT 100')]);

访问结果

结果以行和列的标准格式返回

// Results are a CypherList
$results = $client->run('MATCH (node:Node) RETURN node, node.id AS id');

// A row is a CypherMap
foreach ($results as $result) {
    // Returns a Node
    $node = $result->get('node');

    echo $node->getProperty('id');
    echo $result->get('id');
}

Cypher值和类型映射到这些PHP类型和类

(*) 这些项也可以用作bolt协议的参数,并由驱动程序自动转换,因此可以在Cypher中使用。

除了这些示例之外,\DateTimeInterface将映射到Cypher中的DateTimeZoneId。空或列表类型的array将转换为Cypher的List,而关联数组将转换为map

(**) 一个点可以是实现PointInterface的四种类型之一:\Laudis\Neo4j\Types\CartesianPoint \Laudis\Neo4j\Types\Cartesian3DPoint \Laudis\Neo4j\Types\WGS84Point \Laudis\Neo4j\Types\WGS843DPoint

深入了解

区分参数类型

Cypher有列表和映射。这个概念可能有问题,因为标准的PHP数组封装了两者。当您提供一个空数组作为参数时,将无法确定空列表或映射。

ParameterHelper类是这一点的理想伴侣

use Laudis\Neo4j\ParameterHelper;

$client->run('MATCH (x) WHERE x.slug in $listOrMap RETURN x', ['listOrMap' => ParameterHelper::asList([])]); // will return an empty CypherList
$client->run('MATCH (x) WHERE x.slug in $listOrMap RETURN x', ['listOrMap' => ParameterHelper::asMap([])]); // will error
$client->run('MATCH (x) WHERE x.slug in $listOrMap RETURN x', ['listOrMap' => []]); // will return an empty CypherList

版本兼容性矩阵

Neo4j功能支持

深入要求

  • PHP >= 7.4
  • Neo4j数据库(最低版本3.5)
  • ext-bcmath *
  • ext-json **
  • ext-sockets ***

(*) 需要实现bolt协议

(**) 需要实现http协议

(***) 可以安装以优化bolt协议的性能

如果您计划使用HTTP驱动程序,请确保您的项目中包含了psr-7psr-17psr-18的实现。如果没有,您可以通过composer安装它们

composer require nyholm/psr7 nyholm/psr7-server kriswallsmith/buzz

结果格式/湿化

为了使bolt协议和http的结果统一,驱动程序提供了结果格式化程序(又称湿化器)。客户端可以配置这些格式化程序。您甚至可以自己实现。

默认格式化程序是\Laudis\Neo4j\Formatters\OGMFormatter,在结果格式部分中进行了详细说明。

默认情况下,驱动程序提供了三种格式化程序,它们都位于Formatter命名空间中。

  • \Laudis\Neo4j\Formatter\BasicFormatter它删除所有Cypher类型,并简单地以标量、null或数组值返回结果映射中的每个值。
  • \Laudis\Neo4j\Formatter\OGMFormatter它将Cypher类型映射到PHP类型,具体说明请参阅此处
  • \Laudis\Neo4j\Formatter\SummarizedResultFormatter它装饰任何格式化程序并添加详细的结果摘要。

客户端构建器提供了一种轻松更改格式化程序的方法。

$client = \Laudis\Neo4j\ClientBuilder::create()
    ->withFormatter(\Laudis\Neo4j\Formatter\SummarizedResultFormatter::create())
    ->build();

/**
 * The client will now return a result, decorated with a summary.
 *
 * @var \Laudis\Neo4j\Databags\SummarizedResult $results
 */
$summarisedResult = $client->run('MATCH (x) RETURN x');

// The summary contains extensive information such as counters for changed values in the database,
// information on the database, potential notifications, timing, a (profiled) plan, the type of query
// and information on the server itself.
$summary = $summarisedResult->getSummary();
// The result is exactly the same as the default.
$result = $summarisedResult->getResult();

为了使用自定义格式化程序,实现Laudis\Neo4j\Contracts\FormatterInterface并在使用客户端构建器时提供它。

概念

这里描述的驱动程序API 在此 是驱动程序的主要目标。因此,客户端只是一个驱动程序管理器。驱动程序创建会话。会话通过事务运行查询。

由于这种行为,您可以像这样从客户端开始访问每个概念

use Laudis\Neo4j\ClientBuilder;

// A builder is responsible for configuring the client on a high level.
$builder = ClientBuilder::create();
// A client manages the drivers as configured by the builder.
$client = $builder->build();
// A driver manages connections and sessions.
$driver = $client->getDriver('default');
// A session manages transactions.
$session = $driver->createSession();
// A transaction is the atomic unit of the driver where are the cypher queries are chained.
$transaction = $session->beginTransaction();
// A transaction runs the actual queries
$transaction->run('MATCH (x) RETURN count(x)');

如果您需要完全控制,则可以使用自定义配置对象控制每个对象。

客户端

客户端管理驱动程序并将查询根据预先配置的别名路由到正确的驱动程序。

驱动程序

驱动程序对象是线程安全的骨干,它提供对Neo4j的访问。它拥有连接池并可以生成执行工作的会话

use Laudis\Neo4j\Basic\Driver;
use Laudis\Neo4j\Databags\DriverConfiguration;

$driver = Driver::create(
    uri: 'neo4j://user:mypassword@Localhost:7687',
    configuration: DriverConfiguration::create()->withUserAgent('MyApp/1.0.0')
);

会话

会话是因果链中一系列事务的轻量级容器。它们根据需要从连接池借用连接,并使用书签链接事务。

use Laudis\Neo4j\Databags\SessionConfiguration;
use Laudis\Neo4j\Enum\AccessMode;

$session = $driver->createSession(SessionConfiguration::create()
    ->withDatabase('my-database')
    ->withAccessMode(AccessMode::READ())
);

事务

事务是原子工作单元,可能包含一个或多个查询。每个事务绑定到一个单独的连接,并在因果链中由一个书签表示。

语句

查询是事务内的可执行单元,由Cypher字符串和键参数集组成。每个查询输出一个可能包含零个或多个记录的结果。

结果

一个结果包含来自查询的输出,由标题元数据、内容记录和摘要元数据组成。在Neo4j 4.0及以上版本中,应用程序可以控制结果数据的流。

深入了解配置

URL方案

URL方案是配置驱动程序的最简单方法。

配置格式

'<scheme>://<user>:<password>@<host>:<port>?database=<database>'

默认配置

bolt://localhost:7687?database=neo4j

方案配置矩阵

此库支持三个驱动程序:bolt、HTTP和neo4j。URL方案的组成部分确定驱动程序。

配置对象

可以使用配置对象配置驱动程序、会话和事务。配置选项的概述请参阅此处

代码示例

use \Laudis\Neo4j\Databags\DriverConfiguration;
use Laudis\Neo4j\Databags\SessionConfiguration;
use Laudis\Neo4j\Databags\TransactionConfiguration;

$client = \Laudis\Neo4j\ClientBuilder::create()
    ->withDefaultDriverConfiguration(DriverConfiguration::default()->withUserAgent('MyApp/1.0.0'))
    ->withDefaultSessionConfiguration(SessionConfiguration::default()->withDatabase('app-database'))
    ->withDefaultTransactionConfiguration(TransactionConfiguration::default()->withTimeout(5.0))
    ->build();

// The client will run the query on a driver with the provided config,
// which spawns a session with the provided session config
// and runs the query in a transaction with the provided transaction config
$client->run('MATCH (x) RETURN count(x) AS count');

// More granular control can be achieved by requesting the concepts yourself:
$tsx = $client->getDriver('default')
    ->createSession(SessionConfiguration::default()->withDatabase('management-database'))
    ->beginTransaction(null, TransactionConfiguration::default()->withTimeout(200));

$tsx->run('SOME REALLY LONG MANAGEMENT QUERY');

$tsx->commit();