Last active
August 29, 2015 13:56
-
-
Save potfur/8954044 to your computer and use it in GitHub Desktop.
Self nesting category [nested set]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace gist; | |
/** | |
* Self nesting node | |
* Can use parent_id/order or left/right nested set or convert one to another | |
* | |
* @package gist | |
* @author Michal Wachowski <[email protected]> | |
*/ | |
class Node | |
{ | |
protected $id; | |
protected $left = 0; | |
protected $right = 1; | |
protected $parent_id = 0; | |
protected $order = 0; | |
protected $title; | |
/** @var array|self[] */ | |
public $children = array(); | |
/** | |
* Constructor | |
* | |
* @param array|self[] $children | |
*/ | |
public function __construct($children = array()) | |
{ | |
foreach (get_object_vars($this) as $field => $value) { | |
if (array_key_exists($field, $children)) { | |
$this->$field = $children[$field]; | |
} | |
} | |
} | |
/** | |
* Builds tree using parent_id & order properties | |
* | |
* @return $this | |
*/ | |
public function parentify() | |
{ | |
$tArr = $this->gather(array($this->id => &$this), 'id'); | |
uasort( | |
$tArr, function (self $a, self $b) { | |
return $a->order - $b->order; | |
} | |
); | |
$uArr = array(); | |
foreach ($tArr as $i => &$category) { | |
if (!$category->id) { | |
unset($category); | |
continue; | |
} | |
if (isset($tArr[$category->parent_id])) { | |
$tArr[$category->parent_id]->children[] = &$category; | |
$uArr[] = $i; | |
} | |
unset($category); | |
} | |
foreach ($uArr as $i) { | |
unset($tArr[$i]); | |
} | |
return $this; | |
} | |
/** | |
* Builds tree using nested set left-right properties | |
* | |
* @return $this | |
*/ | |
public function nestify() | |
{ | |
$tArr = $this->gather(array($this->left => $this), 'left'); | |
$lft = &$this->left; | |
$rgt = &$this->right; | |
uasort( | |
$tArr, function (self $a, self $b) use (&$lft, &$rgt) { | |
$lft = (int) min($lft, $a->left, $b->left); | |
$rgt = (int) max($rgt, $a->right, $b->right); | |
return $a->left - $b->left; | |
} | |
); | |
$this->right++; | |
$this->buildSet($this, $tArr); | |
return $this; | |
} | |
/** | |
* Builds set | |
* Internal, used by nestify | |
* | |
* @param $parent | |
* @param $tArr | |
*/ | |
protected function buildSet(&$parent, &$tArr) | |
{ | |
$rArr = array(); | |
while ($category = array_shift($tArr)) { | |
if ($category->left > $parent->left && $category->right < $parent->right) { | |
$parent->children[] = $category; | |
} else { | |
$rArr[] = $category; | |
} | |
} | |
$tArr = $rArr; | |
foreach ($parent->children as $category) { | |
$this->buildSet($category, $parent->children); | |
unset($category); | |
} | |
} | |
/** | |
* Flattens tree to simple array as children in root node | |
* Preserves all property values | |
* | |
* @return $this | |
*/ | |
public function flatten() | |
{ | |
$this->children = $this->gather(); | |
return $this; | |
} | |
/** | |
* Gathers nodes | |
* | |
* @param array $tArr | |
* @param null|string $key | |
* | |
* @return array | |
*/ | |
protected function gather($tArr = array(), $key = null) | |
{ | |
foreach ($this->children as &$category) { | |
if ($key) { | |
$tArr[$category->$key] = &$category; | |
} else { | |
$tArr[] = &$category; | |
} | |
$tArr = $category->gather($tArr, $key); | |
unset($category); | |
} | |
$this->children = array(); | |
return $tArr; | |
} | |
/** | |
* Rebuilds properties in tree | |
* | |
* @param int $i | |
* @param int $parent_id | |
* | |
* @return $this | |
*/ | |
public function rebuild(&$i = 0, $parent_id = 0) | |
{ | |
$this->left = $i; | |
foreach ($this->children as &$category) { | |
$i++; | |
$category->parent_id = $parent_id; | |
$category->rebuild($i, $category->id); | |
unset($category); | |
} | |
$this->right = ++$i; | |
return $this; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use gist\Node; | |
$root = new Node(['id' => 0, ]); | |
$root->children[] = new Node(['id' => 1, 'parent_id' => 0]); | |
$root->children[] = new Node(['id' => 2, 'parent_id' => 1]); | |
$root->children[] = new Node(['id' => 3, 'parent_id' => 0]); | |
$root->children[] = new Node(['id' => 4, 'parent_id' => 3]); | |
var_dump($root->parentify()->rebuild()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment