1

I've been using codeigniter 2.x on a personal project of mine. The database is MySql, but i've decided to move to Neo4J.

I used the library called GraphAware, which i have installed. It runs as intended so far. My test code is as follows :

$user       = 'neo4j';
$password   = 'mypass';
$host       = 'myhost:7474';
$myDB       = 'mydb';

$client = ClientBuilder::create()
        ->addConnection('default','http://'.$user.':'.$password.'@'.$host.'/'.$myDB)
        ->build();

$query = "MATCH (n:user) RETURN n.username";

$result = $client->run($query);

So far so good!

My issue is the following : how can i automatically connect to the neo4j database on page creation, so that the connection doesn't have to be manually created every time?

In my mind, the above code would just become something like this :

$db = $this->db->load('neo4j');

$query = "MATCH (n:user) RETURN n.username";

$result = $db->run($query);

I've been searching around in codeigniter, i can't seem to find a solution, due to a lack of understanding of some core concepts.

Do you have an idea how to proceed.

Thanks.

Loïc.

Loïc N.
  • 353
  • 3
  • 17
  • Generally you would create a neo4j service that will create the connection once, and inject this service where you need it. Maybe look for Codigniter + DependencyInjection on google. I'm the maintainer of GraphAware client but I have zero experience with CI. – Christophe Willemsen Jul 05 '16 at 11:39
  • Thank you for your help Christophe, but i went with a different solution. Loïc. – Loïc N. Jul 06 '16 at 09:50

1 Answers1

0

My objective was to automatically connect to the Neo4J database at every page load and not having to manually connect to the db every time i wanted to access it. My concern was also to not modify any of the codeigniter system files.

Edit : Updated solution. My first solution was problematic as it required the model to call the controller to obtain the DB object. This was impractical and violated the MVC workflow, where it is the controller who should call the model, and not the other way around.

Updated solution:

For this solution, we need to create 2 things :

  • A new library class
  • A new controller class

Also, optional but recommended:

  • Modify the config file and insert your db details and credentials

1) Create a new library class in application/libraries

We want to create a library class that will be loaded and initialized by our new controller, and later accessed by our model.

This library will only contain 2 functions :

  • connect() : Performs a connection to the database and saves the database object in the private class variable $neo4j.
  • get_db() : Returns the database object that was saved in the function connect()

application/libraries/neo4j.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
require_once 'vendor/autoload.php';
use GraphAware\Neo4j\Client\ClientBuilder;

class Neo4j {
    private $neo4j;

    //connect to the neo4j database
    public function connect(){
        //load CI to access config files 
        $CI = & get_instance();

        //Get database details from the config file.
        $user       = $CI->config->item('username');
        $password   = $CI->config->item('password');
        $host       = $CI->config->item('hostname');
        $port       = $CI->config->item('port');
        $database   = $CI->config->item('database');

        //build connection to db
        $client = ClientBuilder::create()
                ->addConnection('default', 'http://'.$user.':'.$password.'@'.$host.':'.$port)
                ->build();

        //save the connection object in a private class variable
        $this->neo4j    = $client;
    }

    //Returns the connection object to the neo4j database
    public function get_db(){
        return $this->neo4j;
    }
}

2) Create a new controller that will load our neo4j library and perform the database connection.

This step is also simple and straightforward. We create a new controller that will extend whatever your current controller class is. I called this controller Neo4j_controller.

This controller only contains a constructor. All we really want to do is to load our neo4j library and initiate the DB connection.

application/core/Neo4j_controller.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Neo4j_controller extends TNK_Controller{

    //connect to neo4j db on instantiation
    function __construct(){
        parent::__construct();
        //load the neo4j library that we created
        $this->load->library('neo4j');
        //connect to the db
        $this->neo4j->connect();
    }
}

3) In your model, you can now access the DB object and use it to perform queries.

Example from one of my models

