Add permission information to the tree structure

@deprecated

@param array $tree
@return array
435724
protected function addPermissions($tree)
    {
        $user = $this->getSession()->getUser();

        $section = MenuService::getSection(
            $this->getRequestParameter('extension'),
            $this->getRequestParameter('perspective'),
            $this->getRequestParameter('section')
        );

        $actions = $section->getActions();

        //then compute ACL for each node of the tree
        $treeKeys = array_keys($tree);
        if (isset($treeKeys[0]) && is_int($treeKeys[0])) {
            foreach ($tree as $index => $treeNode) {
                $tree[$index] = $this->computePermissions($actions, $user, $treeNode);
            }
        } else {
            $tree = $this->computePermissions($actions, $user, $tree);
        }

        return $tree;
    }
270486
public function getTreePerimeterConfiguration($tree)
    {
        foreach ($tree as &$leaf) {
            $leaf = $this->formatConfiguration($leaf);
        }

        return $tree;
    }
1084190
public function toString(Array $tree) {
    $text = '';
    while (!empty($tree)) {
      $node = array_shift($tree);

      $text .= str_repeat('  ',$node->getDepth()).(string) $node."\n";
    }
    
    return $text;
  }
827045
public function getAdminAction(Tree $tree): ResponseInterface
    {
        $this->layout = 'layouts/administration';

        $stories = DB::table('block')
            ->where('module_name', '=', $this->name())
            ->where('gedcom_id', '=', $tree->id())
            ->orderBy('xref')
            ->get();

        foreach ($stories as $story) {
            $block_id = (int) $story->block_id;

            $story->individual = Individual::getInstance($story->xref, $tree);
            $story->title      = $this->getBlockSetting($block_id, 'title');
            $story->languages  = $this->getBlockSetting($block_id, 'languages');
        }

        return $this->viewResponse('modules/stories/config', [
            'stories'    => $stories,
            'title'      => $this->title() . ' — ' . $tree->title(),
            'tree'       => $tree,
            'tree_names' => Tree::getNameList(),
        ]);
    }
97736
protected function yamlArrayToModel($array)
    {
        $filePermissions = $array;
        $permissions = [];
        $index = 0;

        foreach ($filePermissions as $code=>$permission) {
            $permission['permission'] = $code;

            $permissions[] = $permission;
        }

        $this->permissions = $permissions;
    }
1334123
protected function sort_area_tree($tree) {
        foreach ($tree as $key => &$value) {
            if ($key == 'subdirs') {
                core_collator::ksort($value, core_collator::SORT_NATURAL);
                foreach ($value as $subdirname => &$subtree) {
                    $subtree = $this->sort_area_tree($subtree);
                }
            } else if ($key == 'files') {
                core_collator::ksort($value, core_collator::SORT_NATURAL);
            }
        }
        return $tree;
    }
1217627
protected function loadTreeFromEvent(): array
    {
        $event = new AddPermissionsEvent($this->permissionKeys);
        $this->dispatcher->dispatch('logauth.add_permissions', $event);

        return $event->getTree();
    }
530316
public function permissionTree()
  {
    $permtree = array();

    foreach($this->permissionCats() as $key => $val)
    {
      $permtree[$val]["permcatid"]      = $val;
      $permtree[$val]["permcathex"]     = "0x" . dechex($val);
      $permtree[$val]["permcatname"]    = TeamSpeak3_Helper_String::factory(TeamSpeak3_Helper_Convert::permissionCategory($val));
      $permtree[$val]["permcatparent"]  = $permtree[$val]["permcathex"]{3} == 0 ? 0 : hexdec($permtree[$val]["permcathex"]{2} . 0);
      $permtree[$val]["permcatchilren"] = 0;
      $permtree[$val]["permcatcount"]   = 0;

      if(isset($permtree[$permtree[$val]["permcatparent"]]))
      {
        $permtree[$permtree[$val]["permcatparent"]]["permcatchilren"]++;
      }

      if($permtree[$val]["permcatname"]->contains("/"))
      {
        $permtree[$val]["permcatname"] = $permtree[$val]["permcatname"]->section("/", 1)->trim();
      }

      foreach($this->permissionList() as $permission)
      {
        if($permission["permid"]["permcatid"] == $val)
        {
          $permtree[$val]["permcatcount"]++;
        }
      }
    }

    return $permtree;
  }
