A PHP HttpClient for the Neo4j ReST API with MultiDB Support

Related tags

HTTP neo4j-neoclient
Overview

NeoClient

This repository has moved

Neoxygen's NeoClient has been moved to https://github.com/graphaware/neo4j-php-client

Version 3 of this library is still maintained for bug support for the users requiring neoxygen/neoclient in their composer's dependencies.

Version 3 End of Maintenance is planned on September 1, 2016.

Version 4 (with support for the Bolt binary protocol - in current developement) will only be available on the GraphAware's repository.

If you are having issues for the migration, you can open an issue here : https://github.com/graphaware/neo4j-php-client/issues

GraphAware's Enterprise customers can send a direct support email to their first level of support at GraphAware.


A PHP HttpClient for the Neo4j ReST API with MultiDB Support

Build Status Latest Stable Version Total Downloads Latest Unstable Version License SensioLabsInsight

Supported and Sponsored By

GraphAware

Introduction

NeoClient is the most advanced and flexible Neo4j Client for PHP.

What is Neo4j?

Neo4j is a transactional, open-source graph database. A graph database manages data in a connected data structure, capable of representing any kind of data in a very accessible way. Information is stored in nodes and relationships connecting them, both of which can have arbitrary properties. To learn more visit What is a Graph Database?

Key features

  • Supports multiple connections
  • Built-in and automatic support for Neo4j Enterprise HA Master-Slave Mode with auto slaves fallback
  • Fully extensible (You can create your own extensions)

Neo4j Version Support

Version Tested
<= 2.1.5 No
>= 2.1.6 Yes
2.2 Yes

Neo4j Feature Support

Feature Supported?
Auth Yes
Remote Cypher Yes
Transactions Yes
High Availability Yes
Embedded JVM support No

Requirements

  • PHP 5.5+
  • A Neo4j database (minimum version 2.1.6)

Getting Help

You can:

Installation and basic usage

Installation

Add the library to your composer dependencies :

composer require neoxygen/neoclient

Require the composer autoloader, configure your connection by providing a connection alias and your connection settings :



require_once 'vendor/autoload.php';

use Neoxygen\NeoClient\ClientBuilder;

$client = ClientBuilder::create()
    ->addConnection('default','http','localhost',7474)
    ->build();

You're now ready to connect to your database.

