Skip to content

The Node class

Andrea Mecchia edited this page Jul 4, 2018 · 4 revisions

Index > Database > The Node Class


The SnooPHP\Model\Node class is an extension of the Model class.

Nodes and edges

In a relational database we may identify entities and relationships.

A Node object represents an entity of the database (e.g. a user, a post, a group). Its edges represent the connections with other nodes.

The Node class provides a way to navigate down these edges, building an intricate graph of nodes.

Define a node edges

First we need to define the out connections for a specific node class. This is done by defining a set of methods starting with the e_ prefix:

use SnooPHP\Model\Node;

class User extends Node
{
	/**
	 * User groups
	 * 
	 * @return Collection
	 */	
	public function e_groups()
	{
		return $this->hasMany("Group");
	}
}

The default prefix can be changed: it is a static property of the node class:

class User extends Node
{
	protected static $edgePrefix = "edge_";
	public function edge_groups() {}
}

For security reasons it is recommended not to set an empty string as the prefix

In the current implementation, edge methods take no parameter and can return any type of data. If a Node or a Collection object is returned, its edges are evaluated as well.

Controlling graph expansion

When we follow an edge we say that we expand the node over the edge, because we are actually incorporating the information from the edge inside the node.

We do this using Node::expand(array|string $edges = []) method. This method takes as parameter a string or an array that controls which edges to expand:

// As array
$edges = [
	"groups"	=> [
		"events"	=> [],
		"photos"	=> [],
		"members"	=> [],
	],
	"friends"	=> []
];

// Equivalent string
$edges = "groups(events,photos,members),friends";

// Edges to expand on first node: 'groups' and 'friends'
// Edges to expand on 'groups' nodes: 'events', 'photos' and 'members'

The data retrieved from each edge is appended as a property to the expanded node:

$user->expand("groups(events,photos,members),friends");
echo to_json($user);
{
	"username": "charles",
	"email": "charles.x@marvel.com",
	"groups": [
		{
			"id": 123,
			"name": "x-men",
			"events": [],
			"photos": [],
			"members": []
		}
	],
	"friends": [
		{
			"username": "erik",
			"email": "magneto@marvel.com"
		},
		{
			"username": "logan",
			"email": "logan@marvel.com"
		}
	]
}

In the string syntax use , or | to delimit edges at the same depth and () to nest subedges:

// Get users who reacted to posts created by users who reacted to this post
$post->expand("supporters(posts(supporters))");

If you care about performance, you should use arrays: string edges in the end are converted to arrays using a simple C translator that translates the string in json, and then converted in a PHP array with json_decode(). That's quite a trip!

To retrieve data from, say, edge friends, it searches for the method static::$edgePrefix."friends". If you define an empty string prefix, then it would be possible to execute any class method with expand():

$edges = $request->input("edges", []);
$user->expand($edges);

// A client could send a request like '?edges=delete' to call 'Model::delete()' on the user object!
// With a non-empty prefix this would not happen because 'User::e_delete()' method does not exist

The Curl library >