@param Tree   $tree
@param Place  $place
@param string $parent []

@return array|null
@throws Exception
969832
private function getHierarchy($tree, $place, $parent): ?array
    {
        $child_places = $place->getChildPlaces();
        $numfound     = count($child_places);

        if ($numfound > 0) {
            $divisor = $numfound > 20 ? 3 : 2;

            return
                [
                    'tree'      => $tree,
                    'col_class' => 'w-' . ($divisor === 2 ? '25' : '50'),
                    'columns'   => array_chunk($child_places, (int) ceil($numfound / $divisor)),
                    'place'     => $place,
                    'parent'    => $parent,
                ];
        }

        return null;
    }
1242558
private function makeNode(&$row, &$tree)
    {
        $hasChildren = $this->propertyAccessor->getValue($row, "[{$this->options['children_column']}]");
        $weight      = $this->propertyAccessor->getValue($row, "[{$this->options['hierarchy_column']}]");

        $row['hasChildren'] = (bool)($hasChildren > 0);
        $row['weight']      = $weight;
        $tree[$row['id']]   = $row;
    }
825655
public function placesAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $search  = $request->get('search', '');
        $replace = $request->get('replace', '');

        $changes = $this->changePlacesUpdate($tree, $search, $replace);

        $feedback = I18N::translate('The following places have been changed:') . '<ul>';
        foreach ($changes as $old_place => $new_place) {
            $feedback .= '<li>' . e($old_place) . ' &rarr; ' . e($new_place) . '</li>';
        }
        $feedback .= '</ul>';

        FlashMessages::addMessage($feedback, 'success');

        $url = route('admin-trees-places', [
            'ged'     => $tree->name(),
            'replace' => $replace,
            'search'  => $search,
        ]);

        return redirect($url);
    }
299590
private function buildLevel(int $parent_id, array $placename, array &$places): void
    {
        $level = array_search('', $placename, true);

        $rows = DB::table('placelocation')
            ->where('pl_parent_id', '=', $parent_id)
            ->orderBy('pl_place')
            ->get();

        foreach ($rows as $row) {
            $index             = (int) $row->pl_id;
            $placename[$level] = $row->pl_place;
            $places[]          = array_merge(['pl_level' => $row->pl_level], $placename, ['pl_long' => $row->pl_long, 'pl_lati' => $row->pl_lati, 'pl_zoom' => $row->pl_zoom, 'pl_icon' => $row->pl_icon]);
            $this->buildLevel($index, $placename, $places);
        }
    }
340968
protected function mapData(Tree $tree, $reference): array
    {
        $placeObj  = new Place($reference, $tree);
        $places    = $placeObj->getChildPlaces();
        $features  = [];
        $flag_path = Webtrees::MODULES_DIR . 'openstreetmap/';
        $showlink  = true;
        if (empty($places)) {
            $places[] = $placeObj;
            $showlink = false;
        }
        foreach ($places as $id => $place) {
            $location = new Location($place->gedcomName());
            //Stats
            $placeStats = [];
            foreach (['INDI', 'FAM'] as $type) {
                $tmp               = $this->statistics->statsPlaces($type, '', $place->id());
                $placeStats[$type] = empty($tmp) ? 0 : $tmp[0]->tot;
            }
            //Flag
            if ($location->icon() !== '' && is_file($flag_path . $location->icon())) {
                $flag = $flag_path . $location->icon();
            } else {
                $flag = '';
            }
            $features[] = [
                'type'       => 'Feature',
                'id'         => $id,
                'valid'      => $location->longitude() !== 0.0 || $location->latitude() !== 0.0,
                'geometry'   => [
                    'type'        => 'Point',
                    'coordinates' => [$location->longitude(), $location->latitude()],
                ],
                'properties' => [
                    'icon'    => [
                        'name'  => 'globe',
                        'color' => '#1e90ff',
                    ],
                    'tooltip' => $place->gedcomName(),
                    'summary' => view('place-sidebar', [
                        'showlink' => $showlink,
                        'flag'     => $flag,
                        'place'    => $place,
                        'stats'    => $placeStats,
                    ]),
                    'zoom'    => $location->zoom() ?: 2,
                ],
            ];
        }

        return [
            'type'     => 'FeatureCollection',
            'features' => $features,
        ];
    }
