Edit a name record.

@param ServerRequestInterface $request
@param Tree                   $tree

@return ResponseInterface
491786
public function editName(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $fact_id = $request->get('fact_id', '');
        $xref    = $request->get('xref', '');

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

        Auth::checkIndividualAccess($individual, true);

        // Find the fact to edit
        foreach ($individual->facts() as $fact) {
            if ($fact->id() === $fact_id && $fact->canEdit()) {
                return $this->viewResponse('edit/new-individual', [
                    'tree'       => $tree,
                    'title'      => I18N::translate('Edit the name'),
                    'nextaction' => 'update',
                    'individual' => $individual,
                    'family'     => null,
                    'name_fact'  => $fact,
                    'famtag'     => '',
                    'gender'     => $individual->sex(),
                ]);
            }
        }

        throw new NotFoundHttpException();
    }
815552
public function replaceAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $search  = $request->get('search', '');
        $replace = $request->get('replace', '');
        $context = $request->get('context', '');

        switch ($context) {
            case 'all':
                $records = $this->search_service->searchIndividuals([$tree], [$search]);
                $count   = $this->replaceRecords($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s individual has been updated.', '%s individuals have been updated.', $count, I18N::number($count)));

                $records = $this->search_service->searchFamilies([$tree], [$search]);
                $count   = $this->replaceRecords($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s family has been updated.', '%s families have been updated.', $count, I18N::number($count)));

                $records = $this->search_service->searchRepositories([$tree], [$search]);
                $count   = $this->replaceRecords($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s repository has been updated.', '%s repositories have been updated.', $count, I18N::number($count)));

                $records = $this->search_service->searchSources([$tree], [$search]);
                $count   = $this->replaceRecords($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s source has been updated.', '%s sources have been updated.', $count, I18N::number($count)));

                $records = $this->search_service->searchNotes([$tree], [$search]);
                $count   = $this->replaceRecords($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s note has been updated.', '%s notes have been updated.', $count, I18N::number($count)));
                break;

            case 'name':
                $adv_name_tags = preg_split("/[\s,;: ]+/", $tree->getPreference('ADVANCED_NAME_FACTS'));
                $name_tags     = array_unique(array_merge([
                    'NAME',
                    'NPFX',
                    'GIVN',
                    'SPFX',
                    'SURN',
                    'NSFX',
                    '_MARNM',
                    '_AKA',
                ], $adv_name_tags));

                $records = $this->search_service->searchIndividuals([$tree], [$search]);
                $count   = $this->replaceIndividualNames($records, $search, $replace, $name_tags);
                FlashMessages::addMessage(I18N::plural('%s individual has been updated.', '%s individuals have been updated.', $count, I18N::number($count)));
                break;

            case 'place':
                $records = $this->search_service->searchIndividuals([$tree], [$search]);
                $count   = $this->replacePlaces($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s individual has been updated.', '%s individuals have been updated.', $count, I18N::number($count)));

                $records = $this->search_service->searchFamilies([$tree], [$search]);
                $count   = $this->replacePlaces($records, $search, $replace);
                FlashMessages::addMessage(I18N::plural('%s family has been updated.', '%s families have been updated.', $count, I18N::number($count)));
                break;
        }

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

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

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

        if ($individual !== null && $individual->canShow()) {
            $html = $this->loadSpouses($individual, 1);
        } else {
            $html = '';
        }

        return response($html);
    }
473386
public function addChildAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

        $family = Family::getInstance($xref, $tree);

        Auth::checkFamilyAccess($family, true);

        $PEDI      = $request->get('PEDI', '');
        $keep_chan = (bool) $request->get('keep_chan');

        $this->glevels = $request->get('glevels', []);
        $this->tag     = $request->get('tag', []);
        $this->text    = $request->get('text', []);
        $this->islink  = $request->get('islink', []);

        $this->splitSource();
        $gedrec = '0 @@ INDI';
        $gedrec .= $this->addNewName($request, $tree);
        $gedrec .= $this->addNewSex($request);
        if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
            foreach ($matches[1] as $match) {
                $gedrec .= $this->addNewFact($request, $tree, $match);
            }
        }
        $gedrec .= "\n" . GedcomCodePedi::createNewFamcPedi($PEDI, $xref);
        if ((bool) $request->get('SOUR_INDI')) {
            $gedrec = $this->handleUpdates($gedrec);
        } else {
            $gedrec = $this->updateRest($gedrec);
        }

        // Create the new child
        $new_child = $tree->createIndividual($gedrec);

        // Insert new child at the right place
        $done = false;
        foreach ($family->facts(['CHIL']) as $fact) {
            $old_child = $fact->target();
            if ($old_child instanceof Individual && Date::compare($new_child->getEstimatedBirthDate(), $old_child->getEstimatedBirthDate()) < 0) {
                // Insert before this child
                $family->updateFact($fact->id(), '1 CHIL @' . $new_child->xref() . "@\n" . $fact->gedcom(), !$keep_chan);
                $done = true;
                break;
            }
        }
        if (!$done) {
            // Append child at end
            $family->createFact('1 CHIL @' . $new_child->xref() . '@', !$keep_chan);
        }

        if ($request->get('goto') === 'new') {
            return redirect($new_child->url());
        }

        return redirect($family->url());
    }
449851
public function mergeRecordsAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref1 = $request->get('xref1', '');
        $xref2 = $request->get('xref2', '');
        $keep1 = $request->get('keep1', []);
        $keep2 = $request->get('keep2', []);

        // Merge record2 into record1
        $record1 = GedcomRecord::getInstance($xref1, $tree);
        $record2 = GedcomRecord::getInstance($xref2, $tree);

        // Facts found both records
        $facts = [];
        // Facts found in only one record
        $facts1 = [];
        $facts2 = [];

        foreach ($record1->facts() as $fact) {
            if (!$fact->isPendingDeletion() && $fact->getTag() !== 'CHAN') {
                $facts1[$fact->id()] = $fact;
            }
        }

        foreach ($record2->facts() as $fact) {
            if (!$fact->isPendingDeletion() && $fact->getTag() !== 'CHAN') {
                $facts2[$fact->id()] = $fact;
            }
        }

        // If we are not auto-accepting, then we can show a link to the pending deletion
        if (Auth::user()->getPreference('auto_accept')) {
            $record2_name = $record2->fullName();
        } else {
            $record2_name = '<a class="alert-link" href="' . e($record2->url()) . '">' . $record2->fullName() . '</a>';
        }

        // Update records that link to the one we will be removing.
        $linking_records = $record2->linkingRecords();

        foreach ($linking_records as $record) {
            if (!$record->isPendingDeletion()) {
                /* I18N: The placeholders are the names of individuals, sources, etc. */
                FlashMessages::addMessage(I18N::translate(
                    'The link from “%1$s” to “%2$s” has been updated.',
                    '<a class="alert-link" href="' . e($record->url()) . '">' . $record->fullName() . '</a>',
                    $record2_name
                ), 'info');
                $gedcom = str_replace('@' . $xref2 . '@', '@' . $xref1 . '@', $record->gedcom());
                $gedcom = preg_replace(
                    '/(\n1.*@.+@.*(?:(?:\n[2-9].*)*))((?:\n1.*(?:\n[2-9].*)*)*\1)/',
                    '$2',
                    $gedcom
                );
                $record->updateRecord($gedcom, true);
            }
        }

        // Update any linked user-accounts
        DB::table('user_gedcom_setting')
            ->where('gedcom_id', '=', $tree->id())
            ->whereIn('setting_name', ['gedcomid', 'rootid'])
            ->where('setting_value', '=', $xref2)
            ->update(['setting_value' => $xref1]);

        // Merge hit counters
        $hits = DB::table('hit_counter')
            ->where('gedcom_id', '=', $tree->id())
            ->whereIn('page_parameter', [$xref1, $xref2])
            ->groupBy('page_name')
            ->pluck(DB::raw('SUM(page_count)'), 'page_name');

        foreach ($hits as $page_name => $page_count) {
            DB::table('hit_counter')
                ->where('gedcom_id', '=', $tree->id())
                ->where('page_name', '=', $page_name)
                ->update(['page_count' => $page_count]);
        }

        DB::table('hit_counter')
            ->where('gedcom_id', '=', $tree->id())
            ->where('page_parameter', '=', $xref2)
            ->delete();

        $gedcom = '0 @' . $record1->xref() . '@ ' . $record1::RECORD_TYPE;
        foreach ($facts as $fact_id => $fact) {
            $gedcom .= "\n" . $fact->gedcom();
        }
        foreach ($facts1 as $fact_id => $fact) {
            if (in_array($fact_id, $keep1, true)) {
                $gedcom .= "\n" . $fact->gedcom();
            }
        }
        foreach ($facts2 as $fact_id => $fact) {
            if (in_array($fact_id, $keep2, true)) {
                $gedcom .= "\n" . $fact->gedcom();
            }
        }

        DB::table('favorite')
            ->where('gedcom_id', '=', $tree->id())
            ->where('xref', '=', $xref2)
            ->update(['xref' => $xref1]);

        $record1->updateRecord($gedcom, true);
        $record2->deleteRecord();

        /* I18N: Records are individuals, sources, etc. */
        FlashMessages::addMessage(I18N::translate(
            'The records “%1$s” and “%2$s” have been merged.',
            '<a class="alert-link" href="' . e($record1->url()) . '">' . $record1->fullName() . '</a>',
            $record2_name
        ), 'success');

        return redirect(route('merge-records', ['ged' => $tree->name()]));
    }
495499
public function list(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
    {
        $soundex_dm  = (bool) $request->get('soundex_dm');
        $soundex_std = (bool) $request->get('soundex_std');
        $surname     = $request->get('surname', '');

        // Highlight direct-line ancestors of this individual.
        $self = Individual::getInstance($tree->getUserPreference($user, 'gedcomid'), $tree);

        if ($surname !== '') {
            $individuals = $this->loadIndividuals($tree, $surname, $soundex_dm, $soundex_std);
        } else {
            $individuals = [];
        }

        if ($self !== null) {
            $ancestors = $this->allAncestors($self);
        } else {
            $ancestors = [];
        }

        // @TODO - convert this to use views
        $html = view('branches-list', [
            'branches' => $this->getPatriarchsHtml($tree, $individuals, $ancestors, $surname, $soundex_dm, $soundex_std),
        ]);

        return response($html);
    }
214228
public function changeFamilyMembers(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref   = $request->get('xref', '');
        $family = Family::getInstance($xref, $tree);
        Auth::checkFamilyAccess($family, true);

        $title = I18N::translate('Change family members') . ' – ' . $family->fullName();

        return $this->viewResponse('edit/change-family-members', [
            'tree'     => $tree,
            'title'    => $title,
            'family'   => $family,
            'father'   => $family->husband(),
            'mother'   => $family->wife(),
            'children' => $family->children(),
        ]);
    }
478158
public function place(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $query = $request->get('query', '');
        $data  = [];

        foreach ($this->search_service->searchPlaces($tree, $query) as $place) {
            $data[] = ['value' => $place->gedcomName()];
        }

        if (empty($data) && $tree->getPreference('GEONAMES_ACCOUNT')) {
            // No place found? Use an external gazetteer
            $url =
                'http://api.geonames.org/searchJSON' .
                '?name_startsWith=' . urlencode($query) .
                '&lang=' . WT_LOCALE .
                '&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC' .
                '&style=full' .
                '&username=' . $tree->getPreference('GEONAMES_ACCOUNT');

            // try to use curl when file_get_contents not allowed
            if (ini_get('allow_url_fopen')) {
                $json = file_get_contents($url);
            } elseif (function_exists('curl_init')) {
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $json = curl_exec($ch);
                curl_close($ch);
            } else {
                return response([]);
            }

            $places = json_decode($json, true);
            if (isset($places['geonames']) && is_array($places['geonames'])) {
                foreach ($places['geonames'] as $k => $place) {
                    $data[] = ['value' => $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName']];
                }
            }
        }

        return response($data);
    }
325344
public function createSourceAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $title               = $request->get('source-title', '');
        $abbreviation        = $request->get('source-abbreviation', '');
        $author              = $request->get('source-author', '');
        $publication         = $request->get('source-publication', '');
        $repository          = $request->get('source-repository', '');
        $call_number         = $request->get('source-call-number', '');
        $text                = $request->get('source-text', '');
        $privacy_restriction = $request->get('privacy-restriction', '');
        $edit_restriction    = $request->get('edit-restriction', '');

        // Fix whitespace
        $title        = trim(preg_replace('/\s+/', ' ', $title));
        $abbreviation = trim(preg_replace('/\s+/', ' ', $abbreviation));
        $author       = trim(preg_replace('/\s+/', ' ', $author));
        $publication  = trim(preg_replace('/\s+/', ' ', $publication));
        $repository   = trim(preg_replace('/\s+/', ' ', $repository));
        $call_number  = trim(preg_replace('/\s+/', ' ', $call_number));

        // Convert line endings to GEDDCOM continuations
        $text = str_replace([
            "\r\n",
            "\r",
            "\n",
        ], "\n1 CONT ", $text);

        $gedcom = "0 @@ SOUR\n\n1 TITL " . $title;

        if ($abbreviation !== '') {
            $gedcom .= "\n1 ABBR " . $abbreviation;
        }

        if ($author !== '') {
            $gedcom .= "\n1 AUTH " . $author;
        }

        if ($publication !== '') {
            $gedcom .= "\n1 PUBL " . $publication;
        }

        if ($text !== '') {
            $gedcom .= "\n1 TEXT " . $text;
        }

        if ($repository !== '') {
            $gedcom .= "\n1 REPO @" . $repository . '@';

            if ($call_number !== '') {
                $gedcom .= "\n2 CALN " . $call_number;
            }
        }

        if (in_array($privacy_restriction, [
            'none',
            'privacy',
            'confidential',
        ])) {
            $gedcom .= "\n1 RESN " . $privacy_restriction;
        }

        if (in_array($edit_restriction, ['locked'])) {
            $gedcom .= "\n1 RESN " . $edit_restriction;
        }

        $record = $tree->createRecord($gedcom);

        // id and text are for select2 / autocomplete
        // html is for interactive modals
        return response([
            'id'   => $record->xref(),
            'text' => view('selects/source', [
                'source' => $record,
            ]),
            'html' => view('modals/record-created', [
                'title' => I18N::translate('The source has been created'),
                'name'  => $record->fullName(),
                'url'   => $record->url(),
            ]),
        ]);
    }
706245
public function addSpouseAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

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

        Auth::checkIndividualAccess($individual, true);

        $sex = $request->get('SEX', 'U');

        $this->glevels = $request->get('glevels', []);
        $this->tag     = $request->get('tag', []);
        $this->text    = $request->get('text', []);
        $this->islink  = $request->get('islink', []);

        $this->splitSource();
        $indi_gedcom = '0 @@ INDI';
        $indi_gedcom .= $this->addNewName($request, $tree);
        $indi_gedcom .= $this->addNewSex($request);
        if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
            foreach ($matches[1] as $match) {
                $indi_gedcom .= $this->addNewFact($request, $tree, $match);
            }
        }
        if ((bool) $request->get('SOUR_INDI')) {
            $indi_gedcom = $this->handleUpdates($indi_gedcom);
        } else {
            $indi_gedcom = $this->updateRest($indi_gedcom);
        }

        $fam_gedcom = '';
        if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) {
            foreach ($matches[1] as $match) {
                $fam_gedcom .= $this->addNewFact($request, $tree, $match);
            }
        }
        if ((bool) $request->get('SOUR_FAM')) {
            $fam_gedcom = $this->handleUpdates($fam_gedcom);
        } else {
            $fam_gedcom = $this->updateRest($fam_gedcom);
        }

        // Create the new spouse
        $spouse = $tree->createIndividual($indi_gedcom);
        // Create a new family
        if ($sex === 'F') {
            $family = $tree->createFamily("0 @@ FAM\n1 WIFE @" . $spouse->xref() . "@\n1 HUSB @" . $individual->xref() . '@' . $fam_gedcom);
        } else {
            $family = $tree->createFamily("0 @@ FAM\n1 HUSB @" . $spouse->xref() . "@\n1 WIFE @" . $individual->xref() . '@' . $fam_gedcom);
        }
        // Link the spouses to the family
        $spouse->createFact('1 FAMS @' . $family->xref() . '@', true);
        $individual->createFact('1 FAMS @' . $family->xref() . '@', true);

        if ($request->get('goto') === 'new') {
            return redirect($spouse->url());
        }

        return redirect($individual->url());
    }
