18c2e8227SGreg Roach<?php 23976b470SGreg Roach 38c2e8227SGreg Roach/** 48c2e8227SGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 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 22de2aa325SGreg Roachuse Aura\Router\Route; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family; 255a78cd34SGreg Roachuse Fisharebest\Webtrees\Gedcom; 260e62c4b8SGreg Roachuse Fisharebest\Webtrees\GedcomRecord; 27f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\FamilyPage; 28f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\IndividualPage; 29e8ded2caSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\LocationPage; 30f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MediaPage; 31f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\NotePage; 32f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\RepositoryPage; 33f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SourcePage; 34d45701ccSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SubmitterPage; 350e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 360e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 37e8ded2caSGreg Roachuse Fisharebest\Webtrees\Location; 385a78cd34SGreg Roachuse Fisharebest\Webtrees\Media; 390e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 405a78cd34SGreg Roachuse Fisharebest\Webtrees\Note; 41d45701ccSGreg Roachuse Fisharebest\Webtrees\Registry; 425a78cd34SGreg Roachuse Fisharebest\Webtrees\Repository; 4369c05a6eSGreg Roachuse Fisharebest\Webtrees\Services\GedcomExportService; 44e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Services\UserService; 450e62c4b8SGreg Roachuse Fisharebest\Webtrees\Session; 465a78cd34SGreg Roachuse Fisharebest\Webtrees\Source; 47d45701ccSGreg Roachuse Fisharebest\Webtrees\Submitter; 48aee13b6dSGreg Roachuse Fisharebest\Webtrees\Tree; 4969c05a6eSGreg Roachuse Illuminate\Support\Collection; 505a78cd34SGreg Roachuse League\Flysystem\Filesystem; 51f0448b68SGreg Roachuse League\Flysystem\FilesystemException; 52f32d77e6SGreg Roachuse League\Flysystem\ZipArchive\FilesystemZipArchiveProvider; 535a78cd34SGreg Roachuse League\Flysystem\ZipArchive\ZipArchiveAdapter; 54*00c45d23SGreg Roachuse Psr\Http\Message\ResponseFactoryInterface; 556ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 566ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 57*00c45d23SGreg Roachuse Psr\Http\Message\StreamFactoryInterface; 5869c05a6eSGreg Roachuse RuntimeException; 593976b470SGreg Roach 60eb235819SGreg Roachuse function app; 61bf80ec58SGreg Roachuse function array_filter; 62bf80ec58SGreg Roachuse function array_keys; 63bf80ec58SGreg Roachuse function array_map; 64fa695506SGreg Roachuse function array_search; 655229eadeSGreg Roachuse function assert; 6669c05a6eSGreg Roachuse function fopen; 67bf80ec58SGreg Roachuse function in_array; 68ddeb3354SGreg Roachuse function is_string; 69bf80ec58SGreg Roachuse function preg_match_all; 70bf80ec58SGreg Roachuse function redirect; 7169c05a6eSGreg Roachuse function rewind; 72bf80ec58SGreg Roachuse function route; 73e5a6b4d4SGreg Roachuse function str_replace; 74fa695506SGreg Roachuse function stream_get_meta_data; 75fa695506SGreg Roachuse function tmpfile; 76fa695506SGreg Roachuse function uasort; 77d45701ccSGreg Roachuse function view; 78fa695506SGreg Roach 79fa695506SGreg Roachuse const PREG_SET_ORDER; 808c2e8227SGreg Roach 818c2e8227SGreg Roach/** 828c2e8227SGreg Roach * Class ClippingsCartModule 838c2e8227SGreg Roach */ 8437eb8894SGreg Roachclass ClippingsCartModule extends AbstractModule implements ModuleMenuInterface 85c1010edaSGreg Roach{ 8649a243cbSGreg Roach use ModuleMenuTrait; 8749a243cbSGreg Roach 8803f99a78SGreg Roach // What to add to the cart? 8903f99a78SGreg Roach private const ADD_RECORD_ONLY = 'record'; 9003f99a78SGreg Roach private const ADD_CHILDREN = 'children'; 9103f99a78SGreg Roach private const ADD_DESCENDANTS = 'descendants'; 9203f99a78SGreg Roach private const ADD_PARENT_FAMILIES = 'parents'; 9303f99a78SGreg Roach private const ADD_SPOUSE_FAMILIES = 'spouses'; 9403f99a78SGreg Roach private const ADD_ANCESTORS = 'ancestors'; 9503f99a78SGreg Roach private const ADD_ANCESTOR_FAMILIES = 'families'; 9603f99a78SGreg Roach private const ADD_LINKED_INDIVIDUALS = 'linked'; 9703f99a78SGreg Roach 985a78cd34SGreg Roach // Routes that have a record which can be added to the clipboard 9916d6367aSGreg Roach private const ROUTES_WITH_RECORDS = [ 100f95e0480SGreg Roach 'Family' => FamilyPage::class, 101f95e0480SGreg Roach 'Individual' => IndividualPage::class, 102f95e0480SGreg Roach 'Media' => MediaPage::class, 103e8ded2caSGreg Roach 'Location' => LocationPage::class, 104f95e0480SGreg Roach 'Note' => NotePage::class, 105f95e0480SGreg Roach 'Repository' => RepositoryPage::class, 106f95e0480SGreg Roach 'Source' => SourcePage::class, 107d45701ccSGreg Roach 'Submitter' => SubmitterPage::class, 108c1010edaSGreg Roach ]; 1095a78cd34SGreg Roach 11049a243cbSGreg Roach /** @var int The default access level for this module. It can be changed in the control panel. */ 11149a243cbSGreg Roach protected $access_level = Auth::PRIV_USER; 11249a243cbSGreg Roach 11369c05a6eSGreg Roach /** @var GedcomExportService */ 11469c05a6eSGreg Roach private $gedcom_export_service; 11569c05a6eSGreg Roach 11669c05a6eSGreg Roach /** @var UserService */ 117e5a6b4d4SGreg Roach private $user_service; 118e5a6b4d4SGreg Roach 119e5a6b4d4SGreg Roach /** 120e5a6b4d4SGreg Roach * ClippingsCartModule constructor. 121e5a6b4d4SGreg Roach * 12269c05a6eSGreg Roach * @param GedcomExportService $gedcom_export_service 123e5a6b4d4SGreg Roach * @param UserService $user_service 124e5a6b4d4SGreg Roach */ 12569c05a6eSGreg Roach public function __construct(GedcomExportService $gedcom_export_service, UserService $user_service) 126e5a6b4d4SGreg Roach { 12769c05a6eSGreg Roach $this->gedcom_export_service = $gedcom_export_service; 128e5a6b4d4SGreg Roach $this->user_service = $user_service; 129e5a6b4d4SGreg Roach } 130e5a6b4d4SGreg Roach 131e5a6b4d4SGreg Roach /** 132961ec755SGreg Roach * A sentence describing what this module does. 133961ec755SGreg Roach * 134961ec755SGreg Roach * @return string 135961ec755SGreg Roach */ 13649a243cbSGreg Roach public function description(): string 137c1010edaSGreg Roach { 138bbb76c12SGreg Roach /* I18N: Description of the “Clippings cart” module */ 139bbb76c12SGreg Roach return I18N::translate('Select records from your family tree and save them as a GEDCOM file.'); 1408c2e8227SGreg Roach } 1418c2e8227SGreg Roach 1420ee13198SGreg Roach /** 14349a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 1440ee13198SGreg Roach * 1450ee13198SGreg Roach * @return int 1460ee13198SGreg Roach */ 1478f53f488SRico Sonntag public function defaultMenuOrder(): int 148c1010edaSGreg Roach { 149353b36abSGreg Roach return 6; 1508c2e8227SGreg Roach } 1518c2e8227SGreg Roach 1520ee13198SGreg Roach /** 1530ee13198SGreg Roach * A menu, to be added to the main application menu. 1540ee13198SGreg Roach * 155aee13b6dSGreg Roach * @param Tree $tree 156aee13b6dSGreg Roach * 1570ee13198SGreg Roach * @return Menu|null 1580ee13198SGreg Roach */ 15946295629SGreg Roach public function getMenu(Tree $tree): ?Menu 160c1010edaSGreg Roach { 161eb235819SGreg Roach /** @var ServerRequestInterface $request */ 1626ccdf4f0SGreg Roach $request = app(ServerRequestInterface::class); 1638c2e8227SGreg Roach 164f7ab47b1SGreg Roach $route = $request->getAttribute('route'); 165de2aa325SGreg Roach assert($route instanceof Route); 1665a78cd34SGreg Roach 167d45701ccSGreg Roach $cart = Session::get('cart', []); 168d45701ccSGreg Roach $count = count($cart[$tree->name()] ?? []); 169d45701ccSGreg Roach $badge = view('components/badge', ['count' => $count]); 170d45701ccSGreg Roach 1715a78cd34SGreg Roach $submenus = [ 172d45701ccSGreg Roach new Menu($this->title() . ' ' . $badge, route('module', [ 17326684e68SGreg Roach 'module' => $this->name(), 174c1010edaSGreg Roach 'action' => 'Show', 175d72b284aSGreg Roach 'tree' => $tree->name(), 176c1010edaSGreg Roach ]), 'menu-clippings-cart', ['rel' => 'nofollow']), 1775a78cd34SGreg Roach ]; 1785a78cd34SGreg Roach 1792b0d92b4SGreg Roach $action = array_search($route->name, self::ROUTES_WITH_RECORDS, true); 180f95e0480SGreg Roach if ($action !== false) { 1812b0d92b4SGreg Roach $xref = $route->attributes['xref']; 182ddeb3354SGreg Roach assert(is_string($xref)); 183ddeb3354SGreg Roach 184c1010edaSGreg Roach $add_route = route('module', [ 18526684e68SGreg Roach 'module' => $this->name(), 186f95e0480SGreg Roach 'action' => 'Add' . $action, 187c1010edaSGreg Roach 'xref' => $xref, 188d72b284aSGreg Roach 'tree' => $tree->name(), 189c1010edaSGreg Roach ]); 1905a78cd34SGreg Roach 19125b2dde3SGreg Roach $submenus[] = new Menu(I18N::translate('Add to the clippings cart'), $add_route, 'menu-clippings-add', ['rel' => 'nofollow']); 1928c2e8227SGreg Roach } 193cbc1590aSGreg Roach 1945a78cd34SGreg Roach if (!$this->isCartEmpty($tree)) { 195c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Empty the clippings cart'), route('module', [ 19626684e68SGreg Roach 'module' => $this->name(), 197c1010edaSGreg Roach 'action' => 'Empty', 198d72b284aSGreg Roach 'tree' => $tree->name(), 199c1010edaSGreg Roach ]), 'menu-clippings-empty', ['rel' => 'nofollow']); 200f95e0480SGreg Roach 201c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Download'), route('module', [ 20226684e68SGreg Roach 'module' => $this->name(), 203c1010edaSGreg Roach 'action' => 'DownloadForm', 204d72b284aSGreg Roach 'tree' => $tree->name(), 205c1010edaSGreg Roach ]), 'menu-clippings-download', ['rel' => 'nofollow']); 2065a78cd34SGreg Roach } 2075a78cd34SGreg Roach 20849a243cbSGreg Roach return new Menu($this->title(), '#', 'menu-clippings', ['rel' => 'nofollow'], $submenus); 2098c2e8227SGreg Roach } 2108c2e8227SGreg Roach 21176692c8bSGreg Roach /** 212d45701ccSGreg Roach * How should this module be identified in the control panel, etc.? 213d45701ccSGreg Roach * 214d45701ccSGreg Roach * @return string 215d45701ccSGreg Roach */ 216d45701ccSGreg Roach public function title(): string 217d45701ccSGreg Roach { 218d45701ccSGreg Roach /* I18N: Name of a module */ 219d45701ccSGreg Roach return I18N::translate('Clippings cart'); 220d45701ccSGreg Roach } 221d45701ccSGreg Roach 222d45701ccSGreg Roach /** 223d45701ccSGreg Roach * @param Tree $tree 224d45701ccSGreg Roach * 225d45701ccSGreg Roach * @return bool 226d45701ccSGreg Roach */ 227d45701ccSGreg Roach private function isCartEmpty(Tree $tree): bool 228d45701ccSGreg Roach { 229d45701ccSGreg Roach $cart = Session::get('cart', []); 230d45701ccSGreg Roach $contents = $cart[$tree->name()] ?? []; 231d45701ccSGreg Roach 232d45701ccSGreg Roach return $contents === []; 233d45701ccSGreg Roach } 234d45701ccSGreg Roach 235d45701ccSGreg Roach /** 236d45701ccSGreg Roach * @param ServerRequestInterface $request 237d45701ccSGreg Roach * 238d45701ccSGreg Roach * @return ResponseInterface 239d45701ccSGreg Roach */ 240d45701ccSGreg Roach public function getDownloadFormAction(ServerRequestInterface $request): ResponseInterface 241d45701ccSGreg Roach { 242d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 243d45701ccSGreg Roach assert($tree instanceof Tree); 244d45701ccSGreg Roach 245d45701ccSGreg Roach $user = $request->getAttribute('user'); 246d45701ccSGreg Roach $title = I18N::translate('Family tree clippings cart') . ' — ' . I18N::translate('Download'); 247d45701ccSGreg Roach 248d45701ccSGreg Roach return $this->viewResponse('modules/clippings/download', [ 249d45701ccSGreg Roach 'is_manager' => Auth::isManager($tree, $user), 250d45701ccSGreg Roach 'is_member' => Auth::isMember($tree, $user), 251d45701ccSGreg Roach 'module' => $this->name(), 252d45701ccSGreg Roach 'title' => $title, 253d45701ccSGreg Roach 'tree' => $tree, 254d45701ccSGreg Roach ]); 255d45701ccSGreg Roach } 256d45701ccSGreg Roach 257d45701ccSGreg Roach /** 2586ccdf4f0SGreg Roach * @param ServerRequestInterface $request 25976692c8bSGreg Roach * 2606ccdf4f0SGreg Roach * @return ResponseInterface 261f0448b68SGreg Roach * @throws FilesystemException 26276692c8bSGreg Roach */ 263f95e0480SGreg Roach public function postDownloadAction(ServerRequestInterface $request): ResponseInterface 264c1010edaSGreg Roach { 26557ab2231SGreg Roach $tree = $request->getAttribute('tree'); 2664ea62551SGreg Roach assert($tree instanceof Tree); 2674ea62551SGreg Roach 2686b9cb339SGreg Roach $data_filesystem = Registry::filesystem()->data(); 269a04bb9a2SGreg Roach 270b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 271b46c87bdSGreg Roach 272d45701ccSGreg Roach $privatize_export = $params['privatize_export'] ?? 'none'; 273e2ed7c79SGreg Roach 274e2ed7c79SGreg Roach if ($privatize_export === 'none' && !Auth::isManager($tree)) { 275e2ed7c79SGreg Roach $privatize_export = 'member'; 276e2ed7c79SGreg Roach } 277e2ed7c79SGreg Roach 278e2ed7c79SGreg Roach if ($privatize_export === 'gedadmin' && !Auth::isManager($tree)) { 279e2ed7c79SGreg Roach $privatize_export = 'member'; 280e2ed7c79SGreg Roach } 281e2ed7c79SGreg Roach 282e2ed7c79SGreg Roach if ($privatize_export === 'user' && !Auth::isMember($tree)) { 283e2ed7c79SGreg Roach $privatize_export = 'visitor'; 284e2ed7c79SGreg Roach } 285e2ed7c79SGreg Roach 286b46c87bdSGreg Roach $convert = (bool) ($params['convert'] ?? false); 2878c2e8227SGreg Roach 28813abd6f3SGreg Roach $cart = Session::get('cart', []); 2898c2e8227SGreg Roach 290aa6f03bbSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 291c8846facSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 2925a78cd34SGreg Roach 2935a78cd34SGreg Roach // Create a new/empty .ZIP file 294a00baf47SGreg Roach $temp_zip_file = stream_get_meta_data(tmpfile())['uri']; 295f32d77e6SGreg Roach $zip_provider = new FilesystemZipArchiveProvider($temp_zip_file, 0755); 296f32d77e6SGreg Roach $zip_adapter = new ZipArchiveAdapter($zip_provider); 2977f996f6eSGreg Roach $zip_filesystem = new Filesystem($zip_adapter); 2985a78cd34SGreg Roach 299fa695506SGreg Roach $media_filesystem = $tree->mediaFilesystem($data_filesystem); 30061bf91b2SGreg Roach 3015a78cd34SGreg Roach // Media file prefix 3025a78cd34SGreg Roach $path = $tree->getPreference('MEDIA_DIRECTORY'); 3035a78cd34SGreg Roach 30469c05a6eSGreg Roach $encoding = $convert ? 'ANSI' : 'UTF-8'; 30569c05a6eSGreg Roach 30669c05a6eSGreg Roach $records = new Collection(); 3075a78cd34SGreg Roach 3085a78cd34SGreg Roach switch ($privatize_export) { 3095a78cd34SGreg Roach case 'gedadmin': 3105a78cd34SGreg Roach $access_level = Auth::PRIV_NONE; 3115a78cd34SGreg Roach break; 3125a78cd34SGreg Roach case 'user': 3135a78cd34SGreg Roach $access_level = Auth::PRIV_USER; 3145a78cd34SGreg Roach break; 3155a78cd34SGreg Roach case 'visitor': 3165a78cd34SGreg Roach $access_level = Auth::PRIV_PRIVATE; 3175a78cd34SGreg Roach break; 3185a78cd34SGreg Roach case 'none': 3195a78cd34SGreg Roach default: 3205a78cd34SGreg Roach $access_level = Auth::PRIV_HIDE; 3215a78cd34SGreg Roach break; 3225a78cd34SGreg Roach } 3235a78cd34SGreg Roach 3245a78cd34SGreg Roach foreach ($xrefs as $xref) { 3256b9cb339SGreg Roach $object = Registry::gedcomRecordFactory()->make($xref, $tree); 3265a78cd34SGreg Roach // The object may have been deleted since we added it to the cart.... 327bed27cedSGreg Roach if ($object instanceof GedcomRecord) { 3285a78cd34SGreg Roach $record = $object->privatizeGedcom($access_level); 3295a78cd34SGreg Roach // Remove links to objects that aren't in the cart 3308d0ebef0SGreg Roach preg_match_all('/\n1 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[2-9].*)*/', $record, $matches, PREG_SET_ORDER); 3315a78cd34SGreg Roach foreach ($matches as $match) { 332bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3335a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3345a78cd34SGreg Roach } 3355a78cd34SGreg Roach } 3368d0ebef0SGreg Roach preg_match_all('/\n2 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[3-9].*)*/', $record, $matches, PREG_SET_ORDER); 3375a78cd34SGreg Roach foreach ($matches as $match) { 338bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3395a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3405a78cd34SGreg Roach } 3415a78cd34SGreg Roach } 3428d0ebef0SGreg Roach preg_match_all('/\n3 ' . Gedcom::REGEX_TAG . ' @(' . Gedcom::REGEX_XREF . ')@(\n[4-9].*)*/', $record, $matches, PREG_SET_ORDER); 3435a78cd34SGreg Roach foreach ($matches as $match) { 344bf80ec58SGreg Roach if (!in_array($match[1], $xrefs, true)) { 3455a78cd34SGreg Roach $record = str_replace($match[0], '', $record); 3465a78cd34SGreg Roach } 3475a78cd34SGreg Roach } 3485a78cd34SGreg Roach 34955167344SGreg Roach if ($object instanceof Individual || $object instanceof Family) { 35069c05a6eSGreg Roach $records->add($record . "\n1 SOUR @WEBTREES@\n2 PAGE " . $object->url()); 35155167344SGreg Roach } elseif ($object instanceof Source) { 35269c05a6eSGreg Roach $records->add($record . "\n1 NOTE " . $object->url()); 35355167344SGreg Roach } elseif ($object instanceof Media) { 35455167344SGreg Roach // Add the media files to the archive 3555a78cd34SGreg Roach foreach ($object->mediaFiles() as $media_file) { 356fa695506SGreg Roach $from = $media_file->filename(); 357fa695506SGreg Roach $to = $path . $media_file->filename(); 358f0448b68SGreg Roach if (!$media_file->isExternal() && $media_filesystem->fileExists($from)) { 359fa695506SGreg Roach $zip_filesystem->writeStream($to, $media_filesystem->readStream($from)); 3605a78cd34SGreg Roach } 3615a78cd34SGreg Roach } 36269c05a6eSGreg Roach $records->add($record); 36355167344SGreg Roach } else { 36469c05a6eSGreg Roach $records->add($record); 3658c2e8227SGreg Roach } 3668c2e8227SGreg Roach } 3678c2e8227SGreg Roach } 3688c2e8227SGreg Roach 3699b93b7c3SGreg Roach $base_url = $request->getAttribute('base_url'); 3709b93b7c3SGreg Roach 3715a78cd34SGreg Roach // Create a source, to indicate the source of the data. 37269c05a6eSGreg Roach $record = "0 @WEBTREES@ SOUR\n1 TITL " . $base_url; 373e5a6b4d4SGreg Roach $author = $this->user_service->find((int) $tree->getPreference('CONTACT_USER_ID')); 3745a78cd34SGreg Roach if ($author !== null) { 37569c05a6eSGreg Roach $record .= "\n1 AUTH " . $author->realName(); 3765a78cd34SGreg Roach } 37769c05a6eSGreg Roach $records->add($record); 3785a78cd34SGreg Roach 37969c05a6eSGreg Roach $stream = fopen('php://temp', 'wb+'); 3805a78cd34SGreg Roach 38169c05a6eSGreg Roach if ($stream === false) { 38269c05a6eSGreg Roach throw new RuntimeException('Failed to create temporary stream'); 3838c2e8227SGreg Roach } 384cbc1590aSGreg Roach 38569c05a6eSGreg Roach // We have already applied privacy filtering, so do not do it again. 38669c05a6eSGreg Roach $this->gedcom_export_service->export($tree, $stream, false, $encoding, Auth::PRIV_HIDE, $path, $records); 38769c05a6eSGreg Roach rewind($stream); 38869c05a6eSGreg Roach 3895a78cd34SGreg Roach // Finally add the GEDCOM file to the .ZIP file. 39069c05a6eSGreg Roach $zip_filesystem->writeStream('clippings.ged', $stream); 3915a78cd34SGreg Roach 3926ccdf4f0SGreg Roach // Use a stream, so that we do not have to load the entire file into memory. 393*00c45d23SGreg Roach $stream = app(StreamFactoryInterface::class)->createStreamFromFile($temp_zip_file); 3945a78cd34SGreg Roach 395*00c45d23SGreg Roach /** @var ResponseFactoryInterface $response_factory */ 396*00c45d23SGreg Roach $response_factory = app(ResponseFactoryInterface::class); 397*00c45d23SGreg Roach 398*00c45d23SGreg Roach return $response_factory->createResponse() 3996ccdf4f0SGreg Roach ->withBody($stream) 4001b3d4731SGreg Roach ->withHeader('Content-Type', 'application/zip') 401bed27cedSGreg Roach ->withHeader('Content-Disposition', 'attachment; filename="clippings.zip'); 4028c2e8227SGreg Roach } 4038c2e8227SGreg Roach 4048c2e8227SGreg Roach /** 40557ab2231SGreg Roach * @param ServerRequestInterface $request 40676692c8bSGreg Roach * 4076ccdf4f0SGreg Roach * @return ResponseInterface 4088c2e8227SGreg Roach */ 40957ab2231SGreg Roach public function getEmptyAction(ServerRequestInterface $request): ResponseInterface 410c1010edaSGreg Roach { 41157ab2231SGreg Roach $tree = $request->getAttribute('tree'); 4124ea62551SGreg Roach assert($tree instanceof Tree); 4134ea62551SGreg Roach 4145a78cd34SGreg Roach $cart = Session::get('cart', []); 415aa6f03bbSGreg Roach $cart[$tree->name()] = []; 4165a78cd34SGreg Roach Session::put('cart', $cart); 4178c2e8227SGreg Roach 418c1010edaSGreg Roach $url = route('module', [ 41926684e68SGreg Roach 'module' => $this->name(), 420c1010edaSGreg Roach 'action' => 'Show', 421d72b284aSGreg Roach 'tree' => $tree->name(), 422c1010edaSGreg Roach ]); 4235a78cd34SGreg Roach 4246ccdf4f0SGreg Roach return redirect($url); 4255a78cd34SGreg Roach } 4265a78cd34SGreg Roach 4275a78cd34SGreg Roach /** 4286ccdf4f0SGreg Roach * @param ServerRequestInterface $request 4295a78cd34SGreg Roach * 4306ccdf4f0SGreg Roach * @return ResponseInterface 4315a78cd34SGreg Roach */ 43257ab2231SGreg Roach public function postRemoveAction(ServerRequestInterface $request): ResponseInterface 433c1010edaSGreg Roach { 43457ab2231SGreg Roach $tree = $request->getAttribute('tree'); 43575964c75SGreg Roach assert($tree instanceof Tree); 4365229eadeSGreg Roach 437d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 4385a78cd34SGreg Roach 4395a78cd34SGreg Roach $cart = Session::get('cart', []); 440aa6f03bbSGreg Roach unset($cart[$tree->name()][$xref]); 4415a78cd34SGreg Roach Session::put('cart', $cart); 4425a78cd34SGreg Roach 443c1010edaSGreg Roach $url = route('module', [ 44426684e68SGreg Roach 'module' => $this->name(), 445c1010edaSGreg Roach 'action' => 'Show', 446d72b284aSGreg Roach 'tree' => $tree->name(), 447c1010edaSGreg Roach ]); 4485a78cd34SGreg Roach 4496ccdf4f0SGreg Roach return redirect($url); 4505a78cd34SGreg Roach } 4515a78cd34SGreg Roach 4525a78cd34SGreg Roach /** 45357ab2231SGreg Roach * @param ServerRequestInterface $request 4545a78cd34SGreg Roach * 4556ccdf4f0SGreg Roach * @return ResponseInterface 4565a78cd34SGreg Roach */ 45757ab2231SGreg Roach public function getShowAction(ServerRequestInterface $request): ResponseInterface 458c1010edaSGreg Roach { 45957ab2231SGreg Roach $tree = $request->getAttribute('tree'); 46075964c75SGreg Roach assert($tree instanceof Tree); 46157ab2231SGreg Roach 4625a78cd34SGreg Roach return $this->viewResponse('modules/clippings/show', [ 46377b78a63SRichard Cissée 'module' => $this->name(), 4645a78cd34SGreg Roach 'records' => $this->allRecordsInCart($tree), 4655a78cd34SGreg Roach 'title' => I18N::translate('Family tree clippings cart'), 4665a78cd34SGreg Roach 'tree' => $tree, 4675a78cd34SGreg Roach ]); 4685a78cd34SGreg Roach } 4695a78cd34SGreg Roach 4705a78cd34SGreg Roach /** 471d45701ccSGreg Roach * Get all the records in the cart. 472d45701ccSGreg Roach * 473d45701ccSGreg Roach * @param Tree $tree 474d45701ccSGreg Roach * 475d45701ccSGreg Roach * @return GedcomRecord[] 476d45701ccSGreg Roach */ 477d45701ccSGreg Roach private function allRecordsInCart(Tree $tree): array 478d45701ccSGreg Roach { 479d45701ccSGreg Roach $cart = Session::get('cart', []); 480d45701ccSGreg Roach 481d45701ccSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 482d45701ccSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 483d45701ccSGreg Roach 484d45701ccSGreg Roach // Fetch all the records in the cart. 485d45701ccSGreg Roach $records = array_map(static function (string $xref) use ($tree): ?GedcomRecord { 486d45701ccSGreg Roach return Registry::gedcomRecordFactory()->make($xref, $tree); 487d45701ccSGreg Roach }, $xrefs); 488d45701ccSGreg Roach 489d45701ccSGreg Roach // Some records may have been deleted after they were added to the cart. 490d45701ccSGreg Roach $records = array_filter($records); 491d45701ccSGreg Roach 492d45701ccSGreg Roach // Group and sort. 493d45701ccSGreg Roach uasort($records, static function (GedcomRecord $x, GedcomRecord $y): int { 494d45701ccSGreg Roach return $x->tag() <=> $y->tag() ?: GedcomRecord::nameComparator()($x, $y); 495d45701ccSGreg Roach }); 496d45701ccSGreg Roach 497d45701ccSGreg Roach return $records; 498d45701ccSGreg Roach } 499d45701ccSGreg Roach 500d45701ccSGreg Roach /** 5016ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5025a78cd34SGreg Roach * 5036ccdf4f0SGreg Roach * @return ResponseInterface 5045a78cd34SGreg Roach */ 50557ab2231SGreg Roach public function getAddFamilyAction(ServerRequestInterface $request): ResponseInterface 506c1010edaSGreg Roach { 50757ab2231SGreg Roach $tree = $request->getAttribute('tree'); 50875964c75SGreg Roach assert($tree instanceof Tree); 5095229eadeSGreg Roach 510d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 5115a78cd34SGreg Roach 5126b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 513d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 514d45701ccSGreg Roach $name = $family->fullName(); 5155a78cd34SGreg Roach 516d45701ccSGreg Roach $options = [ 51703f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 518bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 51903f99a78SGreg Roach self::ADD_CHILDREN => I18N::translate('%s and their children', $name), 520bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 52103f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s and their descendants', $name), 5225a78cd34SGreg Roach ]; 523d45701ccSGreg Roach 524d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 525d45701ccSGreg Roach 526d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 527d45701ccSGreg Roach 'options' => $options, 528d45701ccSGreg Roach 'record' => $family, 529d45701ccSGreg Roach 'title' => $title, 530d45701ccSGreg Roach 'tree' => $tree, 531d45701ccSGreg Roach ]); 5325a78cd34SGreg Roach } 5335a78cd34SGreg Roach 5345a78cd34SGreg Roach /** 5356ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5365a78cd34SGreg Roach * 5376ccdf4f0SGreg Roach * @return ResponseInterface 5385a78cd34SGreg Roach */ 53957ab2231SGreg Roach public function postAddFamilyAction(ServerRequestInterface $request): ResponseInterface 540c1010edaSGreg Roach { 54157ab2231SGreg Roach $tree = $request->getAttribute('tree'); 5424ea62551SGreg Roach assert($tree instanceof Tree); 5434ea62551SGreg Roach 544b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 545b46c87bdSGreg Roach 546d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 547d45701ccSGreg Roach $option = $params['option'] ?? ''; 5485a78cd34SGreg Roach 5496b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 550d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 5515a78cd34SGreg Roach 5525a78cd34SGreg Roach switch ($option) { 55303f99a78SGreg Roach case self::ADD_RECORD_ONLY: 5545a78cd34SGreg Roach $this->addFamilyToCart($family); 5555a78cd34SGreg Roach break; 5565a78cd34SGreg Roach 55703f99a78SGreg Roach case self::ADD_CHILDREN: 5585a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 5595a78cd34SGreg Roach break; 5605a78cd34SGreg Roach 56103f99a78SGreg Roach case self::ADD_DESCENDANTS: 5625a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 5635a78cd34SGreg Roach break; 5645a78cd34SGreg Roach } 5655a78cd34SGreg Roach 5666ccdf4f0SGreg Roach return redirect($family->url()); 5675a78cd34SGreg Roach } 5685a78cd34SGreg Roach 5695a78cd34SGreg Roach 5705a78cd34SGreg Roach /** 5715a78cd34SGreg Roach * @param Family $family 57218d7a90dSGreg Roach * 57318d7a90dSGreg Roach * @return void 5745a78cd34SGreg Roach */ 575d45701ccSGreg Roach protected function addFamilyAndChildrenToCart(Family $family): void 576c1010edaSGreg Roach { 577d45701ccSGreg Roach $this->addFamilyToCart($family); 5785a78cd34SGreg Roach 57939ca88baSGreg Roach foreach ($family->children() as $child) { 580d45701ccSGreg Roach $this->addIndividualToCart($child); 5815a78cd34SGreg Roach } 5825a78cd34SGreg Roach } 5835a78cd34SGreg Roach 5845a78cd34SGreg Roach /** 5855a78cd34SGreg Roach * @param Family $family 58618d7a90dSGreg Roach * 58718d7a90dSGreg Roach * @return void 5885a78cd34SGreg Roach */ 589d45701ccSGreg Roach protected function addFamilyAndDescendantsToCart(Family $family): void 590c1010edaSGreg Roach { 591d45701ccSGreg Roach $this->addFamilyAndChildrenToCart($family); 5925a78cd34SGreg Roach 59339ca88baSGreg Roach foreach ($family->children() as $child) { 59439ca88baSGreg Roach foreach ($child->spouseFamilies() as $child_family) { 5955a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($child_family); 5965a78cd34SGreg Roach } 5975a78cd34SGreg Roach } 5985a78cd34SGreg Roach } 5995a78cd34SGreg Roach 6005a78cd34SGreg Roach /** 6016ccdf4f0SGreg Roach * @param ServerRequestInterface $request 6025a78cd34SGreg Roach * 6036ccdf4f0SGreg Roach * @return ResponseInterface 6045a78cd34SGreg Roach */ 60557ab2231SGreg Roach public function getAddIndividualAction(ServerRequestInterface $request): ResponseInterface 606c1010edaSGreg Roach { 60757ab2231SGreg Roach $tree = $request->getAttribute('tree'); 60875964c75SGreg Roach assert($tree instanceof Tree); 6095229eadeSGreg Roach 610d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 6115a78cd34SGreg Roach 6126b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 613d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 614d45701ccSGreg Roach $name = $individual->fullName(); 6155a78cd34SGreg Roach 61639ca88baSGreg Roach if ($individual->sex() === 'F') { 617d45701ccSGreg Roach $options = [ 61803f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 61903f99a78SGreg Roach self::ADD_PARENT_FAMILIES => I18N::translate('%s, her parents and siblings', $name), 62003f99a78SGreg Roach self::ADD_SPOUSE_FAMILIES => I18N::translate('%s, her spouses and children', $name), 62103f99a78SGreg Roach self::ADD_ANCESTORS => I18N::translate('%s and her ancestors', $name), 62203f99a78SGreg Roach self::ADD_ANCESTOR_FAMILIES => I18N::translate('%s, her ancestors and their families', $name), 62303f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s, her spouses and descendants', $name), 6245a78cd34SGreg Roach ]; 625d45701ccSGreg Roach } else { 626d45701ccSGreg Roach $options = [ 62703f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 62803f99a78SGreg Roach self::ADD_PARENT_FAMILIES => I18N::translate('%s, his parents and siblings', $name), 62903f99a78SGreg Roach self::ADD_SPOUSE_FAMILIES => I18N::translate('%s, his spouses and children', $name), 63003f99a78SGreg Roach self::ADD_ANCESTORS => I18N::translate('%s and his ancestors', $name), 63103f99a78SGreg Roach self::ADD_ANCESTOR_FAMILIES => I18N::translate('%s, his ancestors and their families', $name), 63203f99a78SGreg Roach self::ADD_DESCENDANTS => I18N::translate('%s, his spouses and descendants', $name), 6335a78cd34SGreg Roach ]; 6345a78cd34SGreg Roach } 6355a78cd34SGreg Roach 636d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 637d45701ccSGreg Roach 638d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 639d45701ccSGreg Roach 'options' => $options, 640d45701ccSGreg Roach 'record' => $individual, 641d45701ccSGreg Roach 'title' => $title, 642d45701ccSGreg Roach 'tree' => $tree, 643d45701ccSGreg Roach ]); 644d45701ccSGreg Roach } 645d45701ccSGreg Roach 6465a78cd34SGreg Roach /** 6476ccdf4f0SGreg Roach * @param ServerRequestInterface $request 6485a78cd34SGreg Roach * 6496ccdf4f0SGreg Roach * @return ResponseInterface 6505a78cd34SGreg Roach */ 65157ab2231SGreg Roach public function postAddIndividualAction(ServerRequestInterface $request): ResponseInterface 652c1010edaSGreg Roach { 65357ab2231SGreg Roach $tree = $request->getAttribute('tree'); 6544ea62551SGreg Roach assert($tree instanceof Tree); 6554ea62551SGreg Roach 656b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 657b46c87bdSGreg Roach 658d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 659d45701ccSGreg Roach $option = $params['option'] ?? ''; 6605a78cd34SGreg Roach 6616b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 662d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 6635a78cd34SGreg Roach 6645a78cd34SGreg Roach switch ($option) { 66503f99a78SGreg Roach case self::ADD_RECORD_ONLY: 666d45701ccSGreg Roach $this->addIndividualToCart($individual); 6675a78cd34SGreg Roach break; 6685a78cd34SGreg Roach 66903f99a78SGreg Roach case self::ADD_PARENT_FAMILIES: 67039ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 6715a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6725a78cd34SGreg Roach } 6735a78cd34SGreg Roach break; 6745a78cd34SGreg Roach 67503f99a78SGreg Roach case self::ADD_SPOUSE_FAMILIES: 67639ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 6775a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6785a78cd34SGreg Roach } 6795a78cd34SGreg Roach break; 6805a78cd34SGreg Roach 68103f99a78SGreg Roach case self::ADD_ANCESTORS: 6825a78cd34SGreg Roach $this->addAncestorsToCart($individual); 6835a78cd34SGreg Roach break; 6845a78cd34SGreg Roach 68503f99a78SGreg Roach case self::ADD_ANCESTOR_FAMILIES: 6865a78cd34SGreg Roach $this->addAncestorFamiliesToCart($individual); 6875a78cd34SGreg Roach break; 6885a78cd34SGreg Roach 68903f99a78SGreg Roach case self::ADD_DESCENDANTS: 69039ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 6915a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 6925a78cd34SGreg Roach } 6935a78cd34SGreg Roach break; 6945a78cd34SGreg Roach } 6955a78cd34SGreg Roach 6966ccdf4f0SGreg Roach return redirect($individual->url()); 6975a78cd34SGreg Roach } 6985a78cd34SGreg Roach 6995a78cd34SGreg Roach /** 7005a78cd34SGreg Roach * @param Individual $individual 70118d7a90dSGreg Roach * 70218d7a90dSGreg Roach * @return void 7035a78cd34SGreg Roach */ 704d45701ccSGreg Roach protected function addAncestorsToCart(Individual $individual): void 705c1010edaSGreg Roach { 706d45701ccSGreg Roach $this->addIndividualToCart($individual); 7075a78cd34SGreg Roach 70839ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 709d45701ccSGreg Roach $this->addFamilyToCart($family); 7108df4c68dSGreg Roach 71139ca88baSGreg Roach foreach ($family->spouses() as $parent) { 7125a78cd34SGreg Roach $this->addAncestorsToCart($parent); 7135a78cd34SGreg Roach } 7145a78cd34SGreg Roach } 7155a78cd34SGreg Roach } 7165a78cd34SGreg Roach 7175a78cd34SGreg Roach /** 7185a78cd34SGreg Roach * @param Individual $individual 71918d7a90dSGreg Roach * 72018d7a90dSGreg Roach * @return void 7215a78cd34SGreg Roach */ 722d45701ccSGreg Roach protected function addAncestorFamiliesToCart(Individual $individual): void 723c1010edaSGreg Roach { 72439ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 7255a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 7268df4c68dSGreg Roach 72739ca88baSGreg Roach foreach ($family->spouses() as $parent) { 728cad6d3f3SGreg Roach $this->addAncestorFamiliesToCart($parent); 7295a78cd34SGreg Roach } 7305a78cd34SGreg Roach } 7315a78cd34SGreg Roach } 7325a78cd34SGreg Roach 7335a78cd34SGreg Roach /** 7346ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7355a78cd34SGreg Roach * 7366ccdf4f0SGreg Roach * @return ResponseInterface 7375a78cd34SGreg Roach */ 738e8ded2caSGreg Roach public function getAddLocationAction(ServerRequestInterface $request): ResponseInterface 739e8ded2caSGreg Roach { 740e8ded2caSGreg Roach $tree = $request->getAttribute('tree'); 741e8ded2caSGreg Roach assert($tree instanceof Tree); 742e8ded2caSGreg Roach 743e8ded2caSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 744e8ded2caSGreg Roach 745e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $tree); 746e8ded2caSGreg Roach $location = Auth::checkLocationAccess($location); 747e8ded2caSGreg Roach $name = $location->fullName(); 748e8ded2caSGreg Roach 749e8ded2caSGreg Roach $options = [ 75003f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 751e8ded2caSGreg Roach ]; 752e8ded2caSGreg Roach 753e8ded2caSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 754e8ded2caSGreg Roach 755e8ded2caSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 756e8ded2caSGreg Roach 'options' => $options, 757e8ded2caSGreg Roach 'record' => $location, 758e8ded2caSGreg Roach 'title' => $title, 759e8ded2caSGreg Roach 'tree' => $tree, 760e8ded2caSGreg Roach ]); 761e8ded2caSGreg Roach } 762e8ded2caSGreg Roach 763e8ded2caSGreg Roach /** 764e8ded2caSGreg Roach * @param ServerRequestInterface $request 765e8ded2caSGreg Roach * 766e8ded2caSGreg Roach * @return ResponseInterface 767e8ded2caSGreg Roach */ 768e8ded2caSGreg Roach public function postAddLocationAction(ServerRequestInterface $request): ResponseInterface 769e8ded2caSGreg Roach { 770e8ded2caSGreg Roach $tree = $request->getAttribute('tree'); 771e8ded2caSGreg Roach assert($tree instanceof Tree); 772e8ded2caSGreg Roach 773e8ded2caSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 774e8ded2caSGreg Roach 775e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $tree); 776e8ded2caSGreg Roach $location = Auth::checkLocationAccess($location); 777e8ded2caSGreg Roach 778e8ded2caSGreg Roach $this->addLocationToCart($location); 779e8ded2caSGreg Roach 780e8ded2caSGreg Roach return redirect($location->url()); 781e8ded2caSGreg Roach } 782e8ded2caSGreg Roach 783e8ded2caSGreg Roach /** 784e8ded2caSGreg Roach * @param ServerRequestInterface $request 785e8ded2caSGreg Roach * 786e8ded2caSGreg Roach * @return ResponseInterface 787e8ded2caSGreg Roach */ 78857ab2231SGreg Roach public function getAddMediaAction(ServerRequestInterface $request): ResponseInterface 789c1010edaSGreg Roach { 79057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 79175964c75SGreg Roach assert($tree instanceof Tree); 7925229eadeSGreg Roach 793d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 7945a78cd34SGreg Roach 7956b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 796d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 797d45701ccSGreg Roach $name = $media->fullName(); 7985a78cd34SGreg Roach 799d45701ccSGreg Roach $options = [ 80003f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 801d45701ccSGreg Roach ]; 8025a78cd34SGreg Roach 803d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 8045a78cd34SGreg Roach 8055a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 8065a78cd34SGreg Roach 'options' => $options, 8075a78cd34SGreg Roach 'record' => $media, 8085a78cd34SGreg Roach 'title' => $title, 8095a78cd34SGreg Roach 'tree' => $tree, 8105a78cd34SGreg Roach ]); 8115a78cd34SGreg Roach } 8125a78cd34SGreg Roach 8135a78cd34SGreg Roach /** 8146ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8155a78cd34SGreg Roach * 8166ccdf4f0SGreg Roach * @return ResponseInterface 8175a78cd34SGreg Roach */ 81857ab2231SGreg Roach public function postAddMediaAction(ServerRequestInterface $request): ResponseInterface 819c1010edaSGreg Roach { 82057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 82175964c75SGreg Roach assert($tree instanceof Tree); 8225229eadeSGreg Roach 823d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8245a78cd34SGreg Roach 8256b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 826d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 8275a78cd34SGreg Roach 828d45701ccSGreg Roach $this->addMediaToCart($media); 8295a78cd34SGreg Roach 8306ccdf4f0SGreg Roach return redirect($media->url()); 8315a78cd34SGreg Roach } 8325a78cd34SGreg Roach 8335a78cd34SGreg Roach /** 8346ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8355a78cd34SGreg Roach * 8366ccdf4f0SGreg Roach * @return ResponseInterface 8375a78cd34SGreg Roach */ 83857ab2231SGreg Roach public function getAddNoteAction(ServerRequestInterface $request): ResponseInterface 839c1010edaSGreg Roach { 84057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 84175964c75SGreg Roach assert($tree instanceof Tree); 8425229eadeSGreg Roach 843d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8445a78cd34SGreg Roach 8456b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 846d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 847d45701ccSGreg Roach $name = $note->fullName(); 8485a78cd34SGreg Roach 849d45701ccSGreg Roach $options = [ 85003f99a78SGreg Roach self::ADD_RECORD_ONLY => $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' => $note, 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 postAddNoteAction(ServerRequestInterface $request): ResponseInterface 869c1010edaSGreg Roach { 87057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 87175964c75SGreg Roach assert($tree instanceof Tree); 8725229eadeSGreg Roach 873d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8745a78cd34SGreg Roach 8756b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 876d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 8775a78cd34SGreg Roach 878d45701ccSGreg Roach $this->addNoteToCart($note); 8795a78cd34SGreg Roach 8806ccdf4f0SGreg Roach return redirect($note->url()); 8815a78cd34SGreg Roach } 8825a78cd34SGreg Roach 8835a78cd34SGreg Roach /** 8846ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8855a78cd34SGreg Roach * 8866ccdf4f0SGreg Roach * @return ResponseInterface 8875a78cd34SGreg Roach */ 88857ab2231SGreg Roach public function getAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 889c1010edaSGreg Roach { 89057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 89175964c75SGreg Roach assert($tree instanceof Tree); 8925229eadeSGreg Roach 893d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8945a78cd34SGreg Roach 8956b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 896d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 897d45701ccSGreg Roach $name = $repository->fullName(); 8985a78cd34SGreg Roach 899d45701ccSGreg Roach $options = [ 90003f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 901d45701ccSGreg Roach ]; 9025a78cd34SGreg Roach 903d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 9045a78cd34SGreg Roach 9055a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 9065a78cd34SGreg Roach 'options' => $options, 9075a78cd34SGreg Roach 'record' => $repository, 9085a78cd34SGreg Roach 'title' => $title, 9095a78cd34SGreg Roach 'tree' => $tree, 9105a78cd34SGreg Roach ]); 9115a78cd34SGreg Roach } 9125a78cd34SGreg Roach 9135a78cd34SGreg Roach /** 9146ccdf4f0SGreg Roach * @param ServerRequestInterface $request 9155a78cd34SGreg Roach * 9166ccdf4f0SGreg Roach * @return ResponseInterface 9175a78cd34SGreg Roach */ 91857ab2231SGreg Roach public function postAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 919c1010edaSGreg Roach { 92057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 92175964c75SGreg Roach assert($tree instanceof Tree); 9225229eadeSGreg Roach 923d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 9245a78cd34SGreg Roach 9256b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 926d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 9275a78cd34SGreg Roach 928d45701ccSGreg Roach $this->addRepositoryToCart($repository); 929d45701ccSGreg Roach 930d45701ccSGreg Roach foreach ($repository->linkedSources('REPO') as $source) { 931d45701ccSGreg Roach $this->addSourceToCart($source); 9325a78cd34SGreg Roach } 9335a78cd34SGreg Roach 9346ccdf4f0SGreg Roach return redirect($repository->url()); 9355a78cd34SGreg Roach } 9365a78cd34SGreg Roach 9375a78cd34SGreg Roach /** 9386ccdf4f0SGreg Roach * @param ServerRequestInterface $request 9395a78cd34SGreg Roach * 9406ccdf4f0SGreg Roach * @return ResponseInterface 9415a78cd34SGreg Roach */ 94257ab2231SGreg Roach public function getAddSourceAction(ServerRequestInterface $request): ResponseInterface 943c1010edaSGreg Roach { 94457ab2231SGreg Roach $tree = $request->getAttribute('tree'); 94575964c75SGreg Roach assert($tree instanceof Tree); 9465229eadeSGreg Roach 947d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 9485a78cd34SGreg Roach 9496b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 950d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 951d45701ccSGreg Roach $name = $source->fullName(); 9525a78cd34SGreg Roach 953d45701ccSGreg Roach $options = [ 95403f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 95503f99a78SGreg Roach self::ADD_LINKED_INDIVIDUALS => I18N::translate('%s and the individuals that reference it.', $name), 956d45701ccSGreg Roach ]; 9575a78cd34SGreg Roach 958d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 9595a78cd34SGreg Roach 9605a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 9615a78cd34SGreg Roach 'options' => $options, 9625a78cd34SGreg Roach 'record' => $source, 9635a78cd34SGreg Roach 'title' => $title, 9645a78cd34SGreg Roach 'tree' => $tree, 9655a78cd34SGreg Roach ]); 9665a78cd34SGreg Roach } 9675a78cd34SGreg Roach 9685a78cd34SGreg Roach /** 9696ccdf4f0SGreg Roach * @param ServerRequestInterface $request 9705a78cd34SGreg Roach * 9716ccdf4f0SGreg Roach * @return ResponseInterface 9725a78cd34SGreg Roach */ 97357ab2231SGreg Roach public function postAddSourceAction(ServerRequestInterface $request): ResponseInterface 974c1010edaSGreg Roach { 97557ab2231SGreg Roach $tree = $request->getAttribute('tree'); 97675964c75SGreg Roach assert($tree instanceof Tree); 9775229eadeSGreg Roach 978b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 979b46c87bdSGreg Roach 980d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 981d45701ccSGreg Roach $option = $params['option'] ?? ''; 9825a78cd34SGreg Roach 9836b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 984d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 9855a78cd34SGreg Roach 986d45701ccSGreg Roach $this->addSourceToCart($source); 9875a78cd34SGreg Roach 98803f99a78SGreg Roach if ($option === self::ADD_LINKED_INDIVIDUALS) { 9895a78cd34SGreg Roach foreach ($source->linkedIndividuals('SOUR') as $individual) { 990d45701ccSGreg Roach $this->addIndividualToCart($individual); 9915a78cd34SGreg Roach } 9925a78cd34SGreg Roach foreach ($source->linkedFamilies('SOUR') as $family) { 993d45701ccSGreg Roach $this->addFamilyToCart($family); 9945a78cd34SGreg Roach } 9955a78cd34SGreg Roach } 9965a78cd34SGreg Roach 9976ccdf4f0SGreg Roach return redirect($source->url()); 9985a78cd34SGreg Roach } 9995a78cd34SGreg Roach 10005a78cd34SGreg Roach /** 1001d45701ccSGreg Roach * @param ServerRequestInterface $request 10025a78cd34SGreg Roach * 1003d45701ccSGreg Roach * @return ResponseInterface 10045a78cd34SGreg Roach */ 1005d45701ccSGreg Roach public function getAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 1006c1010edaSGreg Roach { 1007d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 1008d45701ccSGreg Roach assert($tree instanceof Tree); 10095a78cd34SGreg Roach 1010d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 10115a78cd34SGreg Roach 1012d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 1013d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 1014d45701ccSGreg Roach $name = $submitter->fullName(); 10155a78cd34SGreg Roach 1016d45701ccSGreg Roach $options = [ 101703f99a78SGreg Roach self::ADD_RECORD_ONLY => $name, 1018d45701ccSGreg Roach ]; 10195a78cd34SGreg Roach 1020d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 10215a78cd34SGreg Roach 1022d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 1023d45701ccSGreg Roach 'options' => $options, 1024d45701ccSGreg Roach 'record' => $submitter, 1025d45701ccSGreg Roach 'title' => $title, 1026d45701ccSGreg Roach 'tree' => $tree, 1027d45701ccSGreg Roach ]); 10285a78cd34SGreg Roach } 10295a78cd34SGreg Roach 10305a78cd34SGreg Roach /** 1031d45701ccSGreg Roach * @param ServerRequestInterface $request 10325a78cd34SGreg Roach * 1033d45701ccSGreg Roach * @return ResponseInterface 10345a78cd34SGreg Roach */ 1035d45701ccSGreg Roach public function postAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 1036d45701ccSGreg Roach { 1037d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 1038d45701ccSGreg Roach assert($tree instanceof Tree); 1039d45701ccSGreg Roach 1040d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 1041d45701ccSGreg Roach 1042d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 1043d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 1044d45701ccSGreg Roach 1045d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 1046d45701ccSGreg Roach 1047d45701ccSGreg Roach return redirect($submitter->url()); 1048d45701ccSGreg Roach } 1049d45701ccSGreg Roach 1050d45701ccSGreg Roach /** 1051d45701ccSGreg Roach * @param Family $family 1052d45701ccSGreg Roach */ 1053d45701ccSGreg Roach protected function addFamilyToCart(Family $family): void 1054c1010edaSGreg Roach { 10555a78cd34SGreg Roach $cart = Session::get('cart', []); 1056d45701ccSGreg Roach $tree = $family->tree()->name(); 1057d45701ccSGreg Roach $xref = $family->xref(); 10585a78cd34SGreg Roach 1059d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1060d45701ccSGreg Roach $cart[$tree][$xref] = true; 10615a78cd34SGreg Roach 1062d45701ccSGreg Roach Session::put('cart', $cart); 10635a78cd34SGreg Roach 1064d45701ccSGreg Roach foreach ($family->spouses() as $spouse) { 1065d45701ccSGreg Roach $this->addIndividualToCart($spouse); 10665a78cd34SGreg Roach } 10675a78cd34SGreg Roach 1068e8ded2caSGreg Roach $this->addLocationLinksToCart($family); 1069d45701ccSGreg Roach $this->addMediaLinksToCart($family); 1070d45701ccSGreg Roach $this->addNoteLinksToCart($family); 1071d45701ccSGreg Roach $this->addSourceLinksToCart($family); 1072d45701ccSGreg Roach $this->addSubmitterLinksToCart($family); 1073d45701ccSGreg Roach } 1074d45701ccSGreg Roach } 1075d45701ccSGreg Roach 1076d45701ccSGreg Roach /** 1077d45701ccSGreg Roach * @param Individual $individual 1078d45701ccSGreg Roach */ 1079d45701ccSGreg Roach protected function addIndividualToCart(Individual $individual): void 1080d45701ccSGreg Roach { 1081d45701ccSGreg Roach $cart = Session::get('cart', []); 1082d45701ccSGreg Roach $tree = $individual->tree()->name(); 1083d45701ccSGreg Roach $xref = $individual->xref(); 1084d45701ccSGreg Roach 1085d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1086d45701ccSGreg Roach $cart[$tree][$xref] = true; 1087d45701ccSGreg Roach 1088d45701ccSGreg Roach Session::put('cart', $cart); 1089d45701ccSGreg Roach 1090e8ded2caSGreg Roach $this->addLocationLinksToCart($individual); 1091d45701ccSGreg Roach $this->addMediaLinksToCart($individual); 1092d45701ccSGreg Roach $this->addNoteLinksToCart($individual); 1093d45701ccSGreg Roach $this->addSourceLinksToCart($individual); 1094d45701ccSGreg Roach } 1095d45701ccSGreg Roach } 1096d45701ccSGreg Roach 1097d45701ccSGreg Roach /** 1098e8ded2caSGreg Roach * @param Location $location 1099e8ded2caSGreg Roach */ 1100e8ded2caSGreg Roach protected function addLocationToCart(Location $location): void 1101e8ded2caSGreg Roach { 1102e8ded2caSGreg Roach $cart = Session::get('cart', []); 1103e8ded2caSGreg Roach $tree = $location->tree()->name(); 1104e8ded2caSGreg Roach $xref = $location->xref(); 1105e8ded2caSGreg Roach 1106e8ded2caSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1107e8ded2caSGreg Roach $cart[$tree][$xref] = true; 1108e8ded2caSGreg Roach 1109e8ded2caSGreg Roach Session::put('cart', $cart); 1110e8ded2caSGreg Roach 1111e8ded2caSGreg Roach $this->addLocationLinksToCart($location); 1112e8ded2caSGreg Roach $this->addMediaLinksToCart($location); 1113e8ded2caSGreg Roach $this->addNoteLinksToCart($location); 1114e8ded2caSGreg Roach $this->addSourceLinksToCart($location); 1115e8ded2caSGreg Roach } 1116e8ded2caSGreg Roach } 1117e8ded2caSGreg Roach 1118e8ded2caSGreg Roach /** 1119e8ded2caSGreg Roach * @param GedcomRecord $record 1120e8ded2caSGreg Roach */ 1121e8ded2caSGreg Roach protected function addLocationLinksToCart(GedcomRecord $record): void 1122e8ded2caSGreg Roach { 1123e8ded2caSGreg Roach preg_match_all('/\n\d _LOC @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1124e8ded2caSGreg Roach 1125e8ded2caSGreg Roach foreach ($matches[1] as $xref) { 1126e8ded2caSGreg Roach $location = Registry::locationFactory()->make($xref, $record->tree()); 1127e8ded2caSGreg Roach 1128e8ded2caSGreg Roach if ($location instanceof Location && $location->canShow()) { 1129e8ded2caSGreg Roach $this->addLocationToCart($location); 1130e8ded2caSGreg Roach } 1131e8ded2caSGreg Roach } 1132e8ded2caSGreg Roach } 1133e8ded2caSGreg Roach 1134e8ded2caSGreg Roach /** 1135d45701ccSGreg Roach * @param Media $media 1136d45701ccSGreg Roach */ 1137d45701ccSGreg Roach protected function addMediaToCart(Media $media): void 1138d45701ccSGreg Roach { 1139d45701ccSGreg Roach $cart = Session::get('cart', []); 1140d45701ccSGreg Roach $tree = $media->tree()->name(); 1141d45701ccSGreg Roach $xref = $media->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($media); 1149d45701ccSGreg Roach } 1150d45701ccSGreg Roach } 1151d45701ccSGreg Roach 1152d45701ccSGreg Roach /** 1153d45701ccSGreg Roach * @param GedcomRecord $record 1154d45701ccSGreg Roach */ 1155d45701ccSGreg Roach protected function addMediaLinksToCart(GedcomRecord $record): void 1156d45701ccSGreg Roach { 1157d45701ccSGreg Roach preg_match_all('/\n\d OBJE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1158d45701ccSGreg Roach 1159d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1160d45701ccSGreg Roach $media = Registry::mediaFactory()->make($xref, $record->tree()); 1161d45701ccSGreg Roach 1162d45701ccSGreg Roach if ($media instanceof Media && $media->canShow()) { 1163d45701ccSGreg Roach $this->addMediaToCart($media); 1164d45701ccSGreg Roach } 1165d45701ccSGreg Roach } 1166d45701ccSGreg Roach } 1167d45701ccSGreg Roach 1168d45701ccSGreg Roach /** 1169d45701ccSGreg Roach * @param Note $note 1170d45701ccSGreg Roach */ 1171d45701ccSGreg Roach protected function addNoteToCart(Note $note): void 1172d45701ccSGreg Roach { 1173d45701ccSGreg Roach $cart = Session::get('cart', []); 1174d45701ccSGreg Roach $tree = $note->tree()->name(); 1175d45701ccSGreg Roach $xref = $note->xref(); 1176d45701ccSGreg Roach 1177d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1178d45701ccSGreg Roach $cart[$tree][$xref] = true; 1179d45701ccSGreg Roach 11805a78cd34SGreg Roach Session::put('cart', $cart); 11815a78cd34SGreg Roach } 1182d45701ccSGreg Roach } 11835a78cd34SGreg Roach 11845a78cd34SGreg Roach /** 1185d45701ccSGreg Roach * @param GedcomRecord $record 11865a78cd34SGreg Roach */ 1187d45701ccSGreg Roach protected function addNoteLinksToCart(GedcomRecord $record): void 1188d45701ccSGreg Roach { 1189d45701ccSGreg Roach preg_match_all('/\n\d NOTE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1190d45701ccSGreg Roach 1191d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1192d45701ccSGreg Roach $note = Registry::noteFactory()->make($xref, $record->tree()); 1193d45701ccSGreg Roach 1194d45701ccSGreg Roach if ($note instanceof Note && $note->canShow()) { 1195d45701ccSGreg Roach $this->addNoteToCart($note); 1196d45701ccSGreg Roach } 1197d45701ccSGreg Roach } 1198d45701ccSGreg Roach } 1199d45701ccSGreg Roach 1200d45701ccSGreg Roach /** 1201d45701ccSGreg Roach * @param Source $source 1202d45701ccSGreg Roach */ 1203d45701ccSGreg Roach protected function addSourceToCart(Source $source): void 1204c1010edaSGreg Roach { 12055a78cd34SGreg Roach $cart = Session::get('cart', []); 1206d45701ccSGreg Roach $tree = $source->tree()->name(); 1207d45701ccSGreg Roach $xref = $source->xref(); 12085a78cd34SGreg Roach 1209d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1210d45701ccSGreg Roach $cart[$tree][$xref] = true; 1211d45701ccSGreg Roach 1212d45701ccSGreg Roach Session::put('cart', $cart); 1213d45701ccSGreg Roach 1214d45701ccSGreg Roach $this->addNoteLinksToCart($source); 1215d45701ccSGreg Roach $this->addRepositoryLinksToCart($source); 1216d45701ccSGreg Roach } 1217d45701ccSGreg Roach } 1218d45701ccSGreg Roach 1219d45701ccSGreg Roach /** 1220d45701ccSGreg Roach * @param GedcomRecord $record 1221d45701ccSGreg Roach */ 1222d45701ccSGreg Roach protected function addSourceLinksToCart(GedcomRecord $record): void 1223d45701ccSGreg Roach { 1224d45701ccSGreg Roach preg_match_all('/\n\d SOUR @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1225d45701ccSGreg Roach 1226d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1227d45701ccSGreg Roach $source = Registry::sourceFactory()->make($xref, $record->tree()); 1228d45701ccSGreg Roach 1229d45701ccSGreg Roach if ($source instanceof Source && $source->canShow()) { 1230d45701ccSGreg Roach $this->addSourceToCart($source); 1231d45701ccSGreg Roach } 1232d45701ccSGreg Roach } 1233d45701ccSGreg Roach } 1234d45701ccSGreg Roach 1235d45701ccSGreg Roach /** 1236d45701ccSGreg Roach * @param Repository $repository 1237d45701ccSGreg Roach */ 1238d45701ccSGreg Roach protected function addRepositoryToCart(Repository $repository): void 1239d45701ccSGreg Roach { 1240d45701ccSGreg Roach $cart = Session::get('cart', []); 1241d45701ccSGreg Roach $tree = $repository->tree()->name(); 1242d45701ccSGreg Roach $xref = $repository->xref(); 1243d45701ccSGreg Roach 1244d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1245d45701ccSGreg Roach $cart[$tree][$xref] = true; 1246d45701ccSGreg Roach 1247d45701ccSGreg Roach Session::put('cart', $cart); 1248d45701ccSGreg Roach 1249d45701ccSGreg Roach $this->addNoteLinksToCart($repository); 1250d45701ccSGreg Roach } 1251d45701ccSGreg Roach } 1252d45701ccSGreg Roach 1253d45701ccSGreg Roach /** 1254d45701ccSGreg Roach * @param GedcomRecord $record 1255d45701ccSGreg Roach */ 1256d45701ccSGreg Roach protected function addRepositoryLinksToCart(GedcomRecord $record): void 1257d45701ccSGreg Roach { 1258d45701ccSGreg Roach preg_match_all('/\n\d REPO @(' . Gedcom::REGEX_XREF . '@)/', $record->gedcom(), $matches); 1259d45701ccSGreg Roach 1260d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1261d45701ccSGreg Roach $repository = Registry::repositoryFactory()->make($xref, $record->tree()); 1262d45701ccSGreg Roach 1263d45701ccSGreg Roach if ($repository instanceof Repository && $repository->canShow()) { 1264d45701ccSGreg Roach $this->addRepositoryToCart($repository); 1265d45701ccSGreg Roach } 1266d45701ccSGreg Roach } 1267d45701ccSGreg Roach } 1268d45701ccSGreg Roach 1269d45701ccSGreg Roach /** 1270d45701ccSGreg Roach * @param Submitter $submitter 1271d45701ccSGreg Roach */ 1272d45701ccSGreg Roach protected function addSubmitterToCart(Submitter $submitter): void 1273d45701ccSGreg Roach { 1274d45701ccSGreg Roach $cart = Session::get('cart', []); 1275d45701ccSGreg Roach $tree = $submitter->tree()->name(); 1276d45701ccSGreg Roach $xref = $submitter->xref(); 1277d45701ccSGreg Roach 1278d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1279d45701ccSGreg Roach $cart[$tree][$xref] = true; 1280d45701ccSGreg Roach 1281d45701ccSGreg Roach Session::put('cart', $cart); 1282d45701ccSGreg Roach 1283d45701ccSGreg Roach $this->addNoteLinksToCart($submitter); 1284d45701ccSGreg Roach } 1285d45701ccSGreg Roach } 1286d45701ccSGreg Roach 1287d45701ccSGreg Roach /** 1288d45701ccSGreg Roach * @param GedcomRecord $record 1289d45701ccSGreg Roach */ 1290d45701ccSGreg Roach protected function addSubmitterLinksToCart(GedcomRecord $record): void 1291d45701ccSGreg Roach { 1292d45701ccSGreg Roach preg_match_all('/\n\d SUBM @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1293d45701ccSGreg Roach 1294d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1295d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $record->tree()); 1296d45701ccSGreg Roach 1297d45701ccSGreg Roach if ($submitter instanceof Submitter && $submitter->canShow()) { 1298d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 1299d45701ccSGreg Roach } 1300d45701ccSGreg Roach } 13015a78cd34SGreg Roach } 13028c2e8227SGreg Roach} 1303