18c2e8227SGreg Roach<?php 23976b470SGreg Roach 38c2e8227SGreg Roach/** 48c2e8227SGreg Roach * webtrees: online genealogy 5*d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 68c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 78c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 88c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 98c2e8227SGreg Roach * (at your option) any later version. 108c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 118c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 128c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2e8227SGreg Roach * GNU General Public License for more details. 148c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 168c2e8227SGreg Roach */ 17fcfa147eSGreg Roach 18e7f56f2aSGreg Roachdeclare(strict_types=1); 19e7f56f2aSGreg Roach 2076692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 2176692c8bSGreg Roach 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 231c6adce8SGreg Roachuse Fisharebest\Webtrees\Encodings\ANSEL; 241c6adce8SGreg Roachuse Fisharebest\Webtrees\Encodings\ASCII; 251c6adce8SGreg Roachuse Fisharebest\Webtrees\Encodings\UTF16BE; 261c6adce8SGreg Roachuse Fisharebest\Webtrees\Encodings\UTF8; 271c6adce8SGreg Roachuse Fisharebest\Webtrees\Encodings\Windows1252; 280e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family; 295a78cd34SGreg Roachuse Fisharebest\Webtrees\Gedcom; 300e62c4b8SGreg Roachuse Fisharebest\Webtrees\GedcomRecord; 31f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\FamilyPage; 32f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\IndividualPage; 33e8ded2caSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\LocationPage; 34f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MediaPage; 35f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\NotePage; 36f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\RepositoryPage; 37f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SourcePage; 38d45701ccSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SubmitterPage; 390e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 400e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 41e8ded2caSGreg Roachuse Fisharebest\Webtrees\Location; 425a78cd34SGreg Roachuse Fisharebest\Webtrees\Media; 430e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 445a78cd34SGreg Roachuse Fisharebest\Webtrees\Note; 45d45701ccSGreg Roachuse Fisharebest\Webtrees\Registry; 465a78cd34SGreg Roachuse Fisharebest\Webtrees\Repository; 4769c05a6eSGreg Roachuse Fisharebest\Webtrees\Services\GedcomExportService; 484991f205SGreg Roachuse Fisharebest\Webtrees\Services\LinkedRecordService; 490e62c4b8SGreg Roachuse Fisharebest\Webtrees\Session; 505a78cd34SGreg Roachuse Fisharebest\Webtrees\Source; 51d45701ccSGreg Roachuse Fisharebest\Webtrees\Submitter; 52aee13b6dSGreg Roachuse Fisharebest\Webtrees\Tree; 531c6adce8SGreg Roachuse Fisharebest\Webtrees\Validator; 5469c05a6eSGreg Roachuse Illuminate\Support\Collection; 556ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 566ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 573976b470SGreg Roach 58eb235819SGreg Roachuse function app; 59bf80ec58SGreg Roachuse function array_filter; 60bf80ec58SGreg Roachuse function array_keys; 61bf80ec58SGreg Roachuse function array_map; 62fa695506SGreg Roachuse function array_search; 635229eadeSGreg Roachuse function assert; 6410e06497SGreg Roachuse function count; 6516ecfcafSGreg Roachuse function date; 6616ecfcafSGreg Roachuse function extension_loaded; 67bf80ec58SGreg Roachuse function in_array; 68d8809d62SGreg Roachuse function is_array; 69ddeb3354SGreg Roachuse function is_string; 70bf80ec58SGreg Roachuse function preg_match_all; 71bf80ec58SGreg Roachuse function redirect; 72bf80ec58SGreg Roachuse function route; 73e5a6b4d4SGreg Roachuse function str_replace; 74fa695506SGreg Roachuse function uasort; 75d45701ccSGreg Roachuse function view; 76fa695506SGreg Roach 77fa695506SGreg Roachuse const PREG_SET_ORDER; 788c2e8227SGreg Roach 798c2e8227SGreg Roach/** 808c2e8227SGreg Roach * Class ClippingsCartModule 818c2e8227SGreg Roach */ 8237eb8894SGreg Roachclass ClippingsCartModule extends AbstractModule implements ModuleMenuInterface 83c1010edaSGreg Roach{ 8449a243cbSGreg Roach use ModuleMenuTrait; 8549a243cbSGreg Roach 8603f99a78SGreg Roach // What to add to the cart? 8703f99a78SGreg Roach private const ADD_RECORD_ONLY = 'record'; 8803f99a78SGreg Roach private const ADD_CHILDREN = 'children'; 8903f99a78SGreg Roach private const ADD_DESCENDANTS = 'descendants'; 9003f99a78SGreg Roach private const ADD_PARENT_FAMILIES = 'parents'; 9103f99a78SGreg Roach private const ADD_SPOUSE_FAMILIES = 'spouses'; 9203f99a78SGreg Roach private const ADD_ANCESTORS = 'ancestors'; 9303f99a78SGreg Roach private const ADD_ANCESTOR_FAMILIES = 'families'; 9403f99a78SGreg Roach private const ADD_LINKED_INDIVIDUALS = 'linked'; 9503f99a78SGreg Roach 965a78cd34SGreg Roach // Routes that have a record which can be added to the clipboard 9716d6367aSGreg Roach private const ROUTES_WITH_RECORDS = [ 98f95e0480SGreg Roach 'Family' => FamilyPage::class, 99f95e0480SGreg Roach 'Individual' => IndividualPage::class, 100f95e0480SGreg Roach 'Media' => MediaPage::class, 101e8ded2caSGreg Roach 'Location' => LocationPage::class, 102f95e0480SGreg Roach 'Note' => NotePage::class, 103f95e0480SGreg Roach 'Repository' => RepositoryPage::class, 104f95e0480SGreg Roach 'Source' => SourcePage::class, 105d45701ccSGreg Roach 'Submitter' => SubmitterPage::class, 106c1010edaSGreg Roach ]; 1075a78cd34SGreg Roach 10849a243cbSGreg Roach /** @var int The default access level for this module. It can be changed in the control panel. */ 10933c746f1SGreg Roach protected int $access_level = Auth::PRIV_USER; 11049a243cbSGreg Roach 111ca47b2adSGreg Roach private GedcomExportService $gedcom_export_service; 11269c05a6eSGreg Roach 1134991f205SGreg Roach private LinkedRecordService $linked_record_service; 1144991f205SGreg Roach 115e5a6b4d4SGreg Roach /** 116e5a6b4d4SGreg Roach * ClippingsCartModule constructor. 117e5a6b4d4SGreg Roach * 11869c05a6eSGreg Roach * @param GedcomExportService $gedcom_export_service 1194991f205SGreg Roach * @param LinkedRecordService $linked_record_service 120e5a6b4d4SGreg Roach */ 121ca47b2adSGreg Roach public function __construct( 122ca47b2adSGreg Roach GedcomExportService $gedcom_export_service, 12316ecfcafSGreg Roach LinkedRecordService $linked_record_service 124ca47b2adSGreg Roach ) { 12569c05a6eSGreg Roach $this->gedcom_export_service = $gedcom_export_service; 1264991f205SGreg Roach $this->linked_record_service = $linked_record_service; 127e5a6b4d4SGreg Roach } 128e5a6b4d4SGreg Roach 129e5a6b4d4SGreg Roach /** 130961ec755SGreg Roach * A sentence describing what this module does. 131961ec755SGreg Roach * 132961ec755SGreg Roach * @return string 133961ec755SGreg Roach */ 13449a243cbSGreg Roach public function description(): string 135c1010edaSGreg Roach { 136bbb76c12SGreg Roach /* I18N: Description of the “Clippings cart” module */ 137bbb76c12SGreg Roach return I18N::translate('Select records from your family tree and save them as a GEDCOM file.'); 1388c2e8227SGreg Roach } 1398c2e8227SGreg Roach 1400ee13198SGreg Roach /** 14149a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 1420ee13198SGreg Roach * 1430ee13198SGreg Roach * @return int 1440ee13198SGreg Roach */ 1458f53f488SRico Sonntag public function defaultMenuOrder(): int 146c1010edaSGreg Roach { 147353b36abSGreg Roach return 6; 1488c2e8227SGreg Roach } 1498c2e8227SGreg Roach 1500ee13198SGreg Roach /** 1510ee13198SGreg Roach * A menu, to be added to the main application menu. 1520ee13198SGreg Roach * 153aee13b6dSGreg Roach * @param Tree $tree 154aee13b6dSGreg Roach * 1550ee13198SGreg Roach * @return Menu|null 1560ee13198SGreg Roach */ 15746295629SGreg Roach public function getMenu(Tree $tree): ?Menu 158c1010edaSGreg Roach { 1596ccdf4f0SGreg Roach $request = app(ServerRequestInterface::class); 160b55cbc6bSGreg Roach assert($request instanceof ServerRequestInterface); 1618c2e8227SGreg Roach 162b55cbc6bSGreg Roach $route = Validator::attributes($request)->route(); 163d8809d62SGreg Roach $cart = Session::get('cart'); 164d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 165d45701ccSGreg Roach $count = count($cart[$tree->name()] ?? []); 166d45701ccSGreg Roach $badge = view('components/badge', ['count' => $count]); 167d45701ccSGreg Roach 1685a78cd34SGreg Roach $submenus = [ 169d45701ccSGreg Roach new Menu($this->title() . ' ' . $badge, route('module', [ 17026684e68SGreg Roach 'module' => $this->name(), 171c1010edaSGreg Roach 'action' => 'Show', 172d72b284aSGreg Roach 'tree' => $tree->name(), 173c1010edaSGreg Roach ]), 'menu-clippings-cart', ['rel' => 'nofollow']), 1745a78cd34SGreg Roach ]; 1755a78cd34SGreg Roach 1762b0d92b4SGreg Roach $action = array_search($route->name, self::ROUTES_WITH_RECORDS, true); 177f95e0480SGreg Roach if ($action !== false) { 1782b0d92b4SGreg Roach $xref = $route->attributes['xref']; 179ddeb3354SGreg Roach assert(is_string($xref)); 180ddeb3354SGreg Roach 181c1010edaSGreg Roach $add_route = route('module', [ 18226684e68SGreg Roach 'module' => $this->name(), 183f95e0480SGreg Roach 'action' => 'Add' . $action, 184c1010edaSGreg Roach 'xref' => $xref, 185d72b284aSGreg Roach 'tree' => $tree->name(), 186c1010edaSGreg Roach ]); 1875a78cd34SGreg Roach 18825b2dde3SGreg Roach $submenus[] = new Menu(I18N::translate('Add to the clippings cart'), $add_route, 'menu-clippings-add', ['rel' => 'nofollow']); 1898c2e8227SGreg Roach } 190cbc1590aSGreg Roach 1915a78cd34SGreg Roach if (!$this->isCartEmpty($tree)) { 192c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Empty the clippings cart'), route('module', [ 19326684e68SGreg Roach 'module' => $this->name(), 194c1010edaSGreg Roach 'action' => 'Empty', 195d72b284aSGreg Roach 'tree' => $tree->name(), 196c1010edaSGreg Roach ]), 'menu-clippings-empty', ['rel' => 'nofollow']); 197f95e0480SGreg Roach 198c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Download'), route('module', [ 19926684e68SGreg Roach 'module' => $this->name(), 200c1010edaSGreg Roach 'action' => 'DownloadForm', 201d72b284aSGreg Roach 'tree' => $tree->name(), 202c1010edaSGreg Roach ]), 'menu-clippings-download', ['rel' => 'nofollow']); 2035a78cd34SGreg Roach } 2045a78cd34SGreg Roach 20549a243cbSGreg Roach return new Menu($this->title(), '#', 'menu-clippings', ['rel' => 'nofollow'], $submenus); 2068c2e8227SGreg Roach } 2078c2e8227SGreg Roach 20876692c8bSGreg Roach /** 209d45701ccSGreg Roach * How should this module be identified in the control panel, etc.? 210d45701ccSGreg Roach * 211d45701ccSGreg Roach * @return string 212d45701ccSGreg Roach */ 213d45701ccSGreg Roach public function title(): string 214d45701ccSGreg Roach { 215d45701ccSGreg Roach /* I18N: Name of a module */ 216d45701ccSGreg Roach return I18N::translate('Clippings cart'); 217d45701ccSGreg Roach } 218d45701ccSGreg Roach 219d45701ccSGreg Roach /** 220d45701ccSGreg Roach * @param Tree $tree 221d45701ccSGreg Roach * 222d45701ccSGreg Roach * @return bool 223d45701ccSGreg Roach */ 224d45701ccSGreg Roach private function isCartEmpty(Tree $tree): bool 225d45701ccSGreg Roach { 226d8809d62SGreg Roach $cart = Session::get('cart'); 227d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 228d45701ccSGreg Roach $contents = $cart[$tree->name()] ?? []; 229d45701ccSGreg Roach 230d45701ccSGreg Roach return $contents === []; 231d45701ccSGreg Roach } 232d45701ccSGreg Roach 233d45701ccSGreg Roach /** 234d45701ccSGreg Roach * @param ServerRequestInterface $request 235d45701ccSGreg Roach * 236d45701ccSGreg Roach * @return ResponseInterface 237d45701ccSGreg Roach */ 238d45701ccSGreg Roach public function getDownloadFormAction(ServerRequestInterface $request): ResponseInterface 239d45701ccSGreg Roach { 240b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 241d45701ccSGreg Roach 242d45701ccSGreg Roach $title = I18N::translate('Family tree clippings cart') . ' — ' . I18N::translate('Download'); 243d45701ccSGreg Roach 24416ecfcafSGreg Roach $download_filenames = [ 24516ecfcafSGreg Roach 'clippings' => 'clippings', 24616ecfcafSGreg Roach 'clippings-' . date('Y-m-d') => 'clippings-' . date('Y-m-d'), 24716ecfcafSGreg Roach ]; 24816ecfcafSGreg Roach 249d45701ccSGreg Roach return $this->viewResponse('modules/clippings/download', [ 25016ecfcafSGreg Roach 'download_filenames' => $download_filenames, 251d45701ccSGreg Roach 'module' => $this->name(), 252d45701ccSGreg Roach 'title' => $title, 253d45701ccSGreg Roach 'tree' => $tree, 25416ecfcafSGreg Roach 'zip_available' => extension_loaded('zip'), 255d45701ccSGreg Roach ]); 256d45701ccSGreg Roach } 257d45701ccSGreg Roach 258d45701ccSGreg Roach /** 2596ccdf4f0SGreg Roach * @param ServerRequestInterface $request 26076692c8bSGreg Roach * 2616ccdf4f0SGreg Roach * @return ResponseInterface 26276692c8bSGreg Roach */ 263f95e0480SGreg Roach public function postDownloadAction(ServerRequestInterface $request): ResponseInterface 264c1010edaSGreg Roach { 265b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 2664ea62551SGreg Roach 26716ecfcafSGreg Roach if (Auth::isAdmin()) { 26816ecfcafSGreg Roach $privacy_options = ['none', 'gedadmin', 'user', 'visitor']; 26916ecfcafSGreg Roach } elseif (Auth::isManager($tree)) { 27016ecfcafSGreg Roach $privacy_options = ['gedadmin', 'user', 'visitor']; 27116ecfcafSGreg Roach } elseif (Auth::isMember($tree)) { 27216ecfcafSGreg Roach $privacy_options = ['user', 'visitor']; 27316ecfcafSGreg Roach } else { 27416ecfcafSGreg Roach $privacy_options = ['visitor']; 27516ecfcafSGreg Roach } 276a04bb9a2SGreg Roach 27716ecfcafSGreg Roach $filename = Validator::parsedBody($request)->string('filename'); 27816ecfcafSGreg Roach $format = Validator::parsedBody($request)->isInArray(['gedcom', 'zip', 'zipmedia', 'gedzip'])->string('format'); 27916ecfcafSGreg Roach $privacy = Validator::parsedBody($request)->isInArray($privacy_options)->string('privacy'); 280b55cbc6bSGreg Roach $encoding = Validator::parsedBody($request)->isInArray([UTF8::NAME, UTF16BE::NAME, ANSEL::NAME, ASCII::NAME, Windows1252::NAME])->string('encoding'); 281b55cbc6bSGreg Roach $line_endings = Validator::parsedBody($request)->isInArray(['CRLF', 'LF'])->string('line_endings'); 282b46c87bdSGreg Roach 283d8809d62SGreg Roach $cart = Session::get('cart'); 284d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 2858c2e8227SGreg Roach 286aa6f03bbSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 287c8846facSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 2885a78cd34SGreg Roach 28969c05a6eSGreg Roach $records = new Collection(); 2905a78cd34SGreg Roach 2911c6adce8SGreg Roach switch ($privacy) { 2925a78cd34SGreg Roach case 'gedadmin': 2935a78cd34SGreg Roach $access_level = Auth::PRIV_NONE; 2945a78cd34SGreg Roach break; 2955a78cd34SGreg Roach case 'user': 2965a78cd34SGreg Roach $access_level = Auth::PRIV_USER; 2975a78cd34SGreg Roach break; 2985a78cd34SGreg Roach case 'visitor': 2995a78cd34SGreg Roach $access_level = Auth::PRIV_PRIVATE; 3005a78cd34SGreg Roach break; 3015a78cd34SGreg Roach case 'none': 3025a78cd34SGreg Roach default: 3035a78cd34SGreg Roach $access_level = Auth::PRIV_HIDE; 3045a78cd34SGreg Roach break; 3055a78cd34SGreg Roach } 3065a78cd34SGreg Roach 3075a78cd34SGreg Roach foreach ($xrefs as $xref) { 3086b9cb339SGreg Roach $object = Registry::gedcomRecordFactory()->make($xref, $tree); 3095a78cd34SGreg Roach // The object may have been deleted since we added it to the cart.... 310bed27cedSGreg Roach if ($object instanceof GedcomRecord) { 3115a78cd34SGreg Roach $record = $object->privatizeGedcom($access_level); 3125a78cd34SGreg Roach // Remove links to objects that aren't in the cart 3138d0ebef0SGreg Roach preg_match_all('/\n1 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[2-9].*)*/', $record, $matches, PREG_SET_ORDER); 3145a78cd34SGreg Roach foreach ($matches as $match) { 315bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3165a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3175a78cd34SGreg Roach } 3185a78cd34SGreg Roach } 3198d0ebef0SGreg Roach preg_match_all('/\n2 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[3-9].*)*/', $record, $matches, PREG_SET_ORDER); 3205a78cd34SGreg Roach foreach ($matches as $match) { 321bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3225a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3235a78cd34SGreg Roach } 3245a78cd34SGreg Roach } 3258d0ebef0SGreg Roach preg_match_all('/\n3 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[4-9].*)*/', $record, $matches, PREG_SET_ORDER); 3265a78cd34SGreg Roach foreach ($matches as $match) { 327bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3285a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3295a78cd34SGreg Roach } 3305a78cd34SGreg Roach } 3315a78cd34SGreg Roach 332f566cb16SGreg Roach $records->add($record); 3331c6adce8SGreg Roach } 3341c6adce8SGreg Roach } 335f566cb16SGreg Roach 3361c6adce8SGreg Roach // We have already applied privacy filtering, so do not do it again. 33716ecfcafSGreg Roach return $this->gedcom_export_service->downloadResponse($tree, false, $encoding, 'none', $line_endings, $filename, $format, $records); 3388c2e8227SGreg Roach } 3398c2e8227SGreg Roach 3408c2e8227SGreg Roach /** 34157ab2231SGreg Roach * @param ServerRequestInterface $request 34276692c8bSGreg Roach * 3436ccdf4f0SGreg Roach * @return ResponseInterface 3448c2e8227SGreg Roach */ 34557ab2231SGreg Roach public function getEmptyAction(ServerRequestInterface $request): ResponseInterface 346c1010edaSGreg Roach { 347b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 3484ea62551SGreg Roach 349d8809d62SGreg Roach $cart = Session::get('cart'); 350d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 351d8809d62SGreg Roach 352aa6f03bbSGreg Roach $cart[$tree->name()] = []; 3535a78cd34SGreg Roach Session::put('cart', $cart); 3548c2e8227SGreg Roach 355c1010edaSGreg Roach $url = route('module', [ 35626684e68SGreg Roach 'module' => $this->name(), 357c1010edaSGreg Roach 'action' => 'Show', 358d72b284aSGreg Roach 'tree' => $tree->name(), 359c1010edaSGreg Roach ]); 3605a78cd34SGreg Roach 3616ccdf4f0SGreg Roach return redirect($url); 3625a78cd34SGreg Roach } 3635a78cd34SGreg Roach 3645a78cd34SGreg Roach /** 3656ccdf4f0SGreg Roach * @param ServerRequestInterface $request 3665a78cd34SGreg Roach * 3676ccdf4f0SGreg Roach * @return ResponseInterface 3685a78cd34SGreg Roach */ 36957ab2231SGreg Roach public function postRemoveAction(ServerRequestInterface $request): ResponseInterface 370c1010edaSGreg Roach { 371b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 372748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 373d8809d62SGreg Roach $cart = Session::get('cart'); 374d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 375d8809d62SGreg Roach 376aa6f03bbSGreg Roach unset($cart[$tree->name()][$xref]); 3775a78cd34SGreg Roach Session::put('cart', $cart); 3785a78cd34SGreg Roach 379c1010edaSGreg Roach $url = route('module', [ 38026684e68SGreg Roach 'module' => $this->name(), 381c1010edaSGreg Roach 'action' => 'Show', 382d72b284aSGreg Roach 'tree' => $tree->name(), 383c1010edaSGreg Roach ]); 3845a78cd34SGreg Roach 3856ccdf4f0SGreg Roach return redirect($url); 3865a78cd34SGreg Roach } 3875a78cd34SGreg Roach 3885a78cd34SGreg Roach /** 38957ab2231SGreg Roach * @param ServerRequestInterface $request 3905a78cd34SGreg Roach * 3916ccdf4f0SGreg Roach * @return ResponseInterface 3925a78cd34SGreg Roach */ 39357ab2231SGreg Roach public function getShowAction(ServerRequestInterface $request): ResponseInterface 394c1010edaSGreg Roach { 395b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 39657ab2231SGreg Roach 3975a78cd34SGreg Roach return $this->viewResponse('modules/clippings/show', [ 39877b78a63SRichard Cissée 'module' => $this->name(), 3995a78cd34SGreg Roach 'records' => $this->allRecordsInCart($tree), 4005a78cd34SGreg Roach 'title' => I18N::translate('Family tree clippings cart'), 4015a78cd34SGreg Roach 'tree' => $tree, 4025a78cd34SGreg Roach ]); 4035a78cd34SGreg Roach } 4045a78cd34SGreg Roach 4055a78cd34SGreg Roach /** 406d45701ccSGreg Roach * Get all the records in the cart. 407d45701ccSGreg Roach * 408d45701ccSGreg Roach * @param Tree $tree 409d45701ccSGreg Roach * 41009482a55SGreg Roach * @return array<GedcomRecord> 411d45701ccSGreg Roach */ 412d45701ccSGreg Roach private function allRecordsInCart(Tree $tree): array 413d45701ccSGreg Roach { 414d8809d62SGreg Roach $cart = Session::get('cart'); 415d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 416d45701ccSGreg Roach 417d45701ccSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 418d45701ccSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 419d45701ccSGreg Roach 420d45701ccSGreg Roach // Fetch all the records in the cart. 421d45701ccSGreg Roach $records = array_map(static function (string $xref) use ($tree): ?GedcomRecord { 422d45701ccSGreg Roach return Registry::gedcomRecordFactory()->make($xref, $tree); 423d45701ccSGreg Roach }, $xrefs); 424d45701ccSGreg Roach 425d45701ccSGreg Roach // Some records may have been deleted after they were added to the cart. 426d45701ccSGreg Roach $records = array_filter($records); 427d45701ccSGreg Roach 428d45701ccSGreg Roach // Group and sort. 429d45701ccSGreg Roach uasort($records, static function (GedcomRecord $x, GedcomRecord $y): int { 430d45701ccSGreg Roach return $x->tag() <=> $y->tag() ?: GedcomRecord::nameComparator()($x, $y); 431d45701ccSGreg Roach }); 432d45701ccSGreg Roach 433d45701ccSGreg Roach return $records; 434d45701ccSGreg Roach } 435d45701ccSGreg Roach 436d45701ccSGreg Roach /** 4376ccdf4f0SGreg Roach * @param ServerRequestInterface $request 4385a78cd34SGreg Roach * 4396ccdf4f0SGreg Roach * @return ResponseInterface 4405a78cd34SGreg Roach */ 44157ab2231SGreg Roach public function getAddFamilyAction(ServerRequestInterface $request): ResponseInterface 442c1010edaSGreg Roach { 443b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 444748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 4456b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 446d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 447d45701ccSGreg Roach $name = $family->fullName(); 4485a78cd34SGreg Roach 449d45701ccSGreg Roach $options = [ 45003f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 451bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 45203f99a78SGreg Roach self::ADD_CHILDREN => I18N::translate('%s and their children', $name), 453bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 45403f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s and their descendants', $name), 4555a78cd34SGreg Roach ]; 456d45701ccSGreg Roach 457d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 458d45701ccSGreg Roach 459d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 460d45701ccSGreg Roach 'options' => $options, 461d45701ccSGreg Roach 'record' => $family, 462d45701ccSGreg Roach 'title' => $title, 463d45701ccSGreg Roach 'tree' => $tree, 464d45701ccSGreg Roach ]); 4655a78cd34SGreg Roach } 4665a78cd34SGreg Roach 4675a78cd34SGreg Roach /** 4686ccdf4f0SGreg Roach * @param ServerRequestInterface $request 4695a78cd34SGreg Roach * 4706ccdf4f0SGreg Roach * @return ResponseInterface 4715a78cd34SGreg Roach */ 47257ab2231SGreg Roach public function postAddFamilyAction(ServerRequestInterface $request): ResponseInterface 473c1010edaSGreg Roach { 474b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 475748dbe15SGreg Roach $xref = Validator::parsedBody($request)->isXref()->string('xref'); 476748dbe15SGreg Roach $option = Validator::parsedBody($request)->string('option'); 4775a78cd34SGreg Roach 4786b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 479d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 4805a78cd34SGreg Roach 4815a78cd34SGreg Roach switch ($option) { 48203f99a78SGreg Roach case self::ADD_RECORD_ONLY: 4835a78cd34SGreg Roach $this->addFamilyToCart($family); 4845a78cd34SGreg Roach break; 4855a78cd34SGreg Roach 48603f99a78SGreg Roach case self::ADD_CHILDREN: 4875a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 4885a78cd34SGreg Roach break; 4895a78cd34SGreg Roach 49003f99a78SGreg Roach case self::ADD_DESCENDANTS: 4915a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 4925a78cd34SGreg Roach break; 4935a78cd34SGreg Roach } 4945a78cd34SGreg Roach 4956ccdf4f0SGreg Roach return redirect($family->url()); 4965a78cd34SGreg Roach } 4975a78cd34SGreg Roach 4985a78cd34SGreg Roach 4995a78cd34SGreg Roach /** 5005a78cd34SGreg Roach * @param Family $family 50118d7a90dSGreg Roach * 50218d7a90dSGreg Roach * @return void 5035a78cd34SGreg Roach */ 504d45701ccSGreg Roach protected function addFamilyAndChildrenToCart(Family $family): void 505c1010edaSGreg Roach { 506d45701ccSGreg Roach $this->addFamilyToCart($family); 5075a78cd34SGreg Roach 50839ca88baSGreg Roach foreach ($family->children() as $child) { 509d45701ccSGreg Roach $this->addIndividualToCart($child); 5105a78cd34SGreg Roach } 5115a78cd34SGreg Roach } 5125a78cd34SGreg Roach 5135a78cd34SGreg Roach /** 5145a78cd34SGreg Roach * @param Family $family 51518d7a90dSGreg Roach * 51618d7a90dSGreg Roach * @return void 5175a78cd34SGreg Roach */ 518d45701ccSGreg Roach protected function addFamilyAndDescendantsToCart(Family $family): void 519c1010edaSGreg Roach { 520d45701ccSGreg Roach $this->addFamilyAndChildrenToCart($family); 5215a78cd34SGreg Roach 52239ca88baSGreg Roach foreach ($family->children() as $child) { 52339ca88baSGreg Roach foreach ($child->spouseFamilies() as $child_family) { 5245a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($child_family); 5255a78cd34SGreg Roach } 5265a78cd34SGreg Roach } 5275a78cd34SGreg Roach } 5285a78cd34SGreg Roach 5295a78cd34SGreg Roach /** 5306ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5315a78cd34SGreg Roach * 5326ccdf4f0SGreg Roach * @return ResponseInterface 5335a78cd34SGreg Roach */ 53457ab2231SGreg Roach public function getAddIndividualAction(ServerRequestInterface $request): ResponseInterface 535c1010edaSGreg Roach { 536b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 537748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 5386b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 539d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 540d45701ccSGreg Roach $name = $individual->fullName(); 5415a78cd34SGreg Roach 54239ca88baSGreg Roach if ($individual->sex() === 'F') { 543d45701ccSGreg Roach $options = [ 54403f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 54503f99a78SGreg Roach self::ADD_PARENT_FAMILIES => I18N::translate('%s, her parents and siblings', $name), 54603f99a78SGreg Roach self::ADD_SPOUSE_FAMILIES => I18N::translate('%s, her spouses and children', $name), 54703f99a78SGreg Roach self::ADD_ANCESTORS => I18N::translate('%s and her ancestors', $name), 54803f99a78SGreg Roach self::ADD_ANCESTOR_FAMILIES => I18N::translate('%s, her ancestors and their families', $name), 54903f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s, her spouses and descendants', $name), 5505a78cd34SGreg Roach ]; 551d45701ccSGreg Roach } else { 552d45701ccSGreg Roach $options = [ 55303f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 55403f99a78SGreg Roach self::ADD_PARENT_FAMILIES => I18N::translate('%s, his parents and siblings', $name), 55503f99a78SGreg Roach self::ADD_SPOUSE_FAMILIES => I18N::translate('%s, his spouses and children', $name), 55603f99a78SGreg Roach self::ADD_ANCESTORS => I18N::translate('%s and his ancestors', $name), 55703f99a78SGreg Roach self::ADD_ANCESTOR_FAMILIES => I18N::translate('%s, his ancestors and their families', $name), 55803f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s, his spouses and descendants', $name), 5595a78cd34SGreg Roach ]; 5605a78cd34SGreg Roach } 5615a78cd34SGreg Roach 562d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 563d45701ccSGreg Roach 564d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 565d45701ccSGreg Roach 'options' => $options, 566d45701ccSGreg Roach 'record' => $individual, 567d45701ccSGreg Roach 'title' => $title, 568d45701ccSGreg Roach 'tree' => $tree, 569d45701ccSGreg Roach ]); 570d45701ccSGreg Roach } 571d45701ccSGreg Roach 5725a78cd34SGreg Roach /** 5736ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5745a78cd34SGreg Roach * 5756ccdf4f0SGreg Roach * @return ResponseInterface 5765a78cd34SGreg Roach */ 57757ab2231SGreg Roach public function postAddIndividualAction(ServerRequestInterface $request): ResponseInterface 578c1010edaSGreg Roach { 579b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 580748dbe15SGreg Roach $xref = Validator::parsedBody($request)->isXref()->string('xref'); 581748dbe15SGreg Roach $option = Validator::parsedBody($request)->string('option'); 5825a78cd34SGreg Roach 5836b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 584d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 5855a78cd34SGreg Roach 5865a78cd34SGreg Roach switch ($option) { 58703f99a78SGreg Roach case self::ADD_RECORD_ONLY: 588d45701ccSGreg Roach $this->addIndividualToCart($individual); 5895a78cd34SGreg Roach break; 5905a78cd34SGreg Roach 59103f99a78SGreg Roach case self::ADD_PARENT_FAMILIES: 59239ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 5935a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 5945a78cd34SGreg Roach } 5955a78cd34SGreg Roach break; 5965a78cd34SGreg Roach 59703f99a78SGreg Roach case self::ADD_SPOUSE_FAMILIES: 59839ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 5995a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6005a78cd34SGreg Roach } 6015a78cd34SGreg Roach break; 6025a78cd34SGreg Roach 60303f99a78SGreg Roach case self::ADD_ANCESTORS: 6045a78cd34SGreg Roach $this->addAncestorsToCart($individual); 6055a78cd34SGreg Roach break; 6065a78cd34SGreg Roach 60703f99a78SGreg Roach case self::ADD_ANCESTOR_FAMILIES: 6085a78cd34SGreg Roach $this->addAncestorFamiliesToCart($individual); 6095a78cd34SGreg Roach break; 6105a78cd34SGreg Roach 61103f99a78SGreg Roach case self::ADD_DESCENDANTS: 61239ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 6135a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 6145a78cd34SGreg Roach } 6155a78cd34SGreg Roach break; 6165a78cd34SGreg Roach } 6175a78cd34SGreg Roach 6186ccdf4f0SGreg Roach return redirect($individual->url()); 6195a78cd34SGreg Roach } 6205a78cd34SGreg Roach 6215a78cd34SGreg Roach /** 6225a78cd34SGreg Roach * @param Individual $individual 62318d7a90dSGreg Roach * 62418d7a90dSGreg Roach * @return void 6255a78cd34SGreg Roach */ 626d45701ccSGreg Roach protected function addAncestorsToCart(Individual $individual): void 627c1010edaSGreg Roach { 628d45701ccSGreg Roach $this->addIndividualToCart($individual); 6295a78cd34SGreg Roach 63039ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 631d45701ccSGreg Roach $this->addFamilyToCart($family); 6328df4c68dSGreg Roach 63339ca88baSGreg Roach foreach ($family->spouses() as $parent) { 6345a78cd34SGreg Roach $this->addAncestorsToCart($parent); 6355a78cd34SGreg Roach } 6365a78cd34SGreg Roach } 6375a78cd34SGreg Roach } 6385a78cd34SGreg Roach 6395a78cd34SGreg Roach /** 6405a78cd34SGreg Roach * @param Individual $individual 64118d7a90dSGreg Roach * 64218d7a90dSGreg Roach * @return void 6435a78cd34SGreg Roach */ 644d45701ccSGreg Roach protected function addAncestorFamiliesToCart(Individual $individual): void 645c1010edaSGreg Roach { 64639ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 6475a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6488df4c68dSGreg Roach 64939ca88baSGreg Roach foreach ($family->spouses() as $parent) { 650cad6d3f3SGreg Roach $this->addAncestorFamiliesToCart($parent); 6515a78cd34SGreg Roach } 6525a78cd34SGreg Roach } 6535a78cd34SGreg Roach } 6545a78cd34SGreg Roach 6555a78cd34SGreg Roach /** 6566ccdf4f0SGreg Roach * @param ServerRequestInterface $request 6575a78cd34SGreg Roach * 6586ccdf4f0SGreg Roach * @return ResponseInterface 6595a78cd34SGreg Roach */ 660e8ded2caSGreg Roach public function getAddLocationAction(ServerRequestInterface $request): ResponseInterface 661e8ded2caSGreg Roach { 662b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 663748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 664e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $tree); 665e8ded2caSGreg Roach $location = Auth::checkLocationAccess($location); 666e8ded2caSGreg Roach $name = $location->fullName(); 667e8ded2caSGreg Roach 668e8ded2caSGreg Roach $options = [ 66903f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 670e8ded2caSGreg Roach ]; 671e8ded2caSGreg Roach 672e8ded2caSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 673e8ded2caSGreg Roach 674e8ded2caSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 675e8ded2caSGreg Roach 'options' => $options, 676e8ded2caSGreg Roach 'record' => $location, 677e8ded2caSGreg Roach 'title' => $title, 678e8ded2caSGreg Roach 'tree' => $tree, 679e8ded2caSGreg Roach ]); 680e8ded2caSGreg Roach } 681e8ded2caSGreg Roach 682e8ded2caSGreg Roach /** 683e8ded2caSGreg Roach * @param ServerRequestInterface $request 684e8ded2caSGreg Roach * 685e8ded2caSGreg Roach * @return ResponseInterface 686e8ded2caSGreg Roach */ 687e8ded2caSGreg Roach public function postAddLocationAction(ServerRequestInterface $request): ResponseInterface 688e8ded2caSGreg Roach { 689b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 690748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 691e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $tree); 692e8ded2caSGreg Roach $location = Auth::checkLocationAccess($location); 693e8ded2caSGreg Roach 694e8ded2caSGreg Roach $this->addLocationToCart($location); 695e8ded2caSGreg Roach 696e8ded2caSGreg Roach return redirect($location->url()); 697e8ded2caSGreg Roach } 698e8ded2caSGreg Roach 699e8ded2caSGreg Roach /** 700e8ded2caSGreg Roach * @param ServerRequestInterface $request 701e8ded2caSGreg Roach * 702e8ded2caSGreg Roach * @return ResponseInterface 703e8ded2caSGreg Roach */ 70457ab2231SGreg Roach public function getAddMediaAction(ServerRequestInterface $request): ResponseInterface 705c1010edaSGreg Roach { 706b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 707748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 7086b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 709d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 710d45701ccSGreg Roach $name = $media->fullName(); 7115a78cd34SGreg Roach 712d45701ccSGreg Roach $options = [ 71303f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 714d45701ccSGreg Roach ]; 7155a78cd34SGreg Roach 716d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 7175a78cd34SGreg Roach 7185a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 7195a78cd34SGreg Roach 'options' => $options, 7205a78cd34SGreg Roach 'record' => $media, 7215a78cd34SGreg Roach 'title' => $title, 7225a78cd34SGreg Roach 'tree' => $tree, 7235a78cd34SGreg Roach ]); 7245a78cd34SGreg Roach } 7255a78cd34SGreg Roach 7265a78cd34SGreg Roach /** 7276ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7285a78cd34SGreg Roach * 7296ccdf4f0SGreg Roach * @return ResponseInterface 7305a78cd34SGreg Roach */ 73157ab2231SGreg Roach public function postAddMediaAction(ServerRequestInterface $request): ResponseInterface 732c1010edaSGreg Roach { 733b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 734748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 7356b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 736d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 7375a78cd34SGreg Roach 738d45701ccSGreg Roach $this->addMediaToCart($media); 7395a78cd34SGreg Roach 7406ccdf4f0SGreg Roach return redirect($media->url()); 7415a78cd34SGreg Roach } 7425a78cd34SGreg Roach 7435a78cd34SGreg Roach /** 7446ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7455a78cd34SGreg Roach * 7466ccdf4f0SGreg Roach * @return ResponseInterface 7475a78cd34SGreg Roach */ 74857ab2231SGreg Roach public function getAddNoteAction(ServerRequestInterface $request): ResponseInterface 749c1010edaSGreg Roach { 750b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 751748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 7526b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 753d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 754d45701ccSGreg Roach $name = $note->fullName(); 7555a78cd34SGreg Roach 756d45701ccSGreg Roach $options = [ 75703f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 758d45701ccSGreg Roach ]; 7595a78cd34SGreg Roach 760d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 7615a78cd34SGreg Roach 7625a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 7635a78cd34SGreg Roach 'options' => $options, 7645a78cd34SGreg Roach 'record' => $note, 7655a78cd34SGreg Roach 'title' => $title, 7665a78cd34SGreg Roach 'tree' => $tree, 7675a78cd34SGreg Roach ]); 7685a78cd34SGreg Roach } 7695a78cd34SGreg Roach 7705a78cd34SGreg Roach /** 7716ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7725a78cd34SGreg Roach * 7736ccdf4f0SGreg Roach * @return ResponseInterface 7745a78cd34SGreg Roach */ 77557ab2231SGreg Roach public function postAddNoteAction(ServerRequestInterface $request): ResponseInterface 776c1010edaSGreg Roach { 777b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 778748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 7796b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 780d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 7815a78cd34SGreg Roach 782d45701ccSGreg Roach $this->addNoteToCart($note); 7835a78cd34SGreg Roach 7846ccdf4f0SGreg Roach return redirect($note->url()); 7855a78cd34SGreg Roach } 7865a78cd34SGreg Roach 7875a78cd34SGreg Roach /** 7886ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7895a78cd34SGreg Roach * 7906ccdf4f0SGreg Roach * @return ResponseInterface 7915a78cd34SGreg Roach */ 79257ab2231SGreg Roach public function getAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 793c1010edaSGreg Roach { 794b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 795748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 7966b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 797d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 798d45701ccSGreg Roach $name = $repository->fullName(); 7995a78cd34SGreg Roach 800d45701ccSGreg Roach $options = [ 80103f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 802d45701ccSGreg Roach ]; 8035a78cd34SGreg Roach 804d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 8055a78cd34SGreg Roach 8065a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 8075a78cd34SGreg Roach 'options' => $options, 8085a78cd34SGreg Roach 'record' => $repository, 8095a78cd34SGreg Roach 'title' => $title, 8105a78cd34SGreg Roach 'tree' => $tree, 8115a78cd34SGreg Roach ]); 8125a78cd34SGreg Roach } 8135a78cd34SGreg Roach 8145a78cd34SGreg Roach /** 8156ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8165a78cd34SGreg Roach * 8176ccdf4f0SGreg Roach * @return ResponseInterface 8185a78cd34SGreg Roach */ 81957ab2231SGreg Roach public function postAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 820c1010edaSGreg Roach { 821b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 822748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 8236b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 824d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 8255a78cd34SGreg Roach 826d45701ccSGreg Roach $this->addRepositoryToCart($repository); 827d45701ccSGreg Roach 8284991f205SGreg Roach foreach ($this->linked_record_service->linkedSources($repository) as $source) { 829d45701ccSGreg Roach $this->addSourceToCart($source); 8305a78cd34SGreg Roach } 8315a78cd34SGreg Roach 8326ccdf4f0SGreg Roach return redirect($repository->url()); 8335a78cd34SGreg Roach } 8345a78cd34SGreg Roach 8355a78cd34SGreg Roach /** 8366ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8375a78cd34SGreg Roach * 8386ccdf4f0SGreg Roach * @return ResponseInterface 8395a78cd34SGreg Roach */ 84057ab2231SGreg Roach public function getAddSourceAction(ServerRequestInterface $request): ResponseInterface 841c1010edaSGreg Roach { 842b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 843748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 8446b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 845d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 846d45701ccSGreg Roach $name = $source->fullName(); 8475a78cd34SGreg Roach 848d45701ccSGreg Roach $options = [ 84903f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 85003f99a78SGreg Roach self::ADD_LINKED_INDIVIDUALS => I18N::translate('%s and the individuals that reference it.', $name), 851d45701ccSGreg Roach ]; 8525a78cd34SGreg Roach 853d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 8545a78cd34SGreg Roach 8555a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 8565a78cd34SGreg Roach 'options' => $options, 8575a78cd34SGreg Roach 'record' => $source, 8585a78cd34SGreg Roach 'title' => $title, 8595a78cd34SGreg Roach 'tree' => $tree, 8605a78cd34SGreg Roach ]); 8615a78cd34SGreg Roach } 8625a78cd34SGreg Roach 8635a78cd34SGreg Roach /** 8646ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8655a78cd34SGreg Roach * 8666ccdf4f0SGreg Roach * @return ResponseInterface 8675a78cd34SGreg Roach */ 86857ab2231SGreg Roach public function postAddSourceAction(ServerRequestInterface $request): ResponseInterface 869c1010edaSGreg Roach { 870b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 871748dbe15SGreg Roach $xref = Validator::parsedBody($request)->isXref()->string('xref'); 872748dbe15SGreg Roach $option = Validator::parsedBody($request)->string('option'); 8735a78cd34SGreg Roach 8746b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 875d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 8765a78cd34SGreg Roach 877d45701ccSGreg Roach $this->addSourceToCart($source); 8785a78cd34SGreg Roach 87903f99a78SGreg Roach if ($option === self::ADD_LINKED_INDIVIDUALS) { 8804991f205SGreg Roach foreach ($this->linked_record_service->linkedIndividuals($source) as $individual) { 881d45701ccSGreg Roach $this->addIndividualToCart($individual); 8825a78cd34SGreg Roach } 8834991f205SGreg Roach foreach ($this->linked_record_service->linkedFamilies($source) as $family) { 884d45701ccSGreg Roach $this->addFamilyToCart($family); 8855a78cd34SGreg Roach } 8865a78cd34SGreg Roach } 8875a78cd34SGreg Roach 8886ccdf4f0SGreg Roach return redirect($source->url()); 8895a78cd34SGreg Roach } 8905a78cd34SGreg Roach 8915a78cd34SGreg Roach /** 892d45701ccSGreg Roach * @param ServerRequestInterface $request 8935a78cd34SGreg Roach * 894d45701ccSGreg Roach * @return ResponseInterface 8955a78cd34SGreg Roach */ 896d45701ccSGreg Roach public function getAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 897c1010edaSGreg Roach { 898b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 899748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 900d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 901d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 902d45701ccSGreg Roach $name = $submitter->fullName(); 9035a78cd34SGreg Roach 904d45701ccSGreg Roach $options = [ 90503f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 906d45701ccSGreg Roach ]; 9075a78cd34SGreg Roach 908d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 9095a78cd34SGreg Roach 910d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 911d45701ccSGreg Roach 'options' => $options, 912d45701ccSGreg Roach 'record' => $submitter, 913d45701ccSGreg Roach 'title' => $title, 914d45701ccSGreg Roach 'tree' => $tree, 915d45701ccSGreg Roach ]); 9165a78cd34SGreg Roach } 9175a78cd34SGreg Roach 9185a78cd34SGreg Roach /** 919d45701ccSGreg Roach * @param ServerRequestInterface $request 9205a78cd34SGreg Roach * 921d45701ccSGreg Roach * @return ResponseInterface 9225a78cd34SGreg Roach */ 923d45701ccSGreg Roach public function postAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 924d45701ccSGreg Roach { 925b55cbc6bSGreg Roach $tree = Validator::attributes($request)->tree(); 926748dbe15SGreg Roach $xref = Validator::queryParams($request)->isXref()->string('xref'); 927d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 928d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 929d45701ccSGreg Roach 930d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 931d45701ccSGreg Roach 932d45701ccSGreg Roach return redirect($submitter->url()); 933d45701ccSGreg Roach } 934d45701ccSGreg Roach 935d45701ccSGreg Roach /** 936d45701ccSGreg Roach * @param Family $family 937d45701ccSGreg Roach */ 938d45701ccSGreg Roach protected function addFamilyToCart(Family $family): void 939c1010edaSGreg Roach { 940d8809d62SGreg Roach $cart = Session::get('cart'); 941d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 942d8809d62SGreg Roach 943d45701ccSGreg Roach $tree = $family->tree()->name(); 944d45701ccSGreg Roach $xref = $family->xref(); 9455a78cd34SGreg Roach 946d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 947d45701ccSGreg Roach $cart[$tree][$xref] = true; 9485a78cd34SGreg Roach 949d45701ccSGreg Roach Session::put('cart', $cart); 9505a78cd34SGreg Roach 951d45701ccSGreg Roach foreach ($family->spouses() as $spouse) { 952d45701ccSGreg Roach $this->addIndividualToCart($spouse); 9535a78cd34SGreg Roach } 9545a78cd34SGreg Roach 955e8ded2caSGreg Roach $this->addLocationLinksToCart($family); 956d45701ccSGreg Roach $this->addMediaLinksToCart($family); 957d45701ccSGreg Roach $this->addNoteLinksToCart($family); 958d45701ccSGreg Roach $this->addSourceLinksToCart($family); 959d45701ccSGreg Roach $this->addSubmitterLinksToCart($family); 960d45701ccSGreg Roach } 961d45701ccSGreg Roach } 962d45701ccSGreg Roach 963d45701ccSGreg Roach /** 964d45701ccSGreg Roach * @param Individual $individual 965d45701ccSGreg Roach */ 966d45701ccSGreg Roach protected function addIndividualToCart(Individual $individual): void 967d45701ccSGreg Roach { 968d8809d62SGreg Roach $cart = Session::get('cart'); 969d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 970d8809d62SGreg Roach 971d45701ccSGreg Roach $tree = $individual->tree()->name(); 972d45701ccSGreg Roach $xref = $individual->xref(); 973d45701ccSGreg Roach 974d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 975d45701ccSGreg Roach $cart[$tree][$xref] = true; 976d45701ccSGreg Roach 977d45701ccSGreg Roach Session::put('cart', $cart); 978d45701ccSGreg Roach 979e8ded2caSGreg Roach $this->addLocationLinksToCart($individual); 980d45701ccSGreg Roach $this->addMediaLinksToCart($individual); 981d45701ccSGreg Roach $this->addNoteLinksToCart($individual); 982d45701ccSGreg Roach $this->addSourceLinksToCart($individual); 983d45701ccSGreg Roach } 984d45701ccSGreg Roach } 985d45701ccSGreg Roach 986d45701ccSGreg Roach /** 987e8ded2caSGreg Roach * @param Location $location 988e8ded2caSGreg Roach */ 989e8ded2caSGreg Roach protected function addLocationToCart(Location $location): void 990e8ded2caSGreg Roach { 991d8809d62SGreg Roach $cart = Session::get('cart'); 992d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 993d8809d62SGreg Roach 994e8ded2caSGreg Roach $tree = $location->tree()->name(); 995e8ded2caSGreg Roach $xref = $location->xref(); 996e8ded2caSGreg Roach 997e8ded2caSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 998e8ded2caSGreg Roach $cart[$tree][$xref] = true; 999e8ded2caSGreg Roach 1000e8ded2caSGreg Roach Session::put('cart', $cart); 1001e8ded2caSGreg Roach 1002e8ded2caSGreg Roach $this->addLocationLinksToCart($location); 1003e8ded2caSGreg Roach $this->addMediaLinksToCart($location); 1004e8ded2caSGreg Roach $this->addNoteLinksToCart($location); 1005e8ded2caSGreg Roach $this->addSourceLinksToCart($location); 1006e8ded2caSGreg Roach } 1007e8ded2caSGreg Roach } 1008e8ded2caSGreg Roach 1009e8ded2caSGreg Roach /** 1010e8ded2caSGreg Roach * @param GedcomRecord $record 1011e8ded2caSGreg Roach */ 1012e8ded2caSGreg Roach protected function addLocationLinksToCart(GedcomRecord $record): void 1013e8ded2caSGreg Roach { 1014e8ded2caSGreg Roach preg_match_all('/\n\d _LOC @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1015e8ded2caSGreg Roach 1016e8ded2caSGreg Roach foreach ($matches[1] as $xref) { 1017e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $record->tree()); 1018e8ded2caSGreg Roach 1019e8ded2caSGreg Roach if ($location instanceof Location && $location->canShow()) { 1020e8ded2caSGreg Roach $this->addLocationToCart($location); 1021e8ded2caSGreg Roach } 1022e8ded2caSGreg Roach } 1023e8ded2caSGreg Roach } 1024e8ded2caSGreg Roach 1025e8ded2caSGreg Roach /** 1026d45701ccSGreg Roach * @param Media $media 1027d45701ccSGreg Roach */ 1028d45701ccSGreg Roach protected function addMediaToCart(Media $media): void 1029d45701ccSGreg Roach { 1030d8809d62SGreg Roach $cart = Session::get('cart'); 1031d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 1032d8809d62SGreg Roach 1033d45701ccSGreg Roach $tree = $media->tree()->name(); 1034d45701ccSGreg Roach $xref = $media->xref(); 1035d45701ccSGreg Roach 1036d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1037d45701ccSGreg Roach $cart[$tree][$xref] = true; 1038d45701ccSGreg Roach 1039d45701ccSGreg Roach Session::put('cart', $cart); 1040d45701ccSGreg Roach 1041d45701ccSGreg Roach $this->addNoteLinksToCart($media); 1042d45701ccSGreg Roach } 1043d45701ccSGreg Roach } 1044d45701ccSGreg Roach 1045d45701ccSGreg Roach /** 1046d45701ccSGreg Roach * @param GedcomRecord $record 1047d45701ccSGreg Roach */ 1048d45701ccSGreg Roach protected function addMediaLinksToCart(GedcomRecord $record): void 1049d45701ccSGreg Roach { 1050d45701ccSGreg Roach preg_match_all('/\n\d OBJE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1051d45701ccSGreg Roach 1052d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1053d45701ccSGreg Roach $media = Registry::mediaFactory()->make($xref, $record->tree()); 1054d45701ccSGreg Roach 1055d45701ccSGreg Roach if ($media instanceof Media && $media->canShow()) { 1056d45701ccSGreg Roach $this->addMediaToCart($media); 1057d45701ccSGreg Roach } 1058d45701ccSGreg Roach } 1059d45701ccSGreg Roach } 1060d45701ccSGreg Roach 1061d45701ccSGreg Roach /** 1062d45701ccSGreg Roach * @param Note $note 1063d45701ccSGreg Roach */ 1064d45701ccSGreg Roach protected function addNoteToCart(Note $note): void 1065d45701ccSGreg Roach { 1066d8809d62SGreg Roach $cart = Session::get('cart'); 1067d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 1068d8809d62SGreg Roach 1069d45701ccSGreg Roach $tree = $note->tree()->name(); 1070d45701ccSGreg Roach $xref = $note->xref(); 1071d45701ccSGreg Roach 1072d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1073d45701ccSGreg Roach $cart[$tree][$xref] = true; 1074d45701ccSGreg Roach 10755a78cd34SGreg Roach Session::put('cart', $cart); 10765a78cd34SGreg Roach } 1077d45701ccSGreg Roach } 10785a78cd34SGreg Roach 10795a78cd34SGreg Roach /** 1080d45701ccSGreg Roach * @param GedcomRecord $record 10815a78cd34SGreg Roach */ 1082d45701ccSGreg Roach protected function addNoteLinksToCart(GedcomRecord $record): void 1083d45701ccSGreg Roach { 1084d45701ccSGreg Roach preg_match_all('/\n\d NOTE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1085d45701ccSGreg Roach 1086d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1087d45701ccSGreg Roach $note = Registry::noteFactory()->make($xref, $record->tree()); 1088d45701ccSGreg Roach 1089d45701ccSGreg Roach if ($note instanceof Note && $note->canShow()) { 1090d45701ccSGreg Roach $this->addNoteToCart($note); 1091d45701ccSGreg Roach } 1092d45701ccSGreg Roach } 1093d45701ccSGreg Roach } 1094d45701ccSGreg Roach 1095d45701ccSGreg Roach /** 1096d45701ccSGreg Roach * @param Source $source 1097d45701ccSGreg Roach */ 1098d45701ccSGreg Roach protected function addSourceToCart(Source $source): void 1099c1010edaSGreg Roach { 1100d8809d62SGreg Roach $cart = Session::get('cart'); 1101d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 1102d8809d62SGreg Roach 1103d45701ccSGreg Roach $tree = $source->tree()->name(); 1104d45701ccSGreg Roach $xref = $source->xref(); 11055a78cd34SGreg Roach 1106d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1107d45701ccSGreg Roach $cart[$tree][$xref] = true; 1108d45701ccSGreg Roach 1109d45701ccSGreg Roach Session::put('cart', $cart); 1110d45701ccSGreg Roach 1111d45701ccSGreg Roach $this->addNoteLinksToCart($source); 1112d45701ccSGreg Roach $this->addRepositoryLinksToCart($source); 1113d45701ccSGreg Roach } 1114d45701ccSGreg Roach } 1115d45701ccSGreg Roach 1116d45701ccSGreg Roach /** 1117d45701ccSGreg Roach * @param GedcomRecord $record 1118d45701ccSGreg Roach */ 1119d45701ccSGreg Roach protected function addSourceLinksToCart(GedcomRecord $record): void 1120d45701ccSGreg Roach { 1121d45701ccSGreg Roach preg_match_all('/\n\d SOUR @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1122d45701ccSGreg Roach 1123d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1124d45701ccSGreg Roach $source = Registry::sourceFactory()->make($xref, $record->tree()); 1125d45701ccSGreg Roach 1126d45701ccSGreg Roach if ($source instanceof Source && $source->canShow()) { 1127d45701ccSGreg Roach $this->addSourceToCart($source); 1128d45701ccSGreg Roach } 1129d45701ccSGreg Roach } 1130d45701ccSGreg Roach } 1131d45701ccSGreg Roach 1132d45701ccSGreg Roach /** 1133d45701ccSGreg Roach * @param Repository $repository 1134d45701ccSGreg Roach */ 1135d45701ccSGreg Roach protected function addRepositoryToCart(Repository $repository): void 1136d45701ccSGreg Roach { 1137d8809d62SGreg Roach $cart = Session::get('cart'); 1138d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 1139d8809d62SGreg Roach 1140d45701ccSGreg Roach $tree = $repository->tree()->name(); 1141d45701ccSGreg Roach $xref = $repository->xref(); 1142d45701ccSGreg Roach 1143d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1144d45701ccSGreg Roach $cart[$tree][$xref] = true; 1145d45701ccSGreg Roach 1146d45701ccSGreg Roach Session::put('cart', $cart); 1147d45701ccSGreg Roach 1148d45701ccSGreg Roach $this->addNoteLinksToCart($repository); 1149d45701ccSGreg Roach } 1150d45701ccSGreg Roach } 1151d45701ccSGreg Roach 1152d45701ccSGreg Roach /** 1153d45701ccSGreg Roach * @param GedcomRecord $record 1154d45701ccSGreg Roach */ 1155d45701ccSGreg Roach protected function addRepositoryLinksToCart(GedcomRecord $record): void 1156d45701ccSGreg Roach { 1157d45701ccSGreg Roach preg_match_all('/\n\d REPO @(' . Gedcom::REGEX_XREF . '@)/', $record->gedcom(), $matches); 1158d45701ccSGreg Roach 1159d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1160d45701ccSGreg Roach $repository = Registry::repositoryFactory()->make($xref, $record->tree()); 1161d45701ccSGreg Roach 1162d45701ccSGreg Roach if ($repository instanceof Repository && $repository->canShow()) { 1163d45701ccSGreg Roach $this->addRepositoryToCart($repository); 1164d45701ccSGreg Roach } 1165d45701ccSGreg Roach } 1166d45701ccSGreg Roach } 1167d45701ccSGreg Roach 1168d45701ccSGreg Roach /** 1169d45701ccSGreg Roach * @param Submitter $submitter 1170d45701ccSGreg Roach */ 1171d45701ccSGreg Roach protected function addSubmitterToCart(Submitter $submitter): void 1172d45701ccSGreg Roach { 1173d8809d62SGreg Roach $cart = Session::get('cart'); 1174d8809d62SGreg Roach $cart = is_array($cart) ? $cart : []; 1175d45701ccSGreg Roach $tree = $submitter->tree()->name(); 1176d45701ccSGreg Roach $xref = $submitter->xref(); 1177d45701ccSGreg Roach 1178d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1179d45701ccSGreg Roach $cart[$tree][$xref] = true; 1180d45701ccSGreg Roach 1181d45701ccSGreg Roach Session::put('cart', $cart); 1182d45701ccSGreg Roach 1183d45701ccSGreg Roach $this->addNoteLinksToCart($submitter); 1184d45701ccSGreg Roach } 1185d45701ccSGreg Roach } 1186d45701ccSGreg Roach 1187d45701ccSGreg Roach /** 1188d45701ccSGreg Roach * @param GedcomRecord $record 1189d45701ccSGreg Roach */ 1190d45701ccSGreg Roach protected function addSubmitterLinksToCart(GedcomRecord $record): void 1191d45701ccSGreg Roach { 1192d45701ccSGreg Roach preg_match_all('/\n\d SUBM @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1193d45701ccSGreg Roach 1194d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1195d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $record->tree()); 1196d45701ccSGreg Roach 1197d45701ccSGreg Roach if ($submitter instanceof Submitter && $submitter->canShow()) { 1198d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 1199d45701ccSGreg Roach } 1200d45701ccSGreg Roach } 12015a78cd34SGreg Roach } 12028c2e8227SGreg Roach} 1203