945688
public function editRawRecord(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref   = $request->get('xref', '');
        $record = GedcomRecord::getInstance($xref, $tree);

        Auth::checkRecordAccess($record, true);

        $title = I18N::translate('Edit the raw GEDCOM') . ' - ' . $record->fullName();

        return $this->viewResponse('edit/raw-gedcom-record', [
            'pattern' => self::GEDCOM_FACT_REGEX,
            'record'  => $record,
            'title'   => $title,
        ]);
    }
504167
public function update(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
    {
        $contact_method = (string) $request->get('contact_method');
        $email          = (string) $request->get('email');
        $language       = (string) $request->get('language');
        $real_name      = (string) $request->get('real_name');
        $password       = (string) $request->get('password');
        $rootid         = (string) $request->get('root_id');
        $theme          = (string) $request->get('theme');
        $time_zone      = (string) $request->get('timezone');
        $user_name      = (string) $request->get('user_name');
        $visible_online = (string) $request->get('visible_online');

        // Change the password
        if ($password !== '') {
            $user->setPassword($password);
        }

        // Change the username
        if ($user_name !== $user->userName()) {
            if ($this->user_service->findByUserName($user_name) === null) {
                $user->setUserName($user_name);
            } else {
                FlashMessages::addMessage(I18N::translate('Duplicate username. A user with that username already exists. Please choose another username.'));
            }
        }

        // Change the email
        if ($email !== $user->email()) {
            if ($this->user_service->findByEmail($email) === null) {
                $user->setEmail($email);
            } else {
                FlashMessages::addMessage(I18N::translate('Duplicate email address. A user with that email already exists.'));
            }
        }

        $user
            ->setRealName($real_name)
            ->setPreference('contactmethod', $contact_method)
            ->setPreference('language', $language)
            ->setPreference('theme', $theme)
            ->setPreference('TIMEZONE', $time_zone)
            ->setPreference('visibleonline', $visible_online);

        $tree->setUserPreference($user, 'rootid', $rootid);

        // Switch to the new theme now
        Session::put('theme', $theme);

        // Switch to the new language now
        Session::put('language', $language);

        return redirect(route('my-account', ['ged' => $tree->name()]));
    }
646548
public function treePageEdit(Tree $tree): ResponseInterface
    {
        $main_blocks = $this->treeBlocks($tree->id(), 'main');
        $side_blocks = $this->treeBlocks($tree->id(), 'side');

        $all_blocks = $this->availableTreeBlocks();
        $title      = I18N::translate('Change the “Home page” blocks');
        $url_cancel = route('tree-page', ['ged' => $tree->name()]);
        $url_save   = route('tree-page-update', ['ged' => $tree->name()]);

        return $this->viewResponse('edit-blocks-page', [
            'all_blocks'  => $all_blocks,
            'can_reset'   => true,
            'main_blocks' => $main_blocks,
            'side_blocks' => $side_blocks,
            'title'       => $title,
            'url_cancel'  => $url_cancel,
            'url_save'    => $url_save,
        ]);
    }
803418
public function preferencesUpdate(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        // Coming soon
        if ((bool) $request->get('all_trees')) {
            FlashMessages::addMessage(I18N::translate('The preferences for all family trees have been updated.'), 'success');
        }
        if ((bool) $request->get('new_trees')) {
            FlashMessages::addMessage(I18N::translate('The preferences for new family trees have been updated.'), 'success');
        }

        $tree->setPreference('ADVANCED_NAME_FACTS', implode(',', $request->get('ADVANCED_NAME_FACTS', [])));
        $tree->setPreference('ADVANCED_PLAC_FACTS', implode(',', $request->get('ADVANCED_PLAC_FACTS', [])));
        $tree->setPreference('ALLOW_THEME_DROPDOWN', (string) (bool) $request->get('ALLOW_THEME_DROPDOWN'));
        // For backwards compatibility with webtrees 1.x we store the two calendar formats in one variable
        // e.g. "gregorian_and_jewish"
        $tree->setPreference('CALENDAR_FORMAT', implode('_and_', array_unique([
            $request->get('CALENDAR_FORMAT0', 'none'),
            $request->get('CALENDAR_FORMAT1', 'none'),
        ])));
        $tree->setPreference('CHART_BOX_TAGS', implode(',', $request->get('CHART_BOX_TAGS', [])));
        $tree->setPreference('CONTACT_USER_ID', $request->get('CONTACT_USER_ID'));
        $tree->setPreference('EXPAND_NOTES', (string) (bool) $request->get('EXPAND_NOTES'));
        $tree->setPreference('EXPAND_SOURCES', (string) (bool) $request->get('EXPAND_SOURCES'));
        $tree->setPreference('FAM_FACTS_ADD', implode(',', $request->get('FAM_FACTS_ADD', [])));
        $tree->setPreference('FAM_FACTS_QUICK', implode(',', $request->get('FAM_FACTS_QUICK', [])));
        $tree->setPreference('FAM_FACTS_UNIQUE', implode(',', $request->get('FAM_FACTS_UNIQUE', [])));
        $tree->setPreference('FULL_SOURCES', (string) (bool) $request->get('FULL_SOURCES'));
        $tree->setPreference('FORMAT_TEXT', $request->get('FORMAT_TEXT'));
        $tree->setPreference('GENERATE_UIDS', (string) (bool) $request->get('GENERATE_UIDS'));
        $tree->setPreference('GEONAMES_ACCOUNT', $request->get('GEONAMES_ACCOUNT'));
        $tree->setPreference('HIDE_GEDCOM_ERRORS', (string) (bool) $request->get('HIDE_GEDCOM_ERRORS'));
        $tree->setPreference('INDI_FACTS_ADD', implode(',', $request->get('INDI_FACTS_ADD', [])));
        $tree->setPreference('INDI_FACTS_QUICK', implode(',', $request->get('INDI_FACTS_QUICK', [])));
        $tree->setPreference('INDI_FACTS_UNIQUE', implode(',', $request->get('INDI_FACTS_UNIQUE', [])));
        $tree->setPreference('LANGUAGE', $request->get('LANGUAGE'));
        $tree->setPreference('MEDIA_UPLOAD', $request->get('MEDIA_UPLOAD'));
        $tree->setPreference('META_DESCRIPTION', $request->get('META_DESCRIPTION'));
        $tree->setPreference('META_TITLE', $request->get('META_TITLE'));
        $tree->setPreference('NO_UPDATE_CHAN', (string) (bool) $request->get('NO_UPDATE_CHAN'));
        $tree->setPreference('PEDIGREE_ROOT_ID', $request->get('PEDIGREE_ROOT_ID'));
        $tree->setPreference('PREFER_LEVEL2_SOURCES', $request->get('PREFER_LEVEL2_SOURCES'));
        $tree->setPreference('QUICK_REQUIRED_FACTS', implode(',', $request->get('QUICK_REQUIRED_FACTS', [])));
        $tree->setPreference('QUICK_REQUIRED_FAMFACTS', implode(',', $request->get('QUICK_REQUIRED_FAMFACTS', [])));
        $tree->setPreference('REPO_FACTS_ADD', implode(',', $request->get('REPO_FACTS_ADD', [])));
        $tree->setPreference('REPO_FACTS_QUICK', implode(',', $request->get('REPO_FACTS_QUICK', [])));
        $tree->setPreference('REPO_FACTS_UNIQUE', implode(',', $request->get('REPO_FACTS_UNIQUE', [])));
        $tree->setPreference('SHOW_COUNTER', (string) (bool) $request->get('SHOW_COUNTER'));
        $tree->setPreference('SHOW_EST_LIST_DATES', (string) (bool) $request->get('SHOW_EST_LIST_DATES'));
        $tree->setPreference('SHOW_FACT_ICONS', (string) (bool) $request->get('SHOW_FACT_ICONS'));
        $tree->setPreference('SHOW_GEDCOM_RECORD', (string) (bool) $request->get('SHOW_GEDCOM_RECORD'));
        $tree->setPreference('SHOW_HIGHLIGHT_IMAGES', (string) (bool) $request->get('SHOW_HIGHLIGHT_IMAGES'));
        $tree->setPreference('SHOW_LAST_CHANGE', (string) (bool) $request->get('SHOW_LAST_CHANGE'));
        $tree->setPreference('SHOW_MEDIA_DOWNLOAD', $request->get('SHOW_MEDIA_DOWNLOAD'));
        $tree->setPreference('SHOW_NO_WATERMARK', $request->get('SHOW_NO_WATERMARK'));
        $tree->setPreference('SHOW_PARENTS_AGE', (string) (bool) $request->get('SHOW_PARENTS_AGE'));
        $tree->setPreference('SHOW_PEDIGREE_PLACES', $request->get('SHOW_PEDIGREE_PLACES'));
        $tree->setPreference('SHOW_PEDIGREE_PLACES_SUFFIX', (string) (bool) $request->get('SHOW_PEDIGREE_PLACES_SUFFIX'));
        $tree->setPreference('SHOW_RELATIVES_EVENTS', implode(',', $request->get('SHOW_RELATIVES_EVENTS', [])));
        $tree->setPreference('SOUR_FACTS_ADD', implode(',', $request->get('SOUR_FACTS_ADD', [])));
        $tree->setPreference('SOUR_FACTS_QUICK', implode(',', $request->get('SOUR_FACTS_QUICK', [])));
        $tree->setPreference('SOUR_FACTS_UNIQUE', implode(',', $request->get('SOUR_FACTS_UNIQUE', [])));
        $tree->setPreference('SUBLIST_TRIGGER_I', (string) (int) $request->get('SUBLIST_TRIGGER_I', 200));
        $tree->setPreference('SURNAME_LIST_STYLE', $request->get('SURNAME_LIST_STYLE'));
        $tree->setPreference('SURNAME_TRADITION', $request->get('SURNAME_TRADITION'));
        $tree->setPreference('THEME_DIR', $request->get('THEME_DIR'));
        $tree->setPreference('USE_SILHOUETTE', (string) (bool) $request->get('USE_SILHOUETTE'));
        $tree->setPreference('WEBMASTER_USER_ID', $request->get('WEBMASTER_USER_ID'));
        $tree->setPreference('WEBTREES_EMAIL', $request->get('WEBTREES_EMAIL'));
        $tree->setPreference('title', $request->get('title'));

        // Only accept valid folders for MEDIA_DIRECTORY
        $MEDIA_DIRECTORY = preg_replace('/[\/\\\\]+/', '/', $request->get('MEDIA_DIRECTORY') . '/');
        if (substr($MEDIA_DIRECTORY, 0, 1) === '/') {
            $MEDIA_DIRECTORY = substr($MEDIA_DIRECTORY, 1);
        }

        if ($MEDIA_DIRECTORY) {
            if (is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
                $tree->setPreference('MEDIA_DIRECTORY', $MEDIA_DIRECTORY);
            } elseif (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) {
                $tree->setPreference('MEDIA_DIRECTORY', $MEDIA_DIRECTORY);
                FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'info');
            } else {
                FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger');
            }
        }

        $gedcom = $request->get('gedcom');
        if ($gedcom && $gedcom !== $tree->name()) {
            try {
                DB::table('gedcom')
                    ->where('gedcom_id', '=', $tree->id())
                    ->update(['gedcom_name' => $gedcom]);

                DB::table('site_setting')
                    ->where('setting_name', '=', 'DEFAULT_GEDCOM')
                    ->where('setting_value', '=', $tree->name())
                    ->update(['setting_value' => $gedcom]);
            } catch (Exception $ex) {
                // Probably a duplicate name.
            }
        }

        FlashMessages::addMessage(I18N::translate('The preferences for the family tree “%s” have been updated.', e($tree->title())), 'success');

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

        return redirect($url);
    }