//Return all sublists of list $list
    public function get_sublists($list){
        //Get the DB object by calling the get_db function from our neo4j library.
        //Since the neo4j library has been loaded by the controller, we can access it
        //by just calling $this->neo4j.
        $db = $this->neo4j->get_db();

        //Write your cypher query
        $query = "match (n:item_list{name:'$list'})-[:sublist*]->(sublist:item_list) sublist.name as list";

        //Run your query
        $result = $db->run($query);

        //Return the result. In this case, i call a function (extract_result_g)
        //that will neatly transform the response into a nice array.
        return $this->extract_results_g($result);   
    }

4) Modify your config file (optional)

I had issues with that. In the end, I created my own config file called neo4jDatabase.php .

If you also encounter issues with creating your own config files, or modifying the current config file, you can still hard-code your database data in your neo4j library file. This is bad practice, but when it's gotta work, it's gotta work.

neo4jDatabase.php

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$config['hostname'] = 'test.mysite.me';
$config['username'] = 'neo4j';
$config['password'] = 'my_password';
$config['database'] = 'mygraphdb';
$config['port']     = '7474';

/* End of file neo4jDatabase.php */
/* Location: ./application/config/neo4jDatabase.php */

This completes the updated solution. Also, please note that i am using codeIgniter HMVC. So i don't know if some of the things i have done are only possible because of that (like calling a library from the model).

Please, below, find the old solution. It should not be used.

Old solution (problematic as it requires your model to call your controller. This is not something that should happen)

For this solution, i simply create a new Controller that will need to be instantiated by any controller wishing to use the Neo4j database.

1) We create a new controller (here called Neo4j_controller)

New controller : Neo4j_controller.php

require_once 'vendor/autoload.php';
use GraphAware\Neo4j\Client\ClientBuilder;

class Neo4j_controller extends Your_Normal_Controller{

    private $neo4j;

    //connect to db on instantiation
    function __construct(){
        parent::__construct();

        $this->connect();
    }

    //Connect to the neo4j db
    private function connect(){
       //I'll get these from config file later on
       $user       = 'neo4j';
       $password   = 'mypass';
       $host       = 'myhost:7474';
       $myDB       = 'mydb';

       //build connect to db 
       $client = ClientBuilder::create()
                ->addConnection('default', 'http://'.$user.':'.$password.'@'.$host.'/'.$myDB)
                ->build();
        //save the connection object in a private class variable
        $this->neo4j    = $client;
    }

    //Returns the connection object to the neo4j database
    public function get_db(){
        return $this->neo4j;
    }
}

2) Make your normal controller instantiate Neo4j_controller

class Test extends Neo4j_controller {...}

3) In your controller (here called Test), create a function in which you will :

  • Get the DB object by calling $this->get_db()

  • Use that object to execute your query

Function created in our Test controller, that sends a query to the neo4j database:

public function db_query(){

    $db = $this->get_db();

    $query = "match (n:user) return n";

    print_r($db->run($query)->getRecords());
  }

When you call the function db_query, it returns the users nodes, without requiring us to write manually any code to connect to the neo4j database.

Loïc.

Loïc N.
  • 353
  • 3
  • 17
  • Looks good to me. I just started using Neo4j and graphaware and came up with almost exactly this same solution. I didn't want to have to instantiate the graphaware client everywhere and so I built a db class as a bridge between the rest of my app and the driver. Works great and keeps everything clean. – Bryan Chapel Jul 19 '16 at 00:26
  • Hello Bryan. I actually modified the solution because i couldn't call my controller from my model to access the db object (and it's bad practice anyway since it kind of break the MVC workflow). So what i did was create a library which is responsible for connecting to the neo4j db. The controller calls the library in its constructor to initiate the connection, and save the db object in the library class. After that, from my model, i just have to call $this->neo4j->get_db() to obtain my db object. Sorry, i forgot to update my post with that new solution. – Loïc N. Jul 20 '16 at 06:00