255532
private function unusedFiles(Tree $tree): array
    {
        $used_files = DB::table('media_file')
            ->where('m_file', '=', $tree->id())
            ->where('multimedia_file_refn', 'NOT LIKE', 'http://%')
            ->where('multimedia_file_refn', 'NOT LIKE', 'https://%')
            ->pluck('multimedia_file_refn')
            ->all();

        $disk_files = [];
        $media_dir  = WT_DATA_DIR . $tree->getPreference('MEDIA_DIRECTORY', 'media/');
        $iter       = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($media_dir, FilesystemIterator::FOLLOW_SYMLINKS));

        foreach ($iter as $file) {
            if ($file->isFile()) {
                $filename = substr($file->getPathname(), strlen($media_dir));
                // Older versions of webtrees used a couple of special folders.
                if (strpos($filename, 'thumbs/') !== 0 && strpos($filename, 'watermarks/') !== 0) {
                    $disk_files[] = $filename;
                }
            }
        }

        $unused_files = array_diff($disk_files, $used_files);

        sort($unused_files);

        return array_combine($unused_files, $unused_files);
    }
1161283
public function check(Tree $tree): ResponseInterface
    {
        // We need to work with raw GEDCOM data, as we are looking for errors
        // which may prevent the GedcomRecord objects from working.

        $q1 = DB::table('individuals')
            ->where('i_file', '=', $tree->id())
            ->select(['i_id AS xref', 'i_gedcom AS gedcom', DB::raw("'INDI' AS type")]);
        $q2 = DB::table('families')
            ->where('f_file', '=', $tree->id())
            ->select(['f_id AS xref', 'f_gedcom AS gedcom', DB::raw("'FAM' AS type")]);
        $q3 = DB::table('media')
            ->where('m_file', '=', $tree->id())
            ->select(['m_id AS xref', 'm_gedcom AS gedcom', DB::raw("'OBJE' AS type")]);
        $q4 = DB::table('sources')
            ->where('s_file', '=', $tree->id())
            ->select(['s_id AS xref', 's_gedcom AS gedcom', DB::raw("'SOUR' AS type")]);
        $q5 = DB::table('other')
            ->where('o_file', '=', $tree->id())
            ->whereNotIn('o_type', ['HEAD', 'TRLR'])
            ->select(['o_id AS xref', 'o_gedcom AS gedcom', 'o_type']);
        $q6 = DB::table('change')
            ->where('gedcom_id', '=', $tree->id())
            ->where('status', '=', 'pending')
            ->orderBy('change_id')
            ->select(['xref', 'new_gedcom AS gedcom', DB::raw("'' AS type")]);

        $rows = $q1
            ->unionAll($q2)
            ->unionAll($q3)
            ->unionAll($q4)
            ->unionAll($q5)
            ->unionAll($q6)
            ->get()
            ->map(static function (stdClass $row): stdClass {
                // Extract type for pending record
                if ($row->type === '' && preg_match('/^0 @[^@]*@ ([_A-Z0-9]+)/', $row->gedcom, $match)) {
                    $row->type = $match[1];
                }

                return $row;
            });

        $records = [];

        foreach ($rows as $row) {
            if ($row->gedcom !== '') {
                // existing or updated record
                $records[$row->xref] = $row;
            } else {
                // deleted record
                unset($records[$row->xref]);
            }
        }

        // LOOK FOR BROKEN LINKS
        $XREF_LINKS = [
            'NOTE'          => 'NOTE',
            'SOUR'          => 'SOUR',
            'REPO'          => 'REPO',
            'OBJE'          => 'OBJE',
            'SUBM'          => 'SUBM',
            'FAMC'          => 'FAM',
            'FAMS'          => 'FAM',
            //'ADOP'=>'FAM', // Need to handle this case specially. We may have both ADOP and FAMC links to the same FAM, but only store one.
            'HUSB'          => 'INDI',
            'WIFE'          => 'INDI',
            'CHIL'          => 'INDI',
            'ASSO'          => 'INDI',
            '_ASSO'         => 'INDI',
            // A webtrees extension
            'ALIA'          => 'INDI',
            'AUTH'          => 'INDI',
            // A webtrees extension
            'ANCI'          => 'SUBM',
            'DESI'          => 'SUBM',
            '_WT_OBJE_SORT' => 'OBJE',
            '_LOC'          => '_LOC',
        ];

        $RECORD_LINKS = [
            'INDI' => [
                'NOTE',
                'OBJE',
                'SOUR',
                'SUBM',
                'ASSO',
                '_ASSO',
                'FAMC',
                'FAMS',
                'ALIA',
                '_WT_OBJE_SORT',
                '_LOC',
            ],
            'FAM'  => [
                'NOTE',
                'OBJE',
                'SOUR',
                'SUBM',
                'ASSO',
                '_ASSO',
                'HUSB',
                'WIFE',
                'CHIL',
                '_LOC',
            ],
            'SOUR' => [
                'NOTE',
                'OBJE',
                'REPO',
                'AUTH',
            ],
            'REPO' => ['NOTE'],
            'OBJE' => ['NOTE'],
            // The spec also allows SOUR, but we treat this as a warning
            'NOTE' => [],
            // The spec also allows SOUR, but we treat this as a warning
            'SUBM' => [
                'NOTE',
                'OBJE',
            ],
            'SUBN' => ['SUBM'],
            '_LOC' => [
                'SOUR',
                'OBJE',
                '_LOC',
                'NOTE',
            ],
        ];

        $errors   = [];
        $warnings = [];

        // Generate lists of all links
        $all_links   = [];
        $upper_links = [];
        foreach ($records as $record) {
            $all_links[$record->xref]               = [];
            $upper_links[strtoupper($record->xref)] = $record->xref;
            preg_match_all('/\n\d (' . Gedcom::REGEX_TAG . ') @([^#@\n][^\n@]*)@/', $record->gedcom, $matches, PREG_SET_ORDER);
            foreach ($matches as $match) {
                $all_links[$record->xref][$match[2]] = $match[1];
            }
        }

        foreach ($all_links as $xref1 => $links) {
            $type1 = $records[$xref1]->type;
            foreach ($links as $xref2 => $type2) {
                $type3 = isset($records[$xref2]) ? $records[$xref2]->type : '';
                if (!array_key_exists($xref2, $all_links)) {
                    if (array_key_exists(strtoupper($xref2), $upper_links)) {
                        $warnings[] =
                            $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) . ' ' .
                            /* I18N: placeholders are GEDCOM XREFs, such as R123 */
                            I18N::translate('%1$s does not exist. Did you mean %2$s?', $this->checkLink($tree, $xref2), $this->checkLink($tree, $upper_links[strtoupper($xref2)]));
                    } else {
                        /* I18N: placeholders are GEDCOM XREFs, such as R123 */
                        $errors[] = $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) . ' ' . I18N::translate('%1$s does not exist.', $this->checkLink($tree, $xref2));
                    }
                } elseif ($type2 === 'SOUR' && $type1 === 'NOTE') {
                    // Notes are intended to add explanations and comments to other records. They should not have their own sources.
                } elseif ($type2 === 'SOUR' && $type1 === 'OBJE') {
                    // Media objects are intended to illustrate other records, facts, and source/citations. They should not have their own sources.
                } elseif ($type2 === 'OBJE' && $type1 === 'REPO') {
                    $warnings[] =
                        $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) .
                        ' ' .
                        I18N::translate('This type of link is not allowed here.');
                } elseif (!array_key_exists($type1, $RECORD_LINKS) || !in_array($type2, $RECORD_LINKS[$type1], true) || !array_key_exists($type2, $XREF_LINKS)) {
                    $errors[] =
                        $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) .
                        ' ' .
                        I18N::translate('This type of link is not allowed here.');
                } elseif ($XREF_LINKS[$type2] !== $type3) {
                    // Target XREF does exist - but is invalid
                    $errors[] =
                        $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) . ' ' .
                        /* I18N: %1$s is an internal ID number such as R123. %2$s and %3$s are record types, such as INDI or SOUR */
                        I18N::translate('%1$s is a %2$s but a %3$s is expected.', $this->checkLink($tree, $xref2), $this->formatType($type3), $this->formatType($type2));
                } elseif (
                    $type2 === 'FAMC' && (!array_key_exists($xref1, $all_links[$xref2]) || $all_links[$xref2][$xref1] !== 'CHIL') ||
                    $type2 === 'FAMS' && (!array_key_exists($xref1, $all_links[$xref2]) || $all_links[$xref2][$xref1] !== 'HUSB' && $all_links[$xref2][$xref1] !== 'WIFE') ||
                    $type2 === 'CHIL' && (!array_key_exists($xref1, $all_links[$xref2]) || $all_links[$xref2][$xref1] !== 'FAMC') ||
                    $type2 === 'HUSB' && (!array_key_exists($xref1, $all_links[$xref2]) || $all_links[$xref2][$xref1] !== 'FAMS') ||
                    $type2 === 'WIFE' && (!array_key_exists($xref1, $all_links[$xref2]) || $all_links[$xref2][$xref1] !== 'FAMS')
                ) {
                    /* I18N: %1$s and %2$s are internal ID numbers such as R123 */
                    $errors[] = $this->checkLinkMessage($tree, $type1, $xref1, $type2, $xref2) . ' ' . I18N::translate('%1$s does not have a link back to %2$s.', $this->checkLink($tree, $xref2), $this->checkLink($tree, $xref1));
                }
            }
        }

        $title = I18N::translate('Check for errors') . ' — ' . e($tree->title());

        return $this->viewResponse('admin/trees-check', [
            'errors'   => $errors,
            'title'    => $title,
            'tree'     => $tree,
            'warnings' => $warnings,
        ]);
    }
