18c2e8227SGreg Roach<?php 28c2e8227SGreg Roach/** 38c2e8227SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 88c2e8227SGreg Roach * (at your option) any later version. 98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 128c2e8227SGreg Roach * GNU General Public License for more details. 138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 158c2e8227SGreg Roach */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 1876692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1976692c8bSGreg Roach 200e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 2250d6f48cSGreg Roachuse Fisharebest\Webtrees\Services\HtmlService; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 2477654037SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 2577654037SGreg Roachuse Illuminate\Database\Query\Builder; 2677654037SGreg Roachuse Illuminate\Support\Collection; 276ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 286ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 298de50a4eSGreg Roachuse stdClass; 308c2e8227SGreg Roach 318c2e8227SGreg Roach/** 328c2e8227SGreg Roach * Class FrequentlyAskedQuestionsModule 338c2e8227SGreg Roach */ 3437eb8894SGreg Roachclass FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleConfigInterface, ModuleMenuInterface 35c1010edaSGreg Roach{ 3649a243cbSGreg Roach use ModuleConfigTrait; 3749a243cbSGreg Roach use ModuleMenuTrait; 3849a243cbSGreg Roach 3950d6f48cSGreg Roach /** @var HtmlService */ 4050d6f48cSGreg Roach private $html_service; 4150d6f48cSGreg Roach 4250d6f48cSGreg Roach /** 4350d6f48cSGreg Roach * HtmlBlockModule bootstrap. 4450d6f48cSGreg Roach * 4550d6f48cSGreg Roach * @param HtmlService $html_service 4650d6f48cSGreg Roach */ 4750d6f48cSGreg Roach public function boot(HtmlService $html_service) 4850d6f48cSGreg Roach { 4950d6f48cSGreg Roach $this->html_service = $html_service; 5050d6f48cSGreg Roach } 5150d6f48cSGreg Roach 52961ec755SGreg Roach /** 530cfd6963SGreg Roach * How should this module be identified in the control panel, etc.? 54961ec755SGreg Roach * 55961ec755SGreg Roach * @return string 56961ec755SGreg Roach */ 5749a243cbSGreg Roach public function title(): string 58c1010edaSGreg Roach { 59bbb76c12SGreg Roach /* I18N: Name of a module. Abbreviation for “Frequently Asked Questions” */ 60bbb76c12SGreg Roach return I18N::translate('FAQ'); 618c2e8227SGreg Roach } 628c2e8227SGreg Roach 63961ec755SGreg Roach /** 64961ec755SGreg Roach * A sentence describing what this module does. 65961ec755SGreg Roach * 66961ec755SGreg Roach * @return string 67961ec755SGreg Roach */ 6849a243cbSGreg Roach public function description(): string 69c1010edaSGreg Roach { 70bbb76c12SGreg Roach /* I18N: Description of the “FAQ” module */ 71bbb76c12SGreg Roach return I18N::translate('A list of frequently asked questions and answers.'); 728c2e8227SGreg Roach } 738c2e8227SGreg Roach 7476692c8bSGreg Roach /** 7549a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 760ee13198SGreg Roach * 770ee13198SGreg Roach * @return int 780ee13198SGreg Roach */ 798f53f488SRico Sonntag public function defaultMenuOrder(): int 80c1010edaSGreg Roach { 81353b36abSGreg Roach return 8; 828c2e8227SGreg Roach } 838c2e8227SGreg Roach 840ee13198SGreg Roach /** 850ee13198SGreg Roach * A menu, to be added to the main application menu. 860ee13198SGreg Roach * 87aee13b6dSGreg Roach * @param Tree $tree 88aee13b6dSGreg Roach * 890ee13198SGreg Roach * @return Menu|null 900ee13198SGreg Roach */ 9146295629SGreg Roach public function getMenu(Tree $tree): ?Menu 92c1010edaSGreg Roach { 9377654037SGreg Roach if ($this->faqsExist($tree, WT_LOCALE)) { 9449a243cbSGreg Roach return new Menu($this->title(), route('module', [ 9526684e68SGreg Roach 'module' => $this->name(), 96c1010edaSGreg Roach 'action' => 'Show', 97aa6f03bbSGreg Roach 'ged' => $tree->name(), 98c1010edaSGreg Roach ]), 'menu-help'); 998c2e8227SGreg Roach } 100b2ce94c6SRico Sonntag 101b2ce94c6SRico Sonntag return null; 1028c2e8227SGreg Roach } 103aee13b6dSGreg Roach 104aee13b6dSGreg Roach /** 105b6db7c1fSGreg Roach * @param Tree $tree 106aee13b6dSGreg Roach * 1076ccdf4f0SGreg Roach * @return ResponseInterface 108aee13b6dSGreg Roach */ 1096ccdf4f0SGreg Roach public function getAdminAction(Tree $tree): ResponseInterface 110c1010edaSGreg Roach { 111aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 112aee13b6dSGreg Roach 11326348dcdSGreg Roach $faqs = $this->faqsForTree($tree); 114aee13b6dSGreg Roach 11577654037SGreg Roach $min_block_order = DB::table('block') 11626684e68SGreg Roach ->where('module_name', '=', $this->name()) 1170b5fd0a6SGreg Roach ->where(static function (Builder $query) use ($tree): void { 11877654037SGreg Roach $query 11977654037SGreg Roach ->whereNull('gedcom_id') 12077654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 12177654037SGreg Roach }) 12277654037SGreg Roach ->min('block_order'); 123aee13b6dSGreg Roach 12477654037SGreg Roach $max_block_order = DB::table('block') 12526684e68SGreg Roach ->where('module_name', '=', $this->name()) 1260b5fd0a6SGreg Roach ->where(static function (Builder $query) use ($tree): void { 12777654037SGreg Roach $query 12877654037SGreg Roach ->whereNull('gedcom_id') 12977654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 13077654037SGreg Roach }) 13177654037SGreg Roach ->max('block_order'); 132aee13b6dSGreg Roach 133cc13d6d8SGreg Roach $title = I18N::translate('Frequently asked questions') . ' — ' . $tree->title(); 134aee13b6dSGreg Roach 135aee13b6dSGreg Roach return $this->viewResponse('modules/faq/config', [ 136aee13b6dSGreg Roach 'faqs' => $faqs, 137aee13b6dSGreg Roach 'max_block_order' => $max_block_order, 138aee13b6dSGreg Roach 'min_block_order' => $min_block_order, 139aee13b6dSGreg Roach 'title' => $title, 140aee13b6dSGreg Roach 'tree' => $tree, 141aee13b6dSGreg Roach 'tree_names' => Tree::getNameList(), 142aee13b6dSGreg Roach ]); 143aee13b6dSGreg Roach } 144aee13b6dSGreg Roach 145aee13b6dSGreg Roach /** 1466ccdf4f0SGreg Roach * @param ServerRequestInterface $request 147b6db7c1fSGreg Roach * @param Tree $tree 148aee13b6dSGreg Roach * 1496ccdf4f0SGreg Roach * @return ResponseInterface 150aee13b6dSGreg Roach */ 1516ccdf4f0SGreg Roach public function postAdminDeleteAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 152c1010edaSGreg Roach { 153eb235819SGreg Roach $block_id = (int) $request->getQueryParams()['block_id']; 154aee13b6dSGreg Roach 15577654037SGreg Roach DB::table('block_setting')->where('block_id', '=', $block_id)->delete(); 156aee13b6dSGreg Roach 15777654037SGreg Roach DB::table('block')->where('block_id', '=', $block_id)->delete(); 158aee13b6dSGreg Roach 159c1010edaSGreg Roach $url = route('module', [ 16026684e68SGreg Roach 'module' => $this->name(), 161c1010edaSGreg Roach 'action' => 'Admin', 162aa6f03bbSGreg Roach 'ged' => $tree->name(), 163c1010edaSGreg Roach ]); 164aee13b6dSGreg Roach 1656ccdf4f0SGreg Roach return redirect($url); 166aee13b6dSGreg Roach } 167aee13b6dSGreg Roach 168aee13b6dSGreg Roach /** 1696ccdf4f0SGreg Roach * @param ServerRequestInterface $request 170b6db7c1fSGreg Roach * @param Tree $tree 171aee13b6dSGreg Roach * 1726ccdf4f0SGreg Roach * @return ResponseInterface 173aee13b6dSGreg Roach */ 1746ccdf4f0SGreg Roach public function postAdminMoveDownAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 175c1010edaSGreg Roach { 176eb235819SGreg Roach $block_id = (int) $request->getQueryParams()['block_id']; 177aee13b6dSGreg Roach 17877654037SGreg Roach $block_order = DB::table('block') 17977654037SGreg Roach ->where('block_id', '=', $block_id) 18077654037SGreg Roach ->value('block_order'); 181aee13b6dSGreg Roach 18277654037SGreg Roach $swap_block = DB::table('block') 18326684e68SGreg Roach ->where('module_name', '=', $this->name()) 184eb235819SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 18577654037SGreg Roach $query 18677654037SGreg Roach ->from('block') 18726684e68SGreg Roach ->where('module_name', '=', $this->name()) 18877654037SGreg Roach ->where('block_order', '>', $block_order) 189*a69f5655SGreg Roach ->min('block_order'); 19077654037SGreg Roach }) 19177654037SGreg Roach ->select(['block_order', 'block_id']) 19277654037SGreg Roach ->first(); 193aee13b6dSGreg Roach 194aee13b6dSGreg Roach if ($swap_block !== null) { 19577654037SGreg Roach DB::table('block') 19677654037SGreg Roach ->where('block_id', '=', $block_id) 19777654037SGreg Roach ->update([ 198aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 199aee13b6dSGreg Roach ]); 20077654037SGreg Roach 20177654037SGreg Roach DB::table('block') 20277654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 20377654037SGreg Roach ->update([ 204aee13b6dSGreg Roach 'block_order' => $block_order, 205aee13b6dSGreg Roach ]); 206aee13b6dSGreg Roach } 207aee13b6dSGreg Roach 208c1010edaSGreg Roach $url = route('module', [ 20926684e68SGreg Roach 'module' => $this->name(), 210c1010edaSGreg Roach 'action' => 'Admin', 211aa6f03bbSGreg Roach 'ged' => $tree->name(), 212c1010edaSGreg Roach ]); 213aee13b6dSGreg Roach 2146ccdf4f0SGreg Roach return redirect($url); 215aee13b6dSGreg Roach } 216aee13b6dSGreg Roach 217aee13b6dSGreg Roach /** 2186ccdf4f0SGreg Roach * @param ServerRequestInterface $request 219b6db7c1fSGreg Roach * @param Tree $tree 220aee13b6dSGreg Roach * 2216ccdf4f0SGreg Roach * @return ResponseInterface 222aee13b6dSGreg Roach */ 2236ccdf4f0SGreg Roach public function postAdminMoveUpAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 224c1010edaSGreg Roach { 225eb235819SGreg Roach $block_id = (int) $request->getQueryParams()['block_id']; 226aee13b6dSGreg Roach 22777654037SGreg Roach $block_order = DB::table('block') 22877654037SGreg Roach ->where('block_id', '=', $block_id) 22977654037SGreg Roach ->value('block_order'); 230aee13b6dSGreg Roach 23177654037SGreg Roach $swap_block = DB::table('block') 23226684e68SGreg Roach ->where('module_name', '=', $this->name()) 233*a69f5655SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 23477654037SGreg Roach $query 23577654037SGreg Roach ->from('block') 23626684e68SGreg Roach ->where('module_name', '=', $this->name()) 23777654037SGreg Roach ->where('block_order', '<', $block_order) 238*a69f5655SGreg Roach ->max('block_order'); 23977654037SGreg Roach }) 24077654037SGreg Roach ->select(['block_order', 'block_id']) 24177654037SGreg Roach ->first(); 242aee13b6dSGreg Roach 243aee13b6dSGreg Roach if ($swap_block !== null) { 24477654037SGreg Roach DB::table('block') 24577654037SGreg Roach ->where('block_id', '=', $block_id) 24677654037SGreg Roach ->update([ 247aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 248aee13b6dSGreg Roach ]); 24977654037SGreg Roach 25077654037SGreg Roach DB::table('block') 25177654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 25277654037SGreg Roach ->update([ 253aee13b6dSGreg Roach 'block_order' => $block_order, 254aee13b6dSGreg Roach ]); 255aee13b6dSGreg Roach } 256aee13b6dSGreg Roach 257c1010edaSGreg Roach $url = route('module', [ 25826684e68SGreg Roach 'module' => $this->name(), 259c1010edaSGreg Roach 'action' => 'Admin', 260aa6f03bbSGreg Roach 'ged' => $tree->name(), 261c1010edaSGreg Roach ]); 262aee13b6dSGreg Roach 2636ccdf4f0SGreg Roach return redirect($url); 264aee13b6dSGreg Roach } 265aee13b6dSGreg Roach 266aee13b6dSGreg Roach /** 2676ccdf4f0SGreg Roach * @param ServerRequestInterface $request 268b6db7c1fSGreg Roach * @param Tree $tree 269aee13b6dSGreg Roach * 2706ccdf4f0SGreg Roach * @return ResponseInterface 271aee13b6dSGreg Roach */ 2726ccdf4f0SGreg Roach public function getAdminEditAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 273c1010edaSGreg Roach { 274aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 275aee13b6dSGreg Roach 276eb235819SGreg Roach $block_id = (int) ($request->getQueryParams()['block_id'] ?? 0); 277aee13b6dSGreg Roach 278aee13b6dSGreg Roach if ($block_id === 0) { 279aee13b6dSGreg Roach // Creating a new faq 280aee13b6dSGreg Roach $header = ''; 281aee13b6dSGreg Roach $faqbody = ''; 28277654037SGreg Roach 28377654037SGreg Roach $block_order = 1 + (int) DB::table('block') 28426684e68SGreg Roach ->where('module_name', '=', $this->name()) 28577654037SGreg Roach ->max('block_order'); 28677654037SGreg Roach 287aee13b6dSGreg Roach $languages = []; 288aee13b6dSGreg Roach 289aee13b6dSGreg Roach $title = I18N::translate('Add an FAQ'); 290aee13b6dSGreg Roach } else { 291aee13b6dSGreg Roach // Editing an existing faq 292aee13b6dSGreg Roach $header = $this->getBlockSetting($block_id, 'header'); 293aee13b6dSGreg Roach $faqbody = $this->getBlockSetting($block_id, 'faqbody'); 29477654037SGreg Roach 29577654037SGreg Roach $block_order = DB::table('block') 29677654037SGreg Roach ->where('block_id', '=', $block_id) 29777654037SGreg Roach ->value('block_order'); 29877654037SGreg Roach 299aee13b6dSGreg Roach $languages = explode(',', $this->getBlockSetting($block_id, 'languages')); 300aee13b6dSGreg Roach 301aee13b6dSGreg Roach $title = I18N::translate('Edit the FAQ'); 302aee13b6dSGreg Roach } 303aee13b6dSGreg Roach 304b6c326d8SGreg Roach $tree_names = ['' => I18N::translate('All')] + Tree::getIdList(); 305b6c326d8SGreg Roach 306aee13b6dSGreg Roach return $this->viewResponse('modules/faq/edit', [ 307aee13b6dSGreg Roach 'block_id' => $block_id, 308aee13b6dSGreg Roach 'block_order' => $block_order, 309aee13b6dSGreg Roach 'header' => $header, 310aee13b6dSGreg Roach 'faqbody' => $faqbody, 311aee13b6dSGreg Roach 'languages' => $languages, 312aee13b6dSGreg Roach 'title' => $title, 313aee13b6dSGreg Roach 'tree' => $tree, 314b6c326d8SGreg Roach 'tree_names' => $tree_names, 315aee13b6dSGreg Roach ]); 316aee13b6dSGreg Roach } 317aee13b6dSGreg Roach 318aee13b6dSGreg Roach /** 3196ccdf4f0SGreg Roach * @param ServerRequestInterface $request 320b6db7c1fSGreg Roach * @param Tree $tree 321aee13b6dSGreg Roach * 3226ccdf4f0SGreg Roach * @return ResponseInterface 323aee13b6dSGreg Roach */ 3246ccdf4f0SGreg Roach public function postAdminEditAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 325c1010edaSGreg Roach { 326eb235819SGreg Roach $block_id = (int) ($request->getQueryParams()['block_id'] ?? 0); 327eb235819SGreg Roach 328eb235819SGreg Roach $params = $request->getParsedBody(); 329eb235819SGreg Roach 330eb235819SGreg Roach $faqbody = $params['faqbody']; 331eb235819SGreg Roach $header = $params['header']; 332eb235819SGreg Roach $languages = $params['languages'] ?? []; 333eb235819SGreg Roach $gedcom_id = (int) $params['gedcom_id'] ?: null; 334eb235819SGreg Roach $block_order = (int) $params['block_order']; 335aee13b6dSGreg Roach 33650d6f48cSGreg Roach $faqbody = $this->html_service->sanitize($faqbody); 33750d6f48cSGreg Roach $header = $this->html_service->sanitize($header); 33850d6f48cSGreg Roach 339aee13b6dSGreg Roach if ($block_id !== 0) { 34077654037SGreg Roach DB::table('block') 34177654037SGreg Roach ->where('block_id', '=', $block_id) 34277654037SGreg Roach ->update([ 34377654037SGreg Roach 'gedcom_id' => $gedcom_id, 34477654037SGreg Roach 'block_order' => $block_order, 345aee13b6dSGreg Roach ]); 346aee13b6dSGreg Roach } else { 34777654037SGreg Roach DB::table('block')->insert([ 34877654037SGreg Roach 'gedcom_id' => $gedcom_id, 34926684e68SGreg Roach 'module_name' => $this->name(), 35077654037SGreg Roach 'block_order' => $block_order, 351aee13b6dSGreg Roach ]); 352aee13b6dSGreg Roach 35377654037SGreg Roach $block_id = (int) DB::connection()->getPdo()->lastInsertId(); 354aee13b6dSGreg Roach } 355aee13b6dSGreg Roach 356aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'faqbody', $faqbody); 357aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'header', $header); 358aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'languages', implode(',', $languages)); 359aee13b6dSGreg Roach 360c1010edaSGreg Roach $url = route('module', [ 36126684e68SGreg Roach 'module' => $this->name(), 362c1010edaSGreg Roach 'action' => 'Admin', 363aa6f03bbSGreg Roach 'ged' => $tree->name(), 364c1010edaSGreg Roach ]); 365aee13b6dSGreg Roach 3666ccdf4f0SGreg Roach return redirect($url); 367aee13b6dSGreg Roach } 368aee13b6dSGreg Roach 369b998dbceSGreg Roach /** 370b6db7c1fSGreg Roach * @param Tree $tree 371b998dbceSGreg Roach * 3726ccdf4f0SGreg Roach * @return ResponseInterface 373b998dbceSGreg Roach */ 3746ccdf4f0SGreg Roach public function getShowAction(Tree $tree): ResponseInterface 375c1010edaSGreg Roach { 3768de50a4eSGreg Roach // Filter foreign languages. 37777654037SGreg Roach $faqs = $this->faqsForTree($tree) 3780b5fd0a6SGreg Roach ->filter(static function (stdClass $faq): bool { 37922d65e5aSGreg Roach return $faq->languages === '' || in_array(WT_LOCALE, explode(',', $faq->languages), true); 3808de50a4eSGreg Roach }); 381aee13b6dSGreg Roach 382aee13b6dSGreg Roach return $this->viewResponse('modules/faq/show', [ 3838de50a4eSGreg Roach 'faqs' => $faqs, 384aee13b6dSGreg Roach 'title' => I18N::translate('Frequently asked questions'), 3858de50a4eSGreg Roach 'tree' => $tree, 386aee13b6dSGreg Roach ]); 387aee13b6dSGreg Roach } 38877654037SGreg Roach 38977654037SGreg Roach /** 39077654037SGreg Roach * @param Tree $tree 39177654037SGreg Roach * 39277654037SGreg Roach * @return Collection 39377654037SGreg Roach */ 39477654037SGreg Roach private function faqsForTree(Tree $tree): Collection 39577654037SGreg Roach { 39677654037SGreg Roach return DB::table('block') 39777654037SGreg Roach ->join('block_setting AS bs1', 'bs1.block_id', '=', 'block.block_id') 39877654037SGreg Roach ->join('block_setting AS bs2', 'bs2.block_id', '=', 'block.block_id') 39977654037SGreg Roach ->join('block_setting AS bs3', 'bs3.block_id', '=', 'block.block_id') 40026684e68SGreg Roach ->where('module_name', '=', $this->name()) 40177654037SGreg Roach ->where('bs1.setting_name', '=', 'header') 40277654037SGreg Roach ->where('bs2.setting_name', '=', 'faqbody') 40377654037SGreg Roach ->where('bs3.setting_name', '=', 'languages') 4040b5fd0a6SGreg Roach ->where(static function (Builder $query) use ($tree): void { 40577654037SGreg Roach $query 40677654037SGreg Roach ->whereNull('gedcom_id') 40777654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 40877654037SGreg Roach }) 40977654037SGreg Roach ->orderBy('block_order') 41077654037SGreg Roach ->select(['block.block_id', 'block_order', 'gedcom_id', 'bs1.setting_value AS header', 'bs2.setting_value AS faqbody', 'bs3.setting_value AS languages']) 41177654037SGreg Roach ->get(); 41277654037SGreg Roach } 41377654037SGreg Roach 41477654037SGreg Roach /** 41577654037SGreg Roach * @param Tree $tree 41677654037SGreg Roach * @param string $language 41777654037SGreg Roach * 41877654037SGreg Roach * @return bool 41977654037SGreg Roach */ 42077654037SGreg Roach private function faqsExist(Tree $tree, string $language): bool 42177654037SGreg Roach { 42277654037SGreg Roach return DB::table('block') 42377654037SGreg Roach ->join('block_setting', 'block_setting.block_id', '=', 'block.block_id') 42426684e68SGreg Roach ->where('module_name', '=', $this->name()) 42577654037SGreg Roach ->where('setting_name', '=', 'languages') 4260b5fd0a6SGreg Roach ->where(static function (Builder $query) use ($tree): void { 42777654037SGreg Roach $query 42877654037SGreg Roach ->whereNull('gedcom_id') 42977654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 43077654037SGreg Roach }) 43177654037SGreg Roach ->select(['setting_value AS languages']) 43277654037SGreg Roach ->get() 4330b5fd0a6SGreg Roach ->filter(static function (stdClass $faq) use ($language): bool { 4340b5fd0a6SGreg Roach return $faq->languages === '' || in_array($language, explode(',', $faq->languages), true); 43577654037SGreg Roach }) 43677654037SGreg Roach ->isNotEmpty(); 43777654037SGreg Roach } 4388c2e8227SGreg Roach} 439