20108
public function general(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $query = $request->get('query', '');

        // What type of records to search?
        $search_individuals  = (bool) $request->get('search_individuals');
        $search_families     = (bool) $request->get('search_families');
        $search_repositories = (bool) $request->get('search_repositories');
        $search_sources      = (bool) $request->get('search_sources');
        $search_notes        = (bool) $request->get('search_notes');

        // Default to individuals only
        if (!$search_individuals && !$search_families && !$search_repositories && !$search_sources && !$search_notes) {
            $search_individuals = true;
        }

        // What to search for?
        $search_terms = $this->extractSearchTerms($query);

        // What trees to seach?
        if (Site::getPreference('ALLOW_CHANGE_GEDCOM') === '1') {
            $all_trees = Tree::getAll();
        } else {
            $all_trees = [$tree];
        }

        $search_tree_names = (array) $request->get('search_trees', []);

        $search_trees = array_filter($all_trees, static function (Tree $tree) use ($search_tree_names): bool {
            return in_array($tree->name(), $search_tree_names, true);
        });

        if (empty($search_trees)) {
            $search_trees = [$tree];
        }

        // Do the search
        if ($search_individuals && !empty($search_terms)) {
            $individuals = $this->search_service->searchIndividuals($search_trees, $search_terms);
        } else {
            $individuals = new Collection();
        }

        if ($search_families && !empty($search_terms)) {
            $tmp1 = $this->search_service->searchFamilies($search_trees, $search_terms);
            $tmp2 = $this->search_service->searchFamilyNames($search_trees, $search_terms);

            $families = $tmp1->merge($tmp2)->unique();
        } else {
            $families = new Collection();
        }

        if ($search_repositories && !empty($search_terms)) {
            $repositories = $this->search_service->searchRepositories($search_trees, $search_terms);
        } else {
            $repositories = new Collection();
        }

        if ($search_sources && !empty($search_terms)) {
            $sources = $this->search_service->searchSources($search_trees, $search_terms);
        } else {
            $sources = new Collection();
        }

        if ($search_notes && !empty($search_terms)) {
            $notes = $this->search_service->searchNotes($search_trees, $search_terms);
        } else {
            $notes = new Collection();
        }

        // If only 1 item is returned, automatically forward to that item
        if ($individuals->count() === 1 && $families->isEmpty() && $sources->isEmpty() && $notes->isEmpty()) {
            return redirect($individuals->first()->url());
        }

        if ($individuals->isEmpty() && $families->count() === 1 && $sources->isEmpty() && $notes->isEmpty()) {
            return redirect($families->first()->url());
        }

        if ($individuals->isEmpty() && $families->isEmpty() && $sources->count() === 1 && $notes->isEmpty()) {
            return redirect($sources->first()->url());
        }

        if ($individuals->isEmpty() && $families->isEmpty() && $sources->isEmpty() && $notes->count() === 1) {
            return redirect($notes->first()->url());
        }

        $title = I18N::translate('General search');

        return $this->viewResponse('search-general-page', [
            'all_trees'           => $all_trees,
            'families'            => $families,
            'individuals'         => $individuals,
            'notes'               => $notes,
            'query'               => $query,
            'repositories'        => $repositories,
            'search_families'     => $search_families,
            'search_individuals'  => $search_individuals,
            'search_notes'        => $search_notes,
            'search_repositories' => $search_repositories,
            'search_sources'      => $search_sources,
            'search_trees'        => $search_trees,
            'sources'             => $sources,
            'title'               => $title,
        ]);
    }