If you use default database settings in a local environment (meaning http://localhost:7474), you can use the handy addDefaultLocalConnection method :

$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->build();

The build method will process configuration settings and return you a Client instance.

Configuring the connection timeout

You can configure the default timeout during the build process :

$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->setDefaultTimeout(20) // <-- Timeout of 20 seconds for http requests
    ->build();

Usage

You have now full access to the database.

getRoot | Returns the root endpoint

$root = $client->getRoot();
Array
    (
        [management] => http://localhost:7474/db/manage/
        [data] => http://localhost:7474/db/data/
    )

Note: As the library provide full support for working with multiple databases, each method explained in the documentation can take a $conn parameter which you can use to define on which connection you want to execute the method. The default connection will be used when the parameter is not set.

For more information on how to set up multiple connections, read the Multiple connections section of the documentation.

getNeo4jVersion | Returns the Neo4j version of the current connection

$version = $client->getNeo4jVersion();

// Returns (string) 2.2.1

Sending Cypher Queries

In order to send a Cypher Query, you need to pass the query as a string, and an optional array of paramaters as arguments :

$q = 'MATCH (n) RETURN count(n)';
$response = $client->sendCypherQuery($q);
renameLabel('Person', 'User'); ``` ### Managing Indexes and Constraints Indexes and Constraints management is also an easy task #### createIndex | Creates an index for a label/property pair ```php $client->createIndex('Person', 'email'); ``` #### listIndex | List indexed properties for a given label ```php $client->listIndex('Person'); ``` Returns you an array of indexed properties for the given label #### listIndexes | List indexed properties for given labels or all labels ```php $personAndUserIndexes = $client->listIndexes(['Person','User']); $allIndexes = $client->listIndexes(); ``` Returns you an array of indexed properties by the form `['Label' => ['prop1','prop2']]`. #### dropIndex | Drop an index for a given label/property pair ```php $client->dropIndex('Person','email'); ``` #### isIndexed | Checks whether or not a given label/property pair is indexed ```php $client->isIndexed('User','username'); ``` Returns true or false #### createUniqueConstraint | Create a uniqueness constraint for a given label/property pair ```php $client->createUniqueConstraint('User','username'); ``` If an index already exist on the combination `Label, property` you can ask the client to drop the index and create the constraint instead of throwing an exception, just pass `true` as a third parameter. ```php $client->createUniqueConstraint('User','username',true); ``` #### dropUniqueConstraint | Drop a uniqueness constraint for a given label/property pair ```php $client->dropUniqueConstraint('User','username'); ``` #### getUniqueConstraints | Returns all the uniqueness constraints by label ```php $constraints = $client->getUniqueConstraints(); ``` Returns `['User' => ['username','email'], 'Movie' => ['imdb_id']]` ## Handling Graph Results The Response Formatter will format graph results in a pretty format of nodes and relationships objects. If you've setup the `autoFormatResponse` configuration value, when a graph result is available, a graph representation is available for you : ```php $query = 'MATCH (a:Actor)-[r]-(m:Movie) RETURN *'; $client->sendCypherQuery($query); // Getting the graph Result $result = $client->getResult(); // The raw response is still available : $response = $client->getResponse(); // Getting all nodes $nodes = $result->getNodes(); // Getting all movie nodes from the result $movies = $result->getNodes('Movie'); // Getting all movie and Actor nodes from the result $moviesAndActors = $result->getNodes(['Movie','Actor']); // Returns you a collection of nodes objects // If you want to group the nodes by labels, you can pass true as second argument to the getNodes method $moviesAndActors = $result->getNodes(['Movie','Actor'], true); // Returns an array with labels as keys ['Movie' => ['NodeObject1', 'NodeObject2']] // Getting only one movie (returns in fact the first element of an array, but is handy when you expect only one node $movie = $result->getSingleNode('Movie'); // Working with the relationships $movie = $result->getSingleNode('Movie'); $actors = $movie->getRelationships('ACTS_IN'); // Or you may want to specify direction $actors = $movie->getRelationships('ACTS_IN', 'IN'); // If you need only one relationship : $actor = $movie->getSingleRelationship('ACTS_IN'); // Getting node/relationships properties // Getting one property $actor = $result->getSingleNode('Actor'); $name = $actor->getProperty('name'); // Getting all properties $props = $actor->getProperties(); // Getting a set of properties $props = $actor->getProperties(['name', 'date_of_birh']); // Getting the node internal Id (Id of the Neo4j database) $id = $actor->getId(); // Getting a node by id in the Result set $node = $result->getNodeById(34); // Counting Nodes And Relationships $nbNodes = $result->getNodesCount(); $nbRels = $result->getRelationshipsCount(); // Since 2.2 // getConnectedNodes and getConnectedNode // Shortcut bypassing the relationship and returning the connected nodes $node->getConnectedNodes(); $node->getConnectedNodes('IN', 'KNOWS'); $node->getconnectedNodes('OUT', ['KNOWS','FOLLOWS']); //Same arguments signature for getConnectedNode $node->getConnectedNode(); // returns only one node ``` ### Using `get` Commonly, you'll use identifiers in your return statements, you can access them in an easy way : ```php $q = 'MATCH (n:User)<-[:FOLLOWS]-(followers) RETURN n, collect(followers) as flwers'; $r = $client->sendCypherQuery($q)->getResult(); print_r($r->get('flwers')); // Returns an array of node objects ``` ### Results in table format Sometimes you will deal with results in table format, there is a dedicated method `getTableFormat` that will format the results for you : ``` $q = 'MATCH (c:Country) MATCH (c)<-[:LIVES_IN]->(p) RETURN c.name, count(*) as people ORDER BY people DESC'; $result = $client->sendCypherQuery($q)->getResult(); print_r($result->getTableFormat()); --- Array ( [0] => Array ( [c.name] => Barbados [people] => 3 ) [1] => Array ( [c.name] => Vietnam [people] => 2 ) [2] => Array ( [c.name] => Liberia [people] => 2 ) [3] => Array ( [c.name] => Rwanda [people] => 2 ) [4] => Array ( [c.name] => Canada [people] => 1 ) ) --- ``` ## Sending multiple statements in one transaction There are 2 ways for sending multiple statements in one and only transaction. 1. Using an open transaction throughout the process (see the next section "Transaction Management") 2. Using a `PreparedTransaction` instance ### PreparedTransaction Handy if you want to keep a `PreparedTransaction` instance throughout your code : ```php $tx = $client->prepareTransaction() ->pushQuery($q, $p) ->pushQuery($q2) ->pushQuery($q3) ->commit(); ``` ## Transaction Management The library comes with a Transaction Manager removing you the burden of parsing commit urls and transaction ids. Usage is straightforward : ```php $transaction = $client->createTransaction(); $transaction->pushQuery('MERGE (n:User {id: 123}) RETURN n'); $transaction->pushQuery('MATCH (n) RETURN count(n)'); $transaction->commit(); // Other methods : $transaction->rollback(); $transaction->getLastResult // Returns the result of the last transaction statements $transaction->getResults() // Returns the results of all the statements ``` Note that a commited or a rolled back transaction will not accept pushQuery calls anymore. ## Working with multiple connections ### Define multiple connections You can work with as many connections you want : ```php $client = ClientBuilder::create() ->addConnection('default', 'http', 'localhost', 7474) ->addConnection('testserver1', 'http', 'testserver.local', 7474) ->addConnection('testserver2', 'http', 'testserver2.local',7474) ->build(); ``` When calling commands, you can specify to which connection the command has to be executed by passing the connection alias as argument : ```php $client->getRoot('default'); $client->sendCypherQuery('MATCH (n) RETURN count(n) as total', array(), 'testserver1'); ``` ## HA (High-Availibilty) ### HA Mode for Neo4j Enterprise NB: There are ongoing changes for improving the HA Mode of the Enterprise Edition, stay tuned ;-) The library provide a powerful system for handling the HA Mode of Neo4j available in Neo4j Enterprise. The convention is to send write queries to the master, and read queries to slaves. To enable the HA Mode and defining which connections are master or slave, you need to add some method call during the build process of the client : ```php $client = ClientBuilder::create() ->addConnection('server1', 'http', '193.147.213.3', 7474) ->addConnection('server2', 'http', '193.147.213.4', 7474) ->addConnection('server3', 'http', '193.147.213.7', 7474) ->setMasterConnection('server1') // Define the Master Connection by providing the connection alias ->setSlaveConnection('server2') // Idem for slave connections ->setSlaveConnection('server3') ->enableHAMode() ->build(); ``` Your configuration is now set. The client has convenience methods for HA usage, respectively `sendReadQuery` and `sendWriteQuery`. Automatically, write queries will be executed against the `master` connection, while `read` queries against slave connections. If a slave is no more reachable, it will automatically check if other slaves are configured. If yes it will attempt to send the query again to the other slave connections. If you have loggers settled up, an `alert` entry will be logged to inform you of slave connection failure. ```php $client->sendWriteQuery('MERGE (n:User {firstname: "Chris"})'); // Will be sent to the "server1" connection $client->sendReadQuery('MATCH (n:User) RETURN n'); // Will be sent to the "server2" connection ``` NB: The above methods do not take the `$conn` argument as the choice of the connection is done in the library internals. Note: You can always retrieve the Master and the first Slave connection alias from the client if you want to specify them when using other commands : ```php $client->getRoot($client->getWriteConnectionAlias()); // Will be run against the master connection $client->listLabels($client->getReadConnectionAlias()); // Will be run agains the first found slave connection ``` Please also note, that when using the *Transaction Manager*, all queries will be run against the same connection. *Transaction* instances are bounded to one and only connection. ### Checking your Master/Slave Configuration You can check that your defined master and slaves connections are running and setup correctly : ```php $client->checkHAMaster('server1'); // Returns true|false $client->checkHASlave('server2'); // Returns true|false $client->checkHAAvailable('serverxxx'); // Returns master|slave|false ``` ### Query Mode Headers When the High Availibity Mode is enabled, an additional header will be set to the http request. This header defines the query mode of the transaction : `READ` or `WRITE`. By default, all queries, live transactions and prepared transactions are assumed `WRITE`. You can define it your self by using the Client's constants `Client::NEOCLIENT_QUERY_MODE_WRITE` and `Client::NEOCLIENT_QUERY_MODE_READ` or by simply passing a string with those values to the following methods: ```php $client->sendCypherQuery($query, $params, $conn = null, $queryMode = Client::NEOCLIENT_QUERY_MODE_READ); $client->createTransaction($conn = null, Client::NEOCLIENT_QUERY_MODE_WRITE); $client->prepareTransaction($conn = null, Client::NEOCLIENT_QUERY_MODE_WRITE); ``` The default headers are the following : * The header key is `Neo4j-Query-Mode` * The write transactions will have a header value of : `NEO4J_QUERY_WRITE` * The read transactions will have a header value of : `NEO4J_QUERY_READ` You can define your own headers definition via the configuration : ##### yaml ```yaml neoclient: ha_mode: enabled: true query_mode_header_key: MY_HEADER read_mode_header_value: QUERY_READ write_mode_header_value: QUERY_WRITE ``` ##### php ```php $client = ClientBuilder::create() // .. other settings ->enableHAMode() ->configureHAQueryModeHeaders($headerKey, $writeModeHeaderValue, $readModeHeaderValue) ->build(); ``` ## Secured connections ### Authenticated connection #### For Neo4j 2.2 Provide the user and the password when building the connection : ```php $client = ClientBuilder::create() ->addConnection('default', 'http', 'myserver.dev', 7474, true, 'username', 'password') ->build(); ``` #### changing the password The client has a built-in method for changing the password : ```php $client->changePassword('user', 'newPassword'); ``` #### Before Neo4j 2.2 using the Auth Extension If you are using the `authenticated-extension` or using [GrapheneDB](http://graphenedb.com) instance, you can specify to use the authMode for the connection and provide your username and password : ```php $client = ClientBuilder::create() ->addConnection('default', 'http', 'myserver.dev', 7474, true, 'username', 'password') ->build(); ``` Your password will automatically be encoded in base64 for the Authorization. ### Convenience methods for the `Authentication extension` #### listUsers | List the users registered in the connection authentication extension ```php $client->listUsers(); ``` ```json {"john"} ``` #### addUser | Adds a user to the extensions ```php $client->addUser('John', 'password'); ``` ```json OK ``` The third argument of the `addUser` method is the `readOnly` parameter, default to false ``` $client->addUser('john', 'password', true); ``` ```json OK {"john"} ``` #### removeUser | Removes a user from the extension ```php $client->removeUser('user', 'password'); ``` ```json OK ``` ## Events & Logging ### Event Listeners You can add listeners to hook into the built-in event system, for all list of all available events, look inside the `NeoEvents.php` file. A listener can be a \Closure instance, an object implementing an __invoke method, a string representing a function, or an array representing an object method or a class method. Event listeners are currently not configurable with the yaml file, it will come soon... ```php $client = ClientBuilder::create() ->addDefaultLocalConnection() ->addEventListener('foo.action', function (Event $event)) ->build(); ``` ### Logging You can add your logging system or ask the library to use the default built-in logging mechanism (currently only stream and ChromePHP are supported). If you integrate your own logging, he must be compatible with the PSR-3 standard. ```php // Adding your own logging $client = ClientBuilder::create() ->addDefaultLocalConnection() ->setLogger('app', MyLogger) // My Logger must implement Psr\Log\LoggerInterface ->build(); ``` The library is shipped with two default Monolog handlers that you can use : Stream and ChromePHP. Registering them is straightforward : ```php $client = ClientBuilder::create() ->addDefaultLocalConnection() ->createDefaultStreamLogger('name', '/path/to/your/log/file.log', 'debug') ->createDefaultChromePHPLogger('app', 'debug'); ->build(); ``` ## Extending NeoClient ### Creating your own commands You can extend the library by creating your own commands. Create your `Command` class, this class must extend `Neoxygen\NeoClient\Command\AbstractCommand` and must implement the `execute` method. By extending the AbstractCommand class, you have access to the http client, and also the connection alias that is used when invoking the command. The best way to execute a command is by calling the `send` request of the HttpClient and passing the `method`, `path`, `body` and `connectionAlias` arguments : ```php httpClient->send($method, $path, null, $this->connection); } } ``` Then you have to register your command when building the client by passing an alias for your command and the class FQDN : ```php $client = ClientBuilder::create() ->addDefaultLocalConnection() ->registerCommand('my_super_command', 'My\Command\Class\Namespace') ->build(); ``` Then to use your command, just use the invoke method of the client : ```php $command = $client->invoke('custom_get_extensions'); $extensions = $command->execute(); print_r($extensions); ``` ### Creating an Extension When you have a lot of commands, it may be good to create a command extension. Creating a command extension is quite simple : You need to create a class that extends the `Neoxygen\NeoClient\Extension\AbstractExtension`, and you have to implement the `getAvailableCommands` method that return an array of command aliases bounded to command classes : ```php use Neoxygen\NeoClient\Extension\NeoClientExtensionInterface; class MyExtension implements NeoClientExtensionInterface { public static function getAvailableCommands() { return array( 'custom_get_extensions' => 'My\Command\Class', 'custom_other_exec' => 'My\Other\Class' ); } } ``` And then register your extension when building the client by giving an alias and the class FQDN of your extension : ```php $client = ClientBuilder::create() ->addDefaultLocalConnection() ->registerExtension('my_extension_alias', 'My\Extension\Class\Namespace') ->build(); ``` ## Production settings The library uses a Dependency Injenction Container and service files definitions, while this provide full flexibility and robust code, this comes at a price. By providing a cache path where the container and all the configuration can be dumped, you'll have the best of both worlds. ```yaml connections: default: scheme: http host: localhost port: 7474 testdb: scheme: http host: testserver.dev port: 7475 cache: enable: true cache_path: /dev/project/cache/ ``` Don't forget to add full permissions to the cache path : `chmod -R 777 your/cache/path` and also to empty the cache dir when you do changes to your configuration. ### Configuration Reference ### YAML ```yaml connections: default: scheme: http host: localhost port: 7474 testdb: scheme: http host: testserver.dev port: 7475 auth: true user: user password: password ha_mode: enabled: true type: community|enterprise master: default slaves: - testdb auto_format_response: true cache: enabled: true cache_path: /dev/project/cache custom_commands: my_command: class: My\Command\Class extensions: my_extension: class: My\Extension\Class ``` ### License The library is released under the MIT License, refer to the LICENSE file. ### Tests To run the test suite, you need to copy the `tests/database_settings.yml.dist` to `tests/database_settings.yml`, as it will create nodes to a real database. Run `vendor/bin/phpunit` ">
Array
(
    [results] => Array
        (
            [0] => Array
                (
                    [columns] => Array
                        (
                            [0] => count(n)
                        )

                    [data] => Array
                        (
                            [0] => Array
                                (
                                    [row] => Array
                                        (
                                            [0] => 1
                                        )
......                                        
```

Handling such response format is not really practical and boring. You can ask the client to format the response in a pretty way and have
this format available to you :

```php
$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->setAutoFormatResponse(true)
    ->build();
```

To get the pretty format :

```php

$q = 'MATCH (n:Actor) RETURN n.name';
$client->sendCypherQuery($q);

$result = $client->getRows();
```

```
Array
(
    [n.name] => Array
        (
            [0] => Keanu Reeves
            [1] => Laurence Fishburne
            [2] => Carrie-Anne Moss
        )

)

```
## Labels, Indexes and Constraints Management

### Managing labels

The library provide handy methods for managing your labels :


#### getLabels | Returns the labels indexed in the database

```php
$labels = $client->getLabels();
```

```php
[ "UriahHeep", "MyLabel", "Version", "Customer", "TestLabel" ]
```

#### renameLabel | Fetch all nodes for that label and rename the label of the nodes

Note that depending on the amount of nodes for the given label, this can take some time.

Call the `renameLabel` method and pass the old label name and the new label name as arguments :

```php
$client->renameLabel('Person', 'User');
```

### Managing Indexes and Constraints

Indexes and Constraints management is also an easy task

#### createIndex | Creates an index for a label/property pair

```php
$client->createIndex('Person', 'email');
```

#### listIndex | List indexed properties for a given label

```php
$client->listIndex('Person');
```

Returns you an array of indexed properties for the given label

#### listIndexes | List indexed properties for given labels or all labels

```php
$personAndUserIndexes = $client->listIndexes(['Person','User']);

$allIndexes = $client->listIndexes();
```

Returns you an array of indexed properties by the form `['Label' => ['prop1','prop2']]`.

#### dropIndex | Drop an index for a given label/property pair

```php
$client->dropIndex('Person','email');
```

#### isIndexed | Checks whether or not a given label/property pair is indexed

```php
$client->isIndexed('User','username');
```

Returns true or false

#### createUniqueConstraint | Create a uniqueness constraint for a given label/property pair

```php
$client->createUniqueConstraint('User','username');
```

If an index already exist on the combination `Label, property` you can ask the client to drop the index and create the
constraint instead of throwing an exception, just pass `true` as a third parameter.

```php
$client->createUniqueConstraint('User','username',true);
```

#### dropUniqueConstraint | Drop a uniqueness constraint for a given label/property pair

```php
$client->dropUniqueConstraint('User','username');
```

#### getUniqueConstraints | Returns all the uniqueness constraints by label

```php
$constraints = $client->getUniqueConstraints();
```

Returns `['User' => ['username','email'], 'Movie' => ['imdb_id']]`


## Handling Graph Results

The Response Formatter will format graph results in a pretty format of nodes and relationships objects.

If you've setup the `autoFormatResponse` configuration value, when a graph result is available, a graph representation
is available for you :

```php
$query = 'MATCH (a:Actor)-[r]-(m:Movie) RETURN *';
$client->sendCypherQuery($query);

// Getting the graph Result
$result = $client->getResult();

// The raw response is still available :
$response = $client->getResponse();

// Getting all nodes

$nodes = $result->getNodes();

// Getting all movie nodes from the result
$movies = $result->getNodes('Movie');

// Getting all movie and Actor nodes from the result

$moviesAndActors = $result->getNodes(['Movie','Actor']);
// Returns you a collection of nodes objects

// If you want to group the nodes by labels, you can pass true as second argument to the getNodes method

$moviesAndActors = $result->getNodes(['Movie','Actor'], true);
// Returns an array with labels as keys ['Movie' => ['NodeObject1', 'NodeObject2']]


// Getting only one movie (returns in fact the first element of an array, but is handy when you expect only one node
$movie = $result->getSingleNode('Movie');

// Working with the relationships

$movie = $result->getSingleNode('Movie');
$actors = $movie->getRelationships('ACTS_IN');
// Or you may want to specify direction
$actors = $movie->getRelationships('ACTS_IN', 'IN');

// If you need only one relationship :
$actor = $movie->getSingleRelationship('ACTS_IN');

// Getting node/relationships properties

// Getting one property
$actor = $result->getSingleNode('Actor');
$name = $actor->getProperty('name');

// Getting all properties
$props = $actor->getProperties();

// Getting a set of properties
$props = $actor->getProperties(['name', 'date_of_birh']);

// Getting the node internal Id (Id of the Neo4j database)

$id = $actor->getId();

// Getting a node by id in the Result set

$node = $result->getNodeById(34);

// Counting Nodes And Relationships

$nbNodes = $result->getNodesCount();
$nbRels = $result->getRelationshipsCount();


// Since 2.2
// getConnectedNodes and getConnectedNode
// Shortcut bypassing the relationship and returning the connected nodes

$node->getConnectedNodes();
$node->getConnectedNodes('IN', 'KNOWS');
$node->getconnectedNodes('OUT', ['KNOWS','FOLLOWS']);
//Same arguments signature for getConnectedNode
$node->getConnectedNode(); // returns only one node

```

### Using `get`

Commonly, you'll use identifiers in your return statements, you can access them in an easy way :

```php
$q = 'MATCH (n:User)<-[:FOLLOWS]-(followers) RETURN n, collect(followers) as flwers';
$r = $client->sendCypherQuery($q)->getResult();

print_r($r->get('flwers')); // Returns an array of node objects
```

### Results in table format

Sometimes you will deal with results in table format, there is a dedicated method `getTableFormat` 
that will format the results for you :

```
$q = 'MATCH (c:Country)
      MATCH (c)<-[:LIVES_IN]->(p)
      RETURN c.name, count(*) as people
      ORDER BY people DESC';
$result = $client->sendCypherQuery($q)->getResult();

print_r($result->getTableFormat());

--- 
Array
(
    [0] => Array
        (
            [c.name] => Barbados
            [people] => 3
        )

    [1] => Array
        (
            [c.name] => Vietnam
            [people] => 2
        )

    [2] => Array
        (
            [c.name] => Liberia
            [people] => 2
        )

    [3] => Array
        (
            [c.name] => Rwanda
            [people] => 2
        )

    [4] => Array
        (
            [c.name] => Canada
            [people] => 1
        )
)
---
```


## Sending multiple statements in one transaction

There are 2 ways for sending multiple statements in one and only transaction.

1. Using an open transaction throughout the process (see the next section "Transaction Management")
2. Using a `PreparedTransaction` instance


### PreparedTransaction

Handy if you want to keep a `PreparedTransaction` instance throughout your code :

```php
$tx = $client->prepareTransaction()
    ->pushQuery($q, $p)
    ->pushQuery($q2)
    ->pushQuery($q3)
    ->commit();
```


## Transaction Management

The library comes with a Transaction Manager removing you the burden of parsing commit urls and transaction ids.

Usage is straightforward :

```php
$transaction = $client->createTransaction();
$transaction->pushQuery('MERGE (n:User {id: 123}) RETURN n');
$transaction->pushQuery('MATCH (n) RETURN count(n)');
$transaction->commit();

// Other methods :
$transaction->rollback();
$transaction->getLastResult // Returns the result of the last transaction statements
$transaction->getResults() // Returns the results of all the statements
```

Note that a commited or a rolled back transaction will not accept pushQuery calls anymore.

## Working with multiple connections

### Define multiple connections

You can work with as many connections you want :

```php
$client = ClientBuilder::create()
    ->addConnection('default', 'http', 'localhost', 7474)
    ->addConnection('testserver1', 'http', 'testserver.local', 7474)
    ->addConnection('testserver2', 'http', 'testserver2.local',7474)
    ->build();
```

When calling commands, you can specify to which connection the command has to be executed by passing the connection alias as argument :

```php
$client->getRoot('default');
$client->sendCypherQuery('MATCH (n) RETURN count(n) as total', array(), 'testserver1');
```

## HA (High-Availibilty)

### HA Mode for Neo4j Enterprise

NB: There are ongoing changes for improving the HA Mode of the Enterprise Edition, stay tuned ;-)

The library provide a powerful system for handling the HA Mode of Neo4j available in Neo4j Enterprise.

The convention is to send write queries to the master, and read queries to slaves.

To enable the HA Mode and defining which connections are master or slave, you need to add some method call during the build process of the
client :

```php

$client = ClientBuilder::create()
    ->addConnection('server1', 'http', '193.147.213.3', 7474)
    ->addConnection('server2', 'http', '193.147.213.4', 7474)
    ->addConnection('server3', 'http', '193.147.213.7', 7474)
    ->setMasterConnection('server1') // Define the Master Connection by providing the connection alias
    ->setSlaveConnection('server2') // Idem for slave connections
    ->setSlaveConnection('server3')
    ->enableHAMode()
    ->build();
```

Your configuration is now set. The client has convenience methods for HA usage, respectively `sendReadQuery` and `sendWriteQuery`.

Automatically, write queries will be executed against the `master` connection, while `read` queries against slave connections.

If a slave is no more reachable, it will automatically check if other slaves are configured. If yes it will attempt to send the query again 
to the other slave connections.

If you have loggers settled up, an `alert` entry will be logged to inform you of slave connection failure.

```php

$client->sendWriteQuery('MERGE (n:User {firstname: "Chris"})'); // Will be sent to the "server1" connection

$client->sendReadQuery('MATCH (n:User) RETURN n'); // Will be sent to the "server2" connection
```

NB: The above methods do not take the `$conn` argument as the choice of the connection is done in the library internals.

Note: You can always retrieve the Master and the first Slave connection alias from the client if you want to specify them when using other commands :

```php

$client->getRoot($client->getWriteConnectionAlias()); // Will be run against the master connection

$client->listLabels($client->getReadConnectionAlias()); // Will be run agains the first found slave connection
```

Please also note, that when using the *Transaction Manager*, all queries will be run against the same connection. *Transaction*  instances 
are bounded to one and only connection.

### Checking your Master/Slave Configuration

You can check that your defined master and slaves connections are running and setup correctly :

```php
$client->checkHAMaster('server1');      // Returns true|false
$client->checkHASlave('server2');       // Returns true|false
$client->checkHAAvailable('serverxxx'); // Returns master|slave|false
```


### Query Mode Headers

When the High Availibity Mode is enabled, an additional header will be set to the http request. This header defines the query mode of 
the transaction : `READ` or `WRITE`.

By default, all queries, live transactions and prepared transactions are assumed `WRITE`.

You can define it your self by using the Client's constants `Client::NEOCLIENT_QUERY_MODE_WRITE` and `Client::NEOCLIENT_QUERY_MODE_READ` 
or by simply passing a string with those values to the following methods:

```php
$client->sendCypherQuery($query, $params, $conn = null, $queryMode = Client::NEOCLIENT_QUERY_MODE_READ);

$client->createTransaction($conn = null, Client::NEOCLIENT_QUERY_MODE_WRITE);

$client->prepareTransaction($conn = null, Client::NEOCLIENT_QUERY_MODE_WRITE);
```

The default headers are the following :

* The header key is `Neo4j-Query-Mode`
* The write transactions will have a header value of : `NEO4J_QUERY_WRITE`
* The read transactions will have a header value of : `NEO4J_QUERY_READ`

You can define your own headers definition via the configuration :

##### yaml

```yaml
neoclient:
	ha_mode:
		enabled: true
		query_mode_header_key: MY_HEADER
		read_mode_header_value: QUERY_READ
		write_mode_header_value: QUERY_WRITE
```

##### php

```php
$client = ClientBuilder::create()
	// .. other settings
	->enableHAMode()
	->configureHAQueryModeHeaders($headerKey, $writeModeHeaderValue, $readModeHeaderValue)
	->build();
```

## Secured connections

### Authenticated connection

#### For Neo4j 2.2

Provide the user and the password when building the connection :

```php
$client = ClientBuilder::create()
    ->addConnection('default', 'http', 'myserver.dev', 7474, true, 'username', 'password')
    ->build();
```

#### changing the password

The client has a built-in method for changing the password :

```php
$client->changePassword('user', 'newPassword');
```

#### Before Neo4j 2.2 using the Auth Extension

If you are using the `authenticated-extension` or using [GrapheneDB](http://graphenedb.com) instance, you can specify to use the authMode for the connection and provide your username
and password :

```php
$client = ClientBuilder::create()
    ->addConnection('default', 'http', 'myserver.dev', 7474, true, 'username', 'password')
    ->build();
```

Your password will automatically be encoded in base64 for the Authorization.

### Convenience methods for the `Authentication extension`

#### listUsers | List the users registered in the connection authentication extension

```php
$client->listUsers();
```

```json
{"john"}
```

#### addUser | Adds a user to the extensions

```php
$client->addUser('John', 'password');
```

```json
OK
```

The third argument of the `addUser` method is the `readOnly` parameter, default to false

```
$client->addUser('john', 'password', true);
```

```json
OK
{"john"}
```

#### removeUser | Removes a user from the extension

```php
$client->removeUser('user', 'password');
```

```json
OK
```

## Events & Logging

### Event Listeners

You can add listeners to hook into the built-in event system, for all list of all available events, look inside the
`NeoEvents.php` file.

A listener can be a \Closure instance, an object implementing an __invoke method,
a string representing a function, or an array representing an object method or a class method.

Event listeners are currently not configurable with the yaml file, it will come soon...

```php
$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->addEventListener('foo.action', function (Event $event))
    ->build();
```

### Logging

You can add your logging system or ask the library to use the default built-in logging mechanism (currently only stream and ChromePHP
are supported).

If you integrate your own logging, he must be compatible with the PSR-3 standard.

```php
// Adding your own logging
$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->setLogger('app', MyLogger) // My Logger must implement Psr\Log\LoggerInterface
    ->build();
```

The library is shipped with two default Monolog handlers that you can use : Stream and ChromePHP. Registering them is straightforward :

```php

$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->createDefaultStreamLogger('name', '/path/to/your/log/file.log', 'debug')
    ->createDefaultChromePHPLogger('app', 'debug');
    ->build();
```

## Extending NeoClient


### Creating your own commands

You can extend the library by creating your own commands.

Create your `Command` class, this class must extend `Neoxygen\NeoClient\Command\AbstractCommand` and must implement
the `execute` method.

By extending the AbstractCommand class, you have access to the http client, and also the connection alias that is used
when invoking the command.

The best way to execute a command is by calling the `send` request of the HttpClient and passing the `method`, `path`,
`body` and `connectionAlias` arguments :

```php
httpClient->send($method, $path, null, $this->connection);
    }
}
```

Then you have to register your command when building the client by passing an alias for your command and the class FQDN :

```php
$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->registerCommand('my_super_command', 'My\Command\Class\Namespace')
    ->build();
```

Then to use your command, just use the invoke method of the client :

```php
$command = $client->invoke('custom_get_extensions');
$extensions = $command->execute();
print_r($extensions);
```

### Creating an Extension

When you have a lot of commands, it may be good to create a command extension. Creating a command extension is quite simple :

You need to create a class that extends the `Neoxygen\NeoClient\Extension\AbstractExtension`, and you have to
implement the `getAvailableCommands` method that return an array of command aliases bounded to command classes :

```php

use Neoxygen\NeoClient\Extension\NeoClientExtensionInterface;

class MyExtension implements NeoClientExtensionInterface
{
    public static function getAvailableCommands()
    {
        return array(
            'custom_get_extensions' => 'My\Command\Class',
            'custom_other_exec' => 'My\Other\Class'
            );
    }
}
```

And then register your extension when building the client by giving an alias and the class FQDN of your extension :

```php
$client = ClientBuilder::create()
    ->addDefaultLocalConnection()
    ->registerExtension('my_extension_alias', 'My\Extension\Class\Namespace')
    ->build();
```

## Production settings

The library uses a Dependency Injenction Container and service files definitions, while this provide full flexibility and
robust code, this comes at a price.

By providing a cache path where the container and all the configuration can be dumped, you'll have the best of both worlds.

```yaml
connections:
  default:
    scheme: http
    host: localhost
    port: 7474
  testdb:
    scheme: http
    host: testserver.dev
    port: 7475

cache:
  enable: true
  cache_path: /dev/project/cache/
```

Don't forget to add full permissions to the cache path : `chmod -R 777 your/cache/path` and also to empty the cache dir when
you do changes to your configuration.

### Configuration Reference

### YAML

```yaml
connections:
  default:
    scheme: http
    host: localhost
    port: 7474
  testdb:
    scheme: http
    host: testserver.dev
    port: 7475
    auth: true
    user: user
    password: password

ha_mode:
    enabled: true
    type: community|enterprise
    master: default
    slaves:
        - testdb

auto_format_response: true

cache:
  enabled: true
  cache_path: /dev/project/cache

custom_commands:
  my_command:
    class: My\Command\Class

extensions:
  my_extension:
    class: My\Extension\Class
```

### License

The library is released under the MIT License, refer to the LICENSE file.

### Tests

To run the test suite, you need to copy the `tests/database_settings.yml.dist` to `tests/database_settings.yml`, as it will
create nodes to a real database.

Run `vendor/bin/phpunit`


Comments
  • How to handle server plugins

    How to handle server plugins

    Hi Christophe,

    I wrote a server plugin and I want to call this new plugin using your bundle. Is it possible? Do I need to create a new command (that extends AbstractCommand)?

    opened by mehmetbilgin 9
  • unable to connect  godaddy server to grapheenDB

    unable to connect godaddy server to grapheenDB

    Hi, i have use Neoxygen\NeoClient in my project , the code and website is hosted in godaddy, now i want to config from godaddy to grapheendb db .. im getting the error while connecting ...can u please help me out...

    my config file code looks like this in godaddy

    addConnection('default', **'http',** 'tobotob.sb02.stations.graphenedb.com', 24789, true, 'tobotob', 'TNhMM7Oec6X6YQ6DUqTO') ->setDefaultTimeout(20) ->setAutoFormatResponse(true) -> build(); ?>

    below one is the error im getting

    Fatal error: Uncaught exception 'Neoxygen\NeoClient\Exception\HttpException' with message 'Error on Connection "default" with message "cURL error 7: Failed to connect to tobotob.sb02.stations.graphenedb.com port 24789: Connection refused (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)"' in /home/balavariyam/public_html/php/vendor/neoxygen/neoclient/src/EventListener/HttpRequestEventSubscriber.php:74 Stack trace: #0 [internal function]: Neoxygen\NeoClient\EventListener\HttpRequestEventSubscriber->onHttpException(Object(Neoxygen\NeoClient\Event\HttpExceptionEvent), 'neoclient.http_...', Object(Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher)) #1 /home/balavariyam/public_html/php/vendor/symfony/event-dispatcher/EventDispatcher.php(181): call_user_func(Array, Object(Neoxygen\NeoClient\Event\HttpExceptionEvent), 'neoclient.http_...', Object(Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher)) #2 /home/balavariyam/public_html/php/vendor/symfony/event-dispatcher/EventDispatcher.php(46): Symfo in /home/balavariyam/public_html/php/vendor/neoxygen/neoclient/src/EventListener/HttpRequestEventSubscriber.php on line 74

    opened by pavan2540 6
  • Issue with custom command

    Issue with custom command

    I am trying to create a custom command to do a simple POST Rest command based on the documentation.

    I am able to register and call the alias fine.

    $this->neo4j = NeoClient\ClientBuilder::create()
                        ->addConnection('default','http', 'localhost',7474, true, 'neo4j', 'neo4j')
                        ->registerCommand('geomlink', 'Minds\Core\Data\Neo4j\Commands\GeomLink')
                        ->setAutoFormatResponse(true)
                        ->setDefaultTimeout(20)
                        ->build();
    

    I then get a fatal error when I run the invoke command

    $this->neo4j->invoke($command);
    

    error: Call to a member function buildRequest() on a non-object

    Any ideas?

    opened by markharding 6
  • clear cache?

    clear cache?

    I'm using the symfony 2 framework and there is a clear:cache command available there If there is a way within this library to clear the cached container, i will be able to hook this up by calling this method

    opened by flip111 5
  • very slow response time

    very slow response time

    hello, i have installed and everything is fine except the response from neo4j (local) is very slow. i wait about 3-5 second to get a response even it is very simple query ,can you solve it? thanks

    opened by szewang2805 5
  • getResult returns nothing

    getResult returns nothing

    Hi,

    I am trying to run this piece of code (similar to a problem I have found here):

    $query = "match (i:institutions)-[:worksAt]-(n:persons) WHERE toLower(i.name) CONTAINS toLower('moldova') return n";
    
    $neo = $this->client->sendReadQuery($query);
    
    $results = $this->client->getResult();
    //tried this too:
    //$results = $neo->getResult();
    
    
    foreach ($results->getNodes() as $node)
    {
        $nodes[] = [
            'name' => $node->getProperty('name'),
            'id' => $node->getId()
        ];
    }
    

    When I do print_r on $neo right after sendReadQuery, I can see the object, and the result of the query is there, just one row. Problem is, $results is emty, it is not an object. I have tried getRows(), getTableFormat(), all sort of combinations, nothing works. getResponse returns me that same object with which none of the functions work. All I want to do is get all the nodes out with their properties in some sort of array.

    It must be something really simple I am missing out.

    Thanks, Ivan

    opened by ivan83 4
  • Optional match return null and crash on Result class

    Optional match return null and crash on Result class

    Im trying to return from the database nodes that some of them have the match and dome not. because is return null its crash on Result class here :

    public function addRelationshipToIdentifier($relationshipId, $identifier) { if (isset($this->identifiers[$identifier])) { foreach ($this->identifiers[$identifier] as $rel) { if ($rel->getId() === $relationshipId) {

                        return;
                    }
            }
        }
        $this->identifiers[$identifier][] = $this->getRelationship($relationshipId);
    }
    

    it can be fix by adding check if $rel is not null. i dont want to do that by myself (because future update) there is a way to fix it ? or update it in next version

    opened by liran89b 4
  • PHP 5.4 composer build error due to Symfony/Config

    PHP 5.4 composer build error due to Symfony/Config

    Composer output

     Problem 1
    
    - Installation request for symfony/filesystem 3.0.x-dev -> satisfiable by symfony/filesystem[3.0.x-dev].
    
    - symfony/filesystem 3.0.x-dev requires php >=5.5.9 -> no matching package found.
    
    Problem 2
    
    - Installation request for symfony/filesystem dev-master -> satisfiable by symfony/filesystem[dev-master].
    
    - symfony/filesystem dev-master requires php >=5.5.9 -> no matching package found.
    
    Problem 3
    
    - symfony/filesystem 3.0.x-dev requires php >=5.5.9 -> no matching package found.
    
    - symfony/config 2.7.x-dev requires symfony/filesystem ~2.3|~3.0.0 -> satisfiable by symfony/filesystem[3.0.x-dev].
    
    - Installation request for symfony/config 2.7.x-dev -> satisfiable by symfony/config[2.7.x-dev].
    
    opened by markharding 4
  • Relationship->getProperty is either true of null

    Relationship->getProperty is either true of null

    The following line:

    $value = isset($this->properties[$name]) ?: null;
    

    will always evaluate to true or null.

    Leaving out the middle part of PHP's ternary operator will make it equal to the first part, which is a boolean. I can send in a pull request, but I don't know where and how you would want those.

    The following should work:

    $value = isset($this->properties[$name]) ? $this->properties[$name] : null;
    
    opened by JackieXu 4
  • Fixed

    Fixed "next significant release" tilde operator use

    The current use of ~x.y.z notation in composer.json makes it impossible, for example, to use a version of Monolog greater than 1.3.x. Using ~x.y instead would allow library users to use newer versions of these dependencies while still requiring that the minimum to be required.

    This was working the way I suggest until this commit, which introduced more strictness.

    Reference: Composer documentation for next significant release

    opened by michaelmoussa 4
  • Fixes issues reported by Mulkave

    Fixes issues reported by Mulkave

    • Fix issue #6 where Node::getProperties returned key=>true instead of key=>value pair
    • Fix issue #7 possibility to add multiple labels at once
    • ListIndex output improvement, fix issue #9
    • Changed Parameter order in getPathBetween method, fix issue #10
    • You can now specify the internal nodeId in the startNode and endNode arrays of getPathBetween fix issue #11
    opened by ikwattro 4
  • I need help working with Neo4j database in php

    I need help working with Neo4j database in php

    Good day Everyone, Am trying to work on neo4j graph database using php. I saw your amazing projects on github

    https://github.com/neoxygen/neo4j-neoclient

    Please I have install xampp and my php is running locally. I have also installed neo4j graph database and its running locally too. I have also install the projects via composer as per "composer require neoxygen/neoclient"

    when I try to connect via your sample code below and print the version. it seems its not connecting. it throws error

    Fatal error: Uncaught Neoxygen\NeoClient\Exception\HttpException: Error on Connection "default" with message "Client error: GET http://localhost:7474/db/data resulted in a 401 Unauthorized response: { "errors" : [ { "code" : "Neo.ClientError.Security.Unauthorized", "message" : "No authentication header su (truncated...) " in C:\xampp\htdocs\neo_oxygen\src\EventListener\HttpRequestEventSubscriber.php:74 Stack trace: #0 C:\xampp\htdocs\neo_oxygen\vendor\symfony\event-dispatcher\EventDispatcher.php(184): Neoxygen\NeoClient\EventListener\HttpRequestEventSubscriber->onHttpException(Object(Neoxygen\NeoClient\Event\HttpExceptionEvent), 'neoclient.http_...', Object(Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher)) #1 C:\xampp\htdocs\neo_oxygen\vendor\symfony\event-dispatcher\EventDispatcher.php(46): Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(Array, 'neoclient.http_...', Object(Neoxygen\NeoClient\Event\HttpExceptionEvent)) #2 C:\xampp\htdocs\neo_oxygen\src\HttpClient\GuzzleHttpCl in C:\xampp\htdocs\neo_oxygen\src\EventListener\HttpRequestEventSubscriber.php on line 74

    below is your connection Code

    
    <?php
    
    require_once 'vendor/autoload.php';
    
    use Neoxygen\NeoClient\ClientBuilder;
    
     $client = ClientBuilder::create()
        ->addConnection('default','http','localhost',7474)
        ->build();
    
    
    
    $root = $client->getRoot();
    
    //print_r($root);
    
    $version = $client->getNeo4jVersion();
    print_r($version);
    
    

    very important, My neo4j local database server has username: neo4j and password: neo65gbcAB

    All I want to implement is how to 1.)Connect to my neo4j local database server 2.) create database eg Test_db via php 3.) insert, select, update and delete data from graph database using php. please can you also help me with that

    Thanks

    opened by nkem56 1
Owner
Neoxygen
Neoxygen
ReactPHP HttpClient Adapter for Guzzle6, for Guzzle5 check ReactGuzzleRing

react-guzzle-psr7 ReactPHP HttpClient Adapter for Guzzle6, for Guzzle5 check ReactGuzzleRing Installation To install via Composer, use the command bel

Cees-Jan Kiewiet 69 Dec 8, 2022
Retrofit implementation in PHP. A REST client for PHP.

Retrofit PHP Retrofit is a type-safe REST client. It is blatantly stolen from square/retrofit and implemented in PHP. ❗ UPGRADE NOTICE ❗ Version 3 int

null 153 Dec 21, 2022
A Chainable, REST Friendly, PHP HTTP Client. A sane alternative to cURL.

Httpful Httpful is a simple Http Client library for PHP 7.2+. There is an emphasis of readability, simplicity, and flexibility – basically provide the

Nate Good 1.7k Dec 21, 2022
Free Cricket API - Live Cricket Score JSON API 🏏

Free Cricket API ?? Live Cricket Score API ?? unofficial API Data Fetched from Cricbuzz.com This is an unofficial API and not Linked or Partnered with

Santhosh Veer 60 Jan 2, 2023
PHP Curl ile letgo api kütüphanesi oluşturuldu. php ile letgo giriş yap.

Kendi LETGO API ile işlemler gerçekleştirelim. // email işlemleri $server = 'imap.gmail.com'; $user = '[email protected]'; $pass = 'password'; $port = 9

Görkem Bayraktar 2 Nov 3, 2022
PHP cURL for feed Instagram Graph API

php-curl-instagram-graph PHP cURL for feed Instagram Graph API Script made based on the new (2020) Instagram API that requires authorization token gen

null 12 Apr 13, 2022
KTMB (Keretapi Tanah Melayu Berhad) Station Schedule Checker in PHP via MyRailTime 2.0's API

KTM Station Schedule Checker & Journey Planner in Web Form (PHP) KTMB (Keretapi Tanah Melayu Berhad) Station Schedule Checker & Journey Planner in Web

Sam Sam 1 Jun 24, 2022
Transform your WordPress site into a modern GraphQL server: graphql-api.com.

GraphQL API for WordPress Transform your WordPress site into a modern GraphQL server: graphql-api.com. This plugin is the implementation for WordPress

GraphQL API 151 Dec 14, 2022
A YOURLS plugin allowing the shortening of multiple URLs with one API request.

Bulk URL Shortening - a YOURLS plugin Plugin for YOURLS Plugin URI: github.com/tdakanalis/bulk_api_bulkshortener Description: A YOURLS plugin allowing

Themistoklis Dakanalis 6 Aug 27, 2022
Creating an all in one AI with a web UI to control it. Create your own AI server and/or sell API keys to other people to use your AI.

+ Currently taking an hour or two break to spend some time with the wife. - Then going to work on auto refreshing the chat and document ingestion so y

null 10 Jun 14, 2023
HTTP header kit for PHP 7.1+ (incl. PHP 8) based on PSR-7

HTTP header kit for PHP 7.1+ (incl. PHP 8) based on PSR-7 Installation composer require sunrise/http-header-kit How to use? HTTP Header Collection Mor

Sunrise // PHP 63 Dec 31, 2022
Express.php is a new HTTP - Server especially made for RESTful APIs written in PHP.

express.php Express.php is a new HTTP - Server especially made for RESTful APIs written in PHP. Features Fast The Library is handles requests fast and

null 5 Aug 19, 2022
Guzzle, an extensible PHP HTTP client

Guzzle, PHP HTTP client Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Simple interf

Guzzle 22.3k Jan 2, 2023
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
PHP's lightweight HTTP client

Buzz - Scripted HTTP browser Buzz is a lightweight (<1000 lines of code) PHP 7.1 library for issuing HTTP requests. The library includes three clients

Kris Wallsmith 1.9k Jan 4, 2023
HTTPlug, the HTTP client abstraction for PHP

HTTPlug HTTPlug, the HTTP client abstraction for PHP. Intro HTTP client standard built on PSR-7 HTTP messages. The HTTPlug client interface is compati

The PHP HTTP group 2.4k Dec 30, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
Unirest in PHP: Simplified, lightweight HTTP client library.

Unirest for PHP Unirest is a set of lightweight HTTP libraries available in multiple languages, built and maintained by Mashape, who also maintain the

Kong 1.3k Dec 28, 2022
PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs

PHP Curl Class: HTTP requests made easy PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs. Installation Requirements Quic

null 3.1k Jan 5, 2023