Sunday, March 20, 2016

CPANAHierarchyBundle - Symfony and Neo4j

I've just uploaded to Github my last project: HierarchyBundle


This Symfony bundle manages a company hierarchy retrieving and stroring information to a Neo4j database. The hierarchy is based on groups: PHP group is part of Software Developement group, which is part of IT, etc. The users are members of these groups having different kind of roles (manager, employee etc).

I've got the idea for this bundle from the Neo4j documentation: http://neo4j.com/docs/stable/examples-user-roles-in-graphs.html . Basically it says that relational database are not really suited for representing hierarchical data :)

HierarchyBundle is using the Neo4jPHP library https://github.com/jadell/neo4jphp . On top of this I've created a class called GroupHierarchyManagement which contains specific functions for this scope, like retrieving the complete hierarchy above a user:



    /**
  * Return the hierarchy of of groups above one user node
  *
  * @param  Everyman\Neo4j\Node   node
  * @return row| null
  */
    public function getGroupHierarchyOfUser($node)
    {
        $id = $node->getId();

        $queryString =  ' MATCH n-[rel:'. $this->defRelTypeUserToGroup .']->group '.
                        ' WHERE id(n)='.$id.' '.
                        ' WITH group '.
                        ' MATCH p=group-[r:PART_OF*..]->d '.
                        ' WHERE ID(d)='.$this->rootGroupId.' '.
                        ' RETURN nodes(p) as nodes';

        $query = new Query($this->client, $queryString);
        $result = $query->getResultSet();

        if ($result->count() != 0) {
            return $result->current()->current();
        } else {
            return;
        }
    }


This class is configured as a service with the Symfony Dependency Injection Container. There are several parameters to be configured in order to work correctly:


#app/config/config.yml

cpana_hierarchy:
    group_hierarchy_manager_neo4j:
        neo4j_user:  'neo4j'
        neo4j_password:  'parola'
        def_rel_type_group_to_group: 'PART_OF'
        def_rel_type_user_to_group: 'MEMBER_OF'
        root_group_id: '69374'
        manager_role_property: 'manager'
        default_property_group:  'name'
        default_property_user: 'name'


Th first two are the user and password in order to login to Neo4j database. Next are the types (names) of the relations between Groups and Groups or between Users and Groups.
We can say that the team "PHP " is "PART_OF" departmenet "Software developement".
Also we can say employee Kenny is "MEMBER_OF" team "PHP".

You need to specify which is the root group node of your hierarchy by prodiving the Neo4j Id of that node in parameter "root_group_id".

The relation "MEMBER_OF" between Users and Groups has a property called "role", you can define which is the value of this property for users which are managers of a certain group: it can be a number, or explicitly  "manager", or "master" :) etc.

A Group or a User node can have many properties, like name, description for Groups, or age, salary for Users, from these we need to configure which to be displayed by default when we talk about that node, the name should be the most obvious value.

With this service called " group_hierarchy_manager_neo4j" I've built an application with a front side where regular users can browse the data and an Admin area to edit  the data.
Below some photos to get the idea:
Front side:

  

Admin side :


No comments:

Post a Comment