583611
public function edit(Tree $tree, UserInterface $user): ResponseInterface
    {
        $my_individual_record = Individual::getInstance($tree->getUserPreference(Auth::user(), 'gedcomid'), $tree);
        $contact_methods      = FunctionsEdit::optionsContactMethods();
        $default_individual   = Individual::getInstance($tree->getUserPreference(Auth::user(), 'rootid'), $tree);
        $installed_languages  = FunctionsEdit::optionsInstalledLanguages();
        $show_delete_option   = !$user->getPreference('canadmin');
        $themes               = $this->themeOptions();
        $timezone_ids         = DateTimeZone::listIdentifiers();
        $timezones            = array_combine($timezone_ids, $timezone_ids);
        $title                = I18N::translate('My account');

        return $this->viewResponse('edit-account-page', [
            'contact_methods'      => $contact_methods,
            'default_individual'   => $default_individual,
            'installed_languages'  => $installed_languages,
            'my_individual_record' => $my_individual_record,
            'show_delete_option'   => $show_delete_option,
            'themes'               => $themes,
            'timezones'            => $timezones,
            'title'                => $title,
            'user'                 => $user,
        ]);
    }
153080
public function userPageUpdate(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
    {
        $defaults = (bool) $request->get('defaults');

        if ($defaults) {
            $main_blocks = $this->userBlocks(-1, 'main')->all();
            $side_blocks = $this->userBlocks(-1, 'side')->all();
        } else {
            $main_blocks = (array) $request->get('main');
            $side_blocks = (array) $request->get('side');
        }

        $this->updateUserBlocks($user->id(), $main_blocks, $side_blocks);

        return redirect(route('user-page', ['ged' => $tree->name()]));
    }