Neo4j is an open source, high performance graph database written in Java. It is a type of NoSQL database but much different from MongoDB. Graph databases are made of nodes and relationships, which both have properties. Nodes can represent something like a user and properties of the user may represent name, birthday, and so on. Some examples of relationships are 'friend', 'watch', 'read', 'recommend', and so forth. The primary advantage of using graph databases over document databases is its extraordinary ability to do complex operations very fast when it comes to related objects. Such cases include, but are not limited to, retrieving distinct friends of friends in a social network model who share similar interests or retrieving most recommended restaurants within a specific radius based on different weights from preferences. For further explanation on graph databases and Neo4j, please visit Neo4j Documentation.

Currently there are no fully functional OGM (similar to Doctrine's ORM/ODM) for PHP. But using PHP wrapper for Neo4j REST interface, Neo4jphp, is more than sufficient to build an awesome application. Follow the instructions on the wiki and install the package by using composer. Next, make the Client available as a service.


# services.yml
    neo4j_client.class: Everyman\Neo4j\Client

        class: "%neo4j_client.class%"

Create a directory inside your bundle called Graph. Files inside this directory will function similar to that of a repository in ORM or ODM. Let's create a class called BaseGraph that all graphs will have to extend.


namespace Melt\AwesomeBundle\Graph;

use Everyman\Neo4j\Client;

abstract class BaseGraph
    protected $client;

    public function __construct(Client $client)
        $this->client = $client;

Note that all classes that extend BaseGraph will have to be defined as a service and by doing so, we can inject Neo4j\Client as a dependency. Even though we do not have Doctrine's mapping abilities at our disposal, we can still model and layout the structure for entities. Let's model a simple user.


namespace Melt\AwesomeBundle\Model;

class User
    protected $id;

    protected $username;

    protected $email;

    protected $name;

    // ... Define getter and setter methods

Now, we need some way to convert this model into data that the Neo4j client can understand. Create a directory inside your bundle called GraphTransformer. All the files inside this directory will be responsible for transforming model data into graph properties and vice versa.


namespace Melt\AwesomeBundle\GraphTransformer;

use Melt\UserBundle\Model\User;
use Melt\UserBundle\Graph\UserGraph;
use Everyman\Neo4j\Node;

class UserGraphTransformer
    public function graphToModel(Node $userNode)
        $user = new User();
        $nodeProperties = $userNode->getProperties();

        return $user;

    public function modelToGraphProperties(User $user)
        $properties = array(
            'id'       => $user->getId(),
            'username' => $user->getUsername(),
            'email'    => $user->getEmail(),
            'name'     => $user->getName(),

        return $properties;
} }

Using GraphTransformer seems hack-ish to me, but until a fully functional OGM comes out, this will have to do. Now all we have left is to create a UserGraph. I will prepopulate it with some methods that may be commonly used. Also, let's not forget to add UserGraph to our services.


# services.yml
    # ...

        class: Melt\AwesomeBundle\Graph\UserGraph
        arguments: [@neo4j.client]


namespace Melt\AwesomeBundle\Graph;

use Everyman\Neo4j\Cypher\Query;
use Everyman\Neo4j\Index\NodeIndex;

class UserGraph
     * @return \Everyman\Neo4j\Node
    public function getUserbyUsername($username)
        $queryString = "START n=node:user(username = {username}) ".
                       "RETURN n ".
                       "LIMIT 1";
        $query = new Query($this->client, $queryString, array(
            'username' => $username,
        $result = $query->getResultSet();
        if (count($result) == 0)
            return null;

        $row = $result->current();
        return $row['n'];

    public function createUser($userProperties)
        $userNode = $this->client->makeNode();
        $userIndex = new NodeIndex($this->client, 'user');
        $userIndex->add($userNode, 'username', $userNode->getProperty('username'));
        $userIndex->add($userNode, 'email', $userNode->getProperty('email'));

In our UserGraph class, we created a method to fetch the user node from a username as well as a method to create a user defined by UserGraphTransformer. The createUser method also creates indexes on user email and username for each user. In order to use our code that we wrote, let's head to the controller.

namespace Melt\AwesomeBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Melt\AwesomeBundle\Model\User;
use Melt\AwesomeBundle\GraphTransformer\UserGraphTransformer;

class AwesomeController extends Controller
    // ...
    // Initialize UserGraph as member variable

    // Example
    public function createUserAction(Request $request)
        $user = new User();
        $userGraphTransformer = new UserGraphTransformer();
        $userGraphProperties = $userGraphTransformer->modelToGraphProperties($user);

        // Return some response

This was a very basic implementation of Neo4j. Nowhere near perfect, but hopefully this simple Neo4j integration can point those interested in using Neo4j with Symfony2 toward the right direction.