Retrieving polymorphic relationships on custom pivot with withPivot
I am building a system to describe a network. The network comprises a Nodes model which has a many-to-many relationship with itself.
class Node extends Model
{
use HasFactory;
protected $fillable = [
'nodeable_id',
'nodeable_type'
];
// ploymorphic relationship to "classes" of Node
public function nodeable()
{
return $this->morphTo();
}
public function children()
{
return $this->belongsToMany(
Node::class,
'edges',
'parent_id',
'child_id'
)
->as('edge');
}
}
And I have a custom pivot table which represents edges (connections to other nodes)...
class Edge extends Pivot
{
protected $table = 'edges';
public $incrementing = true;
protected $fillable = [
'edgeable_id',
'edgeable_type',
'parent_id',
'child_id',
];
// ploymorphic relationship to "classes" of Edge
public function edgeable()
{
return $this->morphTo();
}
As you can see, both the Node model and the Edge model each have a one to one polymorphic relationship with other tables which define their "class". Nodes are connected to a "nodeable" (nodeables are entity types like company or individual) and Edges are connected to an "edgeable" (edgeable are role types like shareholder or director).
The index method for the Node controller is as follows...
public function index()
{
$nodes = Node::with(['nodeable'])->get();
return $nodes;
}
The index method for the Edge controller is as follows...
public function index()
{
$edges = Edge::with('edgeable'])->get();
return $edges;
}
So, the Nodes index shows all Nodes, and their "nodeable", and the Edges index shows all Edges, and their "edgeable". This is exactly what I want.
The problem starts when I want to explore and map the network, which requires me to traverse relationships. I have built a recursive function below...
public function getEntityNetwork(Node $node, $network = [])
{
$networkBranch = [];
foreach ($node->children as $child) {
//foreach ($node->children as $child) {
if ($child->children->count() > 0) {
$child->network = $this->getEntityNetwork($child, $network);
}
$networkBranch[] = $child;
}
return $networkBranch;
}
This function works well to map the network, but now I want it to be aware of the nodeable of each node and the edgeable of each edge. Normally when working with pivot table with extra columns I just add withPivot() method to the relationship...
public function children()
{
return $this->belongsToMany(
Node::class,
'edges',
'parent_id',
'child_id'
)
->as('edge')
->withPivot(['id', 'edgeable']);
}
However, when this refers to a relationship (edgeable) rather than a column in the pivot table, I get the following error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'edges.edgeable' in 'field list' (Connection: mysql, SQL: select nodes.*, edges.parent_id as pivot_parent_id, edges.child_id as pivot_child_id, edges.id as pivot_id, edges.edgeable as pivot_edgeable from nodes inner join edges on nodes.id = edges.child_id where edges.parent_id = 7)
I have looked at many articles around this subject, but no-one seems to be doing this. This article (https://laracasts.com/discuss/channels/laravel/filtering-relationships-via-intermediate-table-relationship?page=1&replyId=346252) works for normal relation ships, but not polymorphic.
Laracasts feels like my last hope in getting help on this. Perhaps I have the wrong approach entirely, but I could use some help from those with more experience. Thanks in advance.
Please or to participate in this conversation.