public function getRoot()
{
// Empty node, let's try to get the first available root, ie lft=1
if (!$this->getId()) {
$this->load(array('lft' => 1));
}
// Sanity checks on current node position
if ($this->lft >= $this->rgt) {
throw new TreeInvalidLftRgtCurrent();
}
// If this is a root node return itself (there is no such thing as the root of a root node)
if ($this->isRoot()) {
return $this;
}
if (empty($this->treeRoot) || !is_object($this->treeRoot) || !$this->treeRoot instanceof TreeModel) {
$this->treeRoot = null;
// First try to get the record with the minimum ID
$db = $this->getDbo();
$fldLft = $db->qn($this->getFieldAlias('lft'));
$fldRgt = $db->qn($this->getFieldAlias('rgt'));
$subQuery = $db->getQuery(true)->select('MIN(' . $fldLft . ')')->from($db->qn($this->tableName));
try {
$root = $this->getClone()->reset()->whereRaw($fldLft . ' = (' . (string) $subQuery . ')')->firstOrFail();
if ($this->isDescendantOf($root)) {
$this->treeRoot = $root;
}
} catch (\RuntimeException $e) {
// If there is no root found throw an exception. Basically: your table is FUBAR.
throw new TreeRootNotFound($this->tableName, $this->lft);
}
// If the above method didn't work, get all roots and select the one with the appropriate lft/rgt values
if (is_null($this->treeRoot)) {
// Find the node with depth = 0, lft < our lft and rgt > our right. That's our root node.
$query = $db->getQuery(true)->select(array($db->qn('node') . '.' . $fldLft, '(COUNT(' . $db->qn('parent') . '.' . $fldLft . ') - 1) AS ' . $db->qn('depth')))->from($db->qn($this->tableName) . ' AS ' . $db->qn('node'))->join('CROSS', $db->qn($this->tableName) . ' AS ' . $db->qn('parent'))->where($db->qn('node') . '.' . $fldLft . ' >= ' . $db->qn('parent') . '.' . $fldLft)->where($db->qn('node') . '.' . $fldLft . ' <= ' . $db->qn('parent') . '.' . $fldRgt)->where($db->qn('node') . '.' . $fldLft . ' < ' . $db->q($this->lft))->where($db->qn('node') . '.' . $fldRgt . ' > ' . $db->q($this->rgt))->having($db->qn('depth') . ' = ' . $db->q(0))->group($db->qn('node') . '.' . $fldLft);
// Get the lft value
$targetLeft = $db->setQuery($query)->loadResult();
if (empty($targetLeft)) {
// If there is no root found throw an exception. Basically: your table is FUBAR.
throw new TreeRootNotFound($this->tableName, $this->lft);
}
try {
$this->treeRoot = $this->getClone()->reset()->whereRaw($fldLft . ' = ' . $db->q($targetLeft))->firstOrFail();
} catch (\RuntimeException $e) {
// If there is no root found throw an exception. Basically: your table is FUBAR.
throw new TreeRootNotFound($this->tableName, $this->lft);
}
}
}
return $this->treeRoot;
}