1344514
private function sitemapRecords(Tree $tree, string $type, int $limit, int $offset): Collection
    {
        switch ($type) {
            case 'i':
                $records = $this->sitemapIndividuals($tree, $limit, $offset);
                break;

            case 'm':
                $records = $this->sitemapMedia($tree, $limit, $offset);
                break;

            case 'n':
                $records = $this->sitemapNotes($tree, $limit, $offset);
                break;

            case 'r':
                $records = $this->sitemapRepositories($tree, $limit, $offset);
                break;

            case 's':
                $records = $this->sitemapSources($tree, $limit, $offset);
                break;

            default:
                throw new NotFoundHttpException('Invalid record type: ' . $type);
        }

        // Skip private records.
        $records = $records->filter(GedcomRecord::accessFilter());

        return $records;
    }
437744
private function changePlacesPreview(Tree $tree, string $search, string $replace): array
    {
        // Fetch the latest GEDCOM for each individual and family
        $union = DB::table('families')
            ->where('f_file', '=', $tree->id())
            ->whereContains('f_gedcom', $search)
            ->select(['f_gedcom AS gedcom']);

        return DB::table('individuals')
            ->where('i_file', '=', $tree->id())
            ->whereContains('i_gedcom', $search)
            ->select(['i_gedcom AS gedcom'])
            ->unionAll($union)
            ->pluck('gedcom')
            ->mapWithKeys(static function (string $gedcom) use ($search, $replace): array {
                preg_match_all('/\n2 PLAC ((?:.*, )*)' . preg_quote($search, '/') . '(\n|$)/i', $gedcom, $matches);

                $changes = [];
                foreach ($matches[1] as $prefix) {
                    $changes[$prefix . $search] = $prefix . $replace;
                }

                return $changes;
            })
            ->sort()
            ->all();
    }
1134786
public static function load(Tree $tree, array $xrefs): void
    {
        $rows = DB::table('individuals')
            ->where('i_file', '=', $tree->id())
            ->whereIn('i_id', array_unique($xrefs))
            ->select(['i_id AS xref', 'i_gedcom AS gedcom'])
            ->get();

        foreach ($rows as $row) {
            self::getInstance($row->xref, $tree, $row->gedcom);
        }
    }
223990
public static function htmlPlacesCloud($places, $totals, Tree $tree) {
		$items = array();
		
		foreach ($places as $place => $count) {
			/** var \MyArtJaub\Webtrees\Place */
			$dplace = Place::getIntance($place, $tree);
			$items[] = array(
				'text' => $dplace->htmlFormattedName('%1 (%2)'),
				'count' => $count,
				'url' => $dplace->getDerivedPlace()->getURL()
			);
		}
		
		return self::htmlListCloud($items, $totals);
	}
19118
public function parent(): Place
    {
        return new self($this->parts->slice(1)->implode(Gedcom::PLACE_SEPARATOR), $this->tree);
    }
1107867
private function buildTreeFromArray(
        array $treeStructure,
        \Tx_Oelib_Visibility_Node $parentNode
    ) {
        foreach ($treeStructure as $nodeKey => $nodeContents) {
            /** @var \Tx_Oelib_Visibility_Node $childNode */
            $childNode = GeneralUtility::makeInstance(\Tx_Oelib_Visibility_Node::class);
            $parentNode->addChild($childNode);

            if (is_array($nodeContents)) {
                $this->buildTreeFromArray($nodeContents, $childNode);
            } elseif ($nodeContents === true) {
                $childNode->markAsVisible();
            }

            $this->nodes[$nodeKey] = $childNode;
        }
    }