1032202
protected function mergeTrees(array $trees): array
    {
        if (count($trees) == 0) {
            return [];
        }

        $tree1 = array_shift($trees);
        while (count($trees)) {
            $tree2 = array_shift($trees);
            foreach ($tree2 as $key => $value) {
                if (in_array($key, $this->permissionKeys)) {
                    $tree1 = $tree2;
                    break;
                }
                if (isset($tree1[$key]) && is_array($value)) {
                    $tree1[$key] = $this->mergeTrees([$tree1[$key], $tree2[$key]]);
                    continue;
                }
                $tree1[$key] = $value;
            }
        }

        return $tree1;
    }
723966
private function getList(Tree $tree, SearchService $search_service): array
    {
        $places = $search_service->searchPlaces($tree, '')
            ->sort(static function (Place $x, Place $y): int {
                return $x->gedcomName() <=> $y->gedcomName();
            })
            ->all();

        $numfound = count($places);

        if ($numfound === 0) {
            $columns = [];
        } else {
            $divisor = $numfound > 20 ? 3 : 2;
            $columns = array_chunk($places, (int) ceil($numfound / $divisor));
        }

        return [
            'columns' => $columns,
        ];
    }
683060
protected function findPartialTree($tree, $categoryId)
    {
        /** @var AbstractCategoryDocument $node */
        foreach ($tree as $node) {
            if ($node->getId() == $categoryId) {
                return [$node];
            }
            if ($node->getChildren()) {
                $result = $this->findPartialTree($node->getChildren(), $categoryId);
                if (!empty($result)) {
                    return $result;
                }
            }
        }

        return [];
    }
