kitlabs/neo4j-php-client

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

13.0.6 2024-02-21 08:21 UTC

This package is auto-updated.

Last update: 2024-08-23 12:03:36 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();