1321101
public function reorderChildrenAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref   = $request->get('xref', '');
        $order  = (array) $request->get('order', []);
        $family = Family::getInstance($xref, $tree);

        Auth::checkFamilyAccess($family, true);

        $dummy_facts = ['0 @' . $family->xref() . '@ FAM'];
        $sort_facts  = [];
        $keep_facts  = [];

        // Split facts into FAMS and other
        foreach ($family->facts() as $fact) {
            if ($fact->getTag() === 'CHIL') {
                $sort_facts[$fact->id()] = $fact->gedcom();
            } else {
                $keep_facts[] = $fact->gedcom();
            }
        }

        // Sort the facts
        uksort($sort_facts, static function ($x, $y) use ($order) {
            return array_search($x, $order, true) - array_search($y, $order, true);
        });

        // Merge the facts
        $gedcom = implode("\n", array_merge($dummy_facts, $sort_facts, $keep_facts));

        $family->updateRecord($gedcom, false);

        return redirect($family->url());
    }
20277
public function postAddIndividualAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref   = $request->get('xref', '');
        $option = $request->get('option', '');

        $individual = Individual::getInstance($xref, $tree);

        if ($individual === null) {
            throw new IndividualNotFoundException();
        }

        switch ($option) {
            case 'self':
                $this->addRecordToCart($individual);
                break;

            case 'parents':
                foreach ($individual->childFamilies() as $family) {
                    $this->addFamilyAndChildrenToCart($family);
                }
                break;

            case 'spouses':
                foreach ($individual->spouseFamilies() as $family) {
                    $this->addFamilyAndChildrenToCart($family);
                }
                break;

            case 'ancestors':
                $this->addAncestorsToCart($individual);
                break;

            case 'ancestor_families':
                $this->addAncestorFamiliesToCart($individual);
                break;

            case 'descendants':
                foreach ($individual->spouseFamilies() as $family) {
                    $this->addFamilyAndDescendantsToCart($family);
                }
                break;
        }

        return redirect($individual->url());
    }
1096075
private function ensureParentAndKey($parent, $key)
    {
        if (!$this->parent)
        {
            $this->parent = $parent;
        }
        if (!$this->key)
        {
            $this->key = $key;
        }
        if ($this->parent != $parent)
        {
            throw new \Exception('Internal Error. Relation retrieved from two different Objects.');
        }
        if ($this->key != $key)
        {
            throw new \Exception('Internal Error. Relation retrieved from two different keys.');
        }
    }
1045118
public function setParentInstance(SiteTree $parent)
    {
        $this->parentInstance = $parent;
        
        $this->setStyleIDFrom($parent);
        
        return $this;
    }
925674
public function getParent()
	{
		if ( ! $this->hasParent()) {
			return null;
		}
		$parents = $this->getAncestors(1);
		if ( ! isset($parents[0])) {
			$dump = static::dump($this);
			throw new Exception\InvalidStructure("Parent node was not found for {$dump} but must exist");
		}
		$parent = $parents[0];
		
		return $parent;
	}
378120
public function populateTree($depth = null, $with = null)
    {
        /** @var ActiveRecord[]|static[] $nodes */
        $query = $this->getDescendants($depth);
        if ($with) {
            $query->with($with);
        }
        $nodes = $query->all();

        $key = $this->owner->getAttribute($this->leftAttribute);
        $relates = [];
        $parents = [$key];
        $prev = $this->owner->getAttribute($this->depthAttribute);
        foreach($nodes as $node)
        {
            $level = $node->getAttribute($this->depthAttribute);
            if ($level <= $prev) {
                $parents = array_slice($parents, 0, $level - $prev - 1);
            }

            $key = end($parents);
            if (!isset($relates[$key])) {
                $relates[$key] = [];
            }
            $relates[$key][] = $node;

            $parents[] = $node->getAttribute($this->leftAttribute);
            $prev = $level;
        }

        $ownerDepth = $this->owner->getAttribute($this->depthAttribute);
        $nodes[] = $this->owner;
        foreach ($nodes as $node) {
            $key = $node->getAttribute($this->leftAttribute);
            if (isset($relates[$key])) {
                $node->populateRelation('children', $relates[$key]);
            } elseif ($depth === null || $ownerDepth + $depth > $node->getAttribute($this->depthAttribute)) {
                $node->populateRelation('children', []);
            }
        }

        return $this->owner;
    }