-
Notifications
You must be signed in to change notification settings - Fork 1
The Node class
Index > Database > The Node Class
The SnooPHP\Model\Node
class is an extension of the Model
class.
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.
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.
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