src/Charcoal/Object/HierarchicalCollection.php
public function sortTree()
    {
        $level   = 0;
        $count   = 0;
        $pageNum = $this->page();
        $perPage = $this->numPerPage();

        $sortedObjects = [];
        $rootObjects   = [];
        $childObjects  = [];

        foreach ($this->objects as $object) {
            // Repair bad hierarchy.
            if ($object->hasMaster() && $object->master()->id() === $object->id()) {
                $object->setMaster(0);
                $object->update([ 'master' ]);
            }

            if ($object->hasMaster()) {
                $childObjects[$object->master()->id()][] = $object;
            } else {
                $rootObjects[] = $object;
            }
        }

        if (empty($rootObjects) && !empty($childObjects)) {
            foreach ($childObjects as $parentId => $children) {
                $parentObj = $children[0]->master();
                $parentObj->auxiliary = true;

                $rootObjects[] = $parentObj;
            }
        }

        $this->objects = &$rootObjects;

        if ($perPage < 1) {
            foreach ($this->objects as $object) {
                $object->level = $level;
                $sortedObjects[$object->id()] = $object;

                $count++;

                if (isset($childObjects[$object->id()])) {
                    $this->sortDescendantObjects(
                        $object,
                        $childObjects,
                        $count,
                        ($level + 1),
                        $sortedObjects
                    );
                }
            }
        } else {
            $start = (( $pageNum - 1 ) * $perPage);
            $end   = ($start + $perPage);

            foreach ($this->objects as $object) {
                if ($count >= $end) {
                    break;
                }

                if ($count >= $start) {
                    $object->level = $level;
                    $sortedObjects[$object->id()] = $object;
                }

                $count++;

                if (isset($childObjects[$object->id()])) {
                    $this->sortDescendantObjects(
                        $object,
                        $childObjects,
                        $count,
                        ($level + 1),
                        $sortedObjects
                    );
                }
            }

            // If we are on the last page, display orphaned descendants.
            if ($childObjects && $count < $end) {
                foreach ($childObjects as $orphans) {
                    foreach ($orphans as $descendants) {
                        if ($count >= $end) {
                            break;
                        }

                        if ($count >= $start) {
                            $descendants->level = 0;
                            $sortedObjects[$descendants->id()] = $descendants;
                        }

                        $count++;
                    }
                }
            }
        }

        $this->objects = $sortedObjects;

        return $this;
    }
public function sortTree()
    {
        $level   = 0;
        $count   = 0;
        $pageNum = $this->page();
        $perPage = $this->numPerPage();

        $sortedObjects = [];
        $rootObjects   = [];
        $childObjects  = [];

        foreach ($this->objects as $object) {
            // Repair bad hierarchy.
            if ($object->hasMaster() && $object->master()->id() === $object->id()) {
                $object->setMaster(0);
                $object->update([ 'master' ]);
            }

            if ($object->hasMaster()) {
                $childObjects[$object->master()->id()][] = $object;
            } else {
                $rootObjects[] = $object;
            }
        }

        if (empty($rootObjects) && !empty($childObjects)) {
            foreach ($childObjects as $parentId => $children) {
                $parentObj = $children[0]->master();
                $parentObj->auxiliary = true;

                $rootObjects[] = $parentObj;
            }
        }

        $this->objects = &$rootObjects;

        if ($perPage < 1) {
            foreach ($this->objects as $object) {
                $object->level = $level;
                $sortedObjects[$object->id()] = $object;

                $count++;

                if (isset($childObjects[$object->id()])) {
                    $this->sortDescendantObjects(
                        $object,
                        $childObjects,
                        $count,
                        ($level + 1),
                        $sortedObjects
                    );
                }
            }
        } else {
            $start = (( $pageNum - 1 ) * $perPage);
            $end   = ($start + $perPage);

            foreach ($this->objects as $object) {
                if ($count >= $end) {
                    break;
                }

                if ($count >= $start) {
                    $object->level = $level;
                    $sortedObjects[$object->id()] = $object;
                }

                $count++;

                if (isset($childObjects[$object->id()])) {
                    $this->sortDescendantObjects(
                        $object,
                        $childObjects,
                        $count,
                        ($level + 1),
                        $sortedObjects
                    );
                }
            }

            // If we are on the last page, display orphaned descendants.
            if ($childObjects && $count < $end) {
                foreach ($childObjects as $orphans) {
                    foreach ($orphans as $descendants) {
                        if ($count >= $end) {
                            break;
                        }

                        if ($count >= $start) {
                            $descendants->level = 0;
                            $sortedObjects[$descendants->id()] = $descendants;
                        }

                        $count++;
                    }
                }
            }
        }

        $this->objects = $sortedObjects;

        return $this;
    }
Sort the hierarchical collection of objects.

@return self