Search code examples
phpdatabasecodeigniterneo4jgraphaware

Codeigniter : Automatic connection to Neo4J database


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.


Solution

  • 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.