1317178
public static function treeToList($tree, $child = '_child', $order = null, &$list = []): array
    {
        if (is_array($tree)) {
            foreach ($tree as $key => $value) {
                $refer = $value;
                if (isset($refer[$child])) {
                    unset($refer[$child]);
                    self::treeToList($value[$child], $child, $order, $list);
                }
                $list[] = $refer;
            }
            if ($order !== null) {
                $list = self::listSortBy($list, $order, 'asc');
            }
        }
        
        return $list;
    }
43996
private function parseAdminBarTree( $tree, $root = null ) {
		$return = [];
		foreach ( $tree as $child => $parent ) {
			if ( $parent === $root ) {
				//  Remove item from tree (we don't need to traverse this again)
				unset( $tree[ $child ] );
				// Append the child into result array and parse its children
				$return[] = [
					'name' => $child,
					'children' => $this->parseAdminBarTree( $tree, $child ),
				];
			}
		}
		return empty( $return ) ? null : $return;
	}
1216744
private static function transform(array $tree): string
    {
        $n = \count($tree);

        $inObject = $usePlusFun = false;
        $expType = null;

        $return = [];
        for ($i = 0; $i < $n; ++$i) {
            $token = $tree[$i];

            if (\is_array($token)) {
                $return[] = self::transform($token);
                continue;
            }

            /* @var Token $token */
            switch ($token->getType()) {
                case 'T_STRING':
                    if ($inObject === false) {
                        $code = '$' . $token->getContent();

                        $next = $tree[$i + 1] ?? null;
                        if ($next instanceof Token) {
                            if ($next->is('.')) {
                                $code = '$this->wrap(' . $code . ')';
                                $inObject = true;
                            }

                            if ($next->is([T_INC, T_DEC])) {
                                $code .= $next->getContent();
                                ++$i;
                            }
                        }

                        $return[] = $code;
                    } else {
                        $return[] = $token->getContent();
                    }
                    continue 2;

                case '.':
                    if ($inObject === false) {
                        throw new \InvalidArgumentException('Expression syntax error');
                    }

                    $return[] = '->';
                    continue 2;

                case 'T_LNUMBER':
                case 'T_DNUMBER':
                case 'T_INC':
                case 'T_DEC':
                    $return[] = $token->getContent();

                    if (!$usePlusFun && $expType === null) {
                        $expType = 'int';
                    }
                    break;

                case 'T_CONSTANT_ENCAPSED_STRING':
                    $return[] = $token->getContent();

                    if (!$usePlusFun && $expType === null) {
                        $expType = 'string';
                    }
                    break;

                case '+':
                    switch ($expType) {
                        case 'int':
                            $return[] = ' + ';
                            break;

                        case 'string':
                            $return[] = ' . ';
                            break;

                        default:
                            if (!$usePlusFun) {
                                if ($return[0] === '(' || $return[0] === '[') {
                                    \array_splice($return, 1, 0, static::class . '::plus(');
                                } else {
                                    \array_unshift($return, static::class . '::plus(');
                                }

                                $usePlusFun = true;
                            }
                            $return[] = ', ';
                            break;
                    }
                    break;


                case '*':
                case '/':
                    if (!$usePlusFun && $expType === null) {
                        $expType = 'int';
                    }

                    $return[] = $token->getContent();
                    break;

                case '-':
                    if ($usePlusFun) {
                        $return[] = ')';
                        $return[] = $token->getContent();
                        $usePlusFun = false;
                    } else {
                        $expType = 'int';
                        $return[] = $token->getContent();
                    }
                    break;

                case ')':
                case ']':
                    if ($usePlusFun) {
                        $return[] = ')';
                        $return[] = $token->getContent();
                        $usePlusFun = false;
                    } else {
                        $return[] = $token->getContent();
                    }
                    break;

                default:
                    $return[] = $token->getContent();
            }

            if ($inObject) {
                $inObject = false;
            }
        }

        if ($usePlusFun) {
            $return[] = ')';
        }

        return \implode('', $return);
    }
1261857
public function treePrivacyEdit(Tree $tree): ResponseInterface
    {
        $title                = e($tree->name()) . ' — ' . I18N::translate('Privacy');
        $all_tags             = $this->tagsForPrivacy($tree);
        $privacy_constants    = $this->privacyConstants();
        $privacy_restrictions = $this->privacyRestrictions($tree);

        return $this->viewResponse('admin/trees-privacy', [
            'all_tags'             => $all_tags,
            'count_trees'          => count(Tree::getAll()),
            'privacy_constants'    => $privacy_constants,
            'privacy_restrictions' => $privacy_restrictions,
            'title'                => $title,
        ]);
    }