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; 29f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MediaPage; 30f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\NotePage; 31f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\RepositoryPage; 32f95e0480SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SourcePage; 33*d45701ccSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SubmitterPage; 340e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 350e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 365a78cd34SGreg Roachuse Fisharebest\Webtrees\Media; 370e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 385a78cd34SGreg Roachuse Fisharebest\Webtrees\Note; 39*d45701ccSGreg Roachuse Fisharebest\Webtrees\Registry; 405a78cd34SGreg Roachuse Fisharebest\Webtrees\Repository; 4169c05a6eSGreg Roachuse Fisharebest\Webtrees\Services\GedcomExportService; 42e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Services\UserService; 430e62c4b8SGreg Roachuse Fisharebest\Webtrees\Session; 445a78cd34SGreg Roachuse Fisharebest\Webtrees\Source; 45*d45701ccSGreg Roachuse Fisharebest\Webtrees\Submitter; 46aee13b6dSGreg Roachuse Fisharebest\Webtrees\Tree; 4769c05a6eSGreg Roachuse Illuminate\Support\Collection; 485a78cd34SGreg Roachuse League\Flysystem\Filesystem; 495a78cd34SGreg Roachuse League\Flysystem\ZipArchive\ZipArchiveAdapter; 50bed27cedSGreg Roachuse Psr\Http\Message\ResponseFactoryInterface; 516ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 526ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 536ccdf4f0SGreg Roachuse Psr\Http\Message\StreamFactoryInterface; 5469c05a6eSGreg Roachuse RuntimeException; 553976b470SGreg Roach 56eb235819SGreg Roachuse function app; 57bf80ec58SGreg Roachuse function array_filter; 58bf80ec58SGreg Roachuse function array_keys; 59bf80ec58SGreg Roachuse function array_map; 60fa695506SGreg Roachuse function array_search; 615229eadeSGreg Roachuse function assert; 6269c05a6eSGreg Roachuse function fopen; 63bf80ec58SGreg Roachuse function in_array; 64ddeb3354SGreg Roachuse function is_string; 65bf80ec58SGreg Roachuse function preg_match_all; 66bf80ec58SGreg Roachuse function redirect; 6769c05a6eSGreg Roachuse function rewind; 68bf80ec58SGreg Roachuse function route; 69e5a6b4d4SGreg Roachuse function str_replace; 70fa695506SGreg Roachuse function stream_get_meta_data; 71fa695506SGreg Roachuse function tmpfile; 72fa695506SGreg Roachuse function uasort; 73*d45701ccSGreg Roachuse function view; 74fa695506SGreg Roach 75fa695506SGreg Roachuse const PREG_SET_ORDER; 768c2e8227SGreg Roach 778c2e8227SGreg Roach/** 788c2e8227SGreg Roach * Class ClippingsCartModule 798c2e8227SGreg Roach */ 8037eb8894SGreg Roachclass ClippingsCartModule extends AbstractModule implements ModuleMenuInterface 81c1010edaSGreg Roach{ 8249a243cbSGreg Roach use ModuleMenuTrait; 8349a243cbSGreg Roach 845a78cd34SGreg Roach // Routes that have a record which can be added to the clipboard 8516d6367aSGreg Roach private const ROUTES_WITH_RECORDS = [ 86f95e0480SGreg Roach 'Family' => FamilyPage::class, 87f95e0480SGreg Roach 'Individual' => IndividualPage::class, 88f95e0480SGreg Roach 'Media' => MediaPage::class, 89f95e0480SGreg Roach 'Note' => NotePage::class, 90f95e0480SGreg Roach 'Repository' => RepositoryPage::class, 91f95e0480SGreg Roach 'Source' => SourcePage::class, 92*d45701ccSGreg Roach 'Submitter' => SubmitterPage::class, 93c1010edaSGreg Roach ]; 945a78cd34SGreg Roach 9549a243cbSGreg Roach /** @var int The default access level for this module. It can be changed in the control panel. */ 9649a243cbSGreg Roach protected $access_level = Auth::PRIV_USER; 9749a243cbSGreg Roach 9869c05a6eSGreg Roach /** @var GedcomExportService */ 9969c05a6eSGreg Roach private $gedcom_export_service; 10069c05a6eSGreg Roach 10169c05a6eSGreg Roach /** @var UserService */ 102e5a6b4d4SGreg Roach private $user_service; 103e5a6b4d4SGreg Roach 104e5a6b4d4SGreg Roach /** 105e5a6b4d4SGreg Roach * ClippingsCartModule constructor. 106e5a6b4d4SGreg Roach * 10769c05a6eSGreg Roach * @param GedcomExportService $gedcom_export_service 108e5a6b4d4SGreg Roach * @param UserService $user_service 109e5a6b4d4SGreg Roach */ 11069c05a6eSGreg Roach public function __construct(GedcomExportService $gedcom_export_service, UserService $user_service) 111e5a6b4d4SGreg Roach { 11269c05a6eSGreg Roach $this->gedcom_export_service = $gedcom_export_service; 113e5a6b4d4SGreg Roach $this->user_service = $user_service; 114e5a6b4d4SGreg Roach } 115e5a6b4d4SGreg Roach 116e5a6b4d4SGreg Roach /** 117961ec755SGreg Roach * A sentence describing what this module does. 118961ec755SGreg Roach * 119961ec755SGreg Roach * @return string 120961ec755SGreg Roach */ 12149a243cbSGreg Roach public function description(): string 122c1010edaSGreg Roach { 123bbb76c12SGreg Roach /* I18N: Description of the “Clippings cart” module */ 124bbb76c12SGreg Roach return I18N::translate('Select records from your family tree and save them as a GEDCOM file.'); 1258c2e8227SGreg Roach } 1268c2e8227SGreg Roach 1270ee13198SGreg Roach /** 12849a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 1290ee13198SGreg Roach * 1300ee13198SGreg Roach * @return int 1310ee13198SGreg Roach */ 1328f53f488SRico Sonntag public function defaultMenuOrder(): int 133c1010edaSGreg Roach { 134353b36abSGreg Roach return 6; 1358c2e8227SGreg Roach } 1368c2e8227SGreg Roach 1370ee13198SGreg Roach /** 1380ee13198SGreg Roach * A menu, to be added to the main application menu. 1390ee13198SGreg Roach * 140aee13b6dSGreg Roach * @param Tree $tree 141aee13b6dSGreg Roach * 1420ee13198SGreg Roach * @return Menu|null 1430ee13198SGreg Roach */ 14446295629SGreg Roach public function getMenu(Tree $tree): ?Menu 145c1010edaSGreg Roach { 146eb235819SGreg Roach /** @var ServerRequestInterface $request */ 1476ccdf4f0SGreg Roach $request = app(ServerRequestInterface::class); 1488c2e8227SGreg Roach 149f7ab47b1SGreg Roach $route = $request->getAttribute('route'); 150de2aa325SGreg Roach assert($route instanceof Route); 1515a78cd34SGreg Roach 152*d45701ccSGreg Roach $cart = Session::get('cart', []); 153*d45701ccSGreg Roach $count = count($cart[$tree->name()] ?? []); 154*d45701ccSGreg Roach $badge = view('components/badge', ['count' => $count]); 155*d45701ccSGreg Roach 1565a78cd34SGreg Roach $submenus = [ 157*d45701ccSGreg Roach new Menu($this->title() . ' ' . $badge, route('module', [ 15826684e68SGreg Roach 'module' => $this->name(), 159c1010edaSGreg Roach 'action' => 'Show', 160d72b284aSGreg Roach 'tree' => $tree->name(), 161c1010edaSGreg Roach ]), 'menu-clippings-cart', ['rel' => 'nofollow']), 1625a78cd34SGreg Roach ]; 1635a78cd34SGreg Roach 1642b0d92b4SGreg Roach $action = array_search($route->name, self::ROUTES_WITH_RECORDS, true); 165f95e0480SGreg Roach if ($action !== false) { 1662b0d92b4SGreg Roach $xref = $route->attributes['xref']; 167ddeb3354SGreg Roach assert(is_string($xref)); 168ddeb3354SGreg Roach 169c1010edaSGreg Roach $add_route = route('module', [ 17026684e68SGreg Roach 'module' => $this->name(), 171f95e0480SGreg Roach 'action' => 'Add' . $action, 172c1010edaSGreg Roach 'xref' => $xref, 173d72b284aSGreg Roach 'tree' => $tree->name(), 174c1010edaSGreg Roach ]); 1755a78cd34SGreg Roach 17625b2dde3SGreg Roach $submenus[] = new Menu(I18N::translate('Add to the clippings cart'), $add_route, 'menu-clippings-add', ['rel' => 'nofollow']); 1778c2e8227SGreg Roach } 178cbc1590aSGreg Roach 1795a78cd34SGreg Roach if (!$this->isCartEmpty($tree)) { 180c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Empty the clippings cart'), route('module', [ 18126684e68SGreg Roach 'module' => $this->name(), 182c1010edaSGreg Roach 'action' => 'Empty', 183d72b284aSGreg Roach 'tree' => $tree->name(), 184c1010edaSGreg Roach ]), 'menu-clippings-empty', ['rel' => 'nofollow']); 185f95e0480SGreg Roach 186c1010edaSGreg Roach $submenus[] = new Menu(I18N::translate('Download'), route('module', [ 18726684e68SGreg Roach 'module' => $this->name(), 188c1010edaSGreg Roach 'action' => 'DownloadForm', 189d72b284aSGreg Roach 'tree' => $tree->name(), 190c1010edaSGreg Roach ]), 'menu-clippings-download', ['rel' => 'nofollow']); 1915a78cd34SGreg Roach } 1925a78cd34SGreg Roach 19349a243cbSGreg Roach return new Menu($this->title(), '#', 'menu-clippings', ['rel' => 'nofollow'], $submenus); 1948c2e8227SGreg Roach } 1958c2e8227SGreg Roach 19676692c8bSGreg Roach /** 197*d45701ccSGreg Roach * How should this module be identified in the control panel, etc.? 198*d45701ccSGreg Roach * 199*d45701ccSGreg Roach * @return string 200*d45701ccSGreg Roach */ 201*d45701ccSGreg Roach public function title(): string 202*d45701ccSGreg Roach { 203*d45701ccSGreg Roach /* I18N: Name of a module */ 204*d45701ccSGreg Roach return I18N::translate('Clippings cart'); 205*d45701ccSGreg Roach } 206*d45701ccSGreg Roach 207*d45701ccSGreg Roach /** 208*d45701ccSGreg Roach * @param Tree $tree 209*d45701ccSGreg Roach * 210*d45701ccSGreg Roach * @return bool 211*d45701ccSGreg Roach */ 212*d45701ccSGreg Roach private function isCartEmpty(Tree $tree): bool 213*d45701ccSGreg Roach { 214*d45701ccSGreg Roach $cart = Session::get('cart', []); 215*d45701ccSGreg Roach $contents = $cart[$tree->name()] ?? []; 216*d45701ccSGreg Roach 217*d45701ccSGreg Roach return $contents === []; 218*d45701ccSGreg Roach } 219*d45701ccSGreg Roach 220*d45701ccSGreg Roach /** 221*d45701ccSGreg Roach * @param ServerRequestInterface $request 222*d45701ccSGreg Roach * 223*d45701ccSGreg Roach * @return ResponseInterface 224*d45701ccSGreg Roach */ 225*d45701ccSGreg Roach public function getDownloadFormAction(ServerRequestInterface $request): ResponseInterface 226*d45701ccSGreg Roach { 227*d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 228*d45701ccSGreg Roach assert($tree instanceof Tree); 229*d45701ccSGreg Roach 230*d45701ccSGreg Roach $user = $request->getAttribute('user'); 231*d45701ccSGreg Roach $title = I18N::translate('Family tree clippings cart') . ' — ' . I18N::translate('Download'); 232*d45701ccSGreg Roach 233*d45701ccSGreg Roach return $this->viewResponse('modules/clippings/download', [ 234*d45701ccSGreg Roach 'is_manager' => Auth::isManager($tree, $user), 235*d45701ccSGreg Roach 'is_member' => Auth::isMember($tree, $user), 236*d45701ccSGreg Roach 'module' => $this->name(), 237*d45701ccSGreg Roach 'title' => $title, 238*d45701ccSGreg Roach 'tree' => $tree, 239*d45701ccSGreg Roach ]); 240*d45701ccSGreg Roach } 241*d45701ccSGreg Roach 242*d45701ccSGreg Roach /** 2436ccdf4f0SGreg Roach * @param ServerRequestInterface $request 24476692c8bSGreg Roach * 2456ccdf4f0SGreg Roach * @return ResponseInterface 24676692c8bSGreg Roach */ 247f95e0480SGreg Roach public function postDownloadAction(ServerRequestInterface $request): ResponseInterface 248c1010edaSGreg Roach { 24957ab2231SGreg Roach $tree = $request->getAttribute('tree'); 2504ea62551SGreg Roach assert($tree instanceof Tree); 2514ea62551SGreg Roach 2526b9cb339SGreg Roach $data_filesystem = Registry::filesystem()->data(); 253a04bb9a2SGreg Roach 254b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 255b46c87bdSGreg Roach 256*d45701ccSGreg Roach $privatize_export = $params['privatize_export'] ?? 'none'; 257e2ed7c79SGreg Roach 258e2ed7c79SGreg Roach if ($privatize_export === 'none' && !Auth::isManager($tree)) { 259e2ed7c79SGreg Roach $privatize_export = 'member'; 260e2ed7c79SGreg Roach } 261e2ed7c79SGreg Roach 262e2ed7c79SGreg Roach if ($privatize_export === 'gedadmin' && !Auth::isManager($tree)) { 263e2ed7c79SGreg Roach $privatize_export = 'member'; 264e2ed7c79SGreg Roach } 265e2ed7c79SGreg Roach 266e2ed7c79SGreg Roach if ($privatize_export === 'user' && !Auth::isMember($tree)) { 267e2ed7c79SGreg Roach $privatize_export = 'visitor'; 268e2ed7c79SGreg Roach } 269e2ed7c79SGreg Roach 270b46c87bdSGreg Roach $convert = (bool) ($params['convert'] ?? false); 2718c2e8227SGreg Roach 27213abd6f3SGreg Roach $cart = Session::get('cart', []); 2738c2e8227SGreg Roach 274aa6f03bbSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 275c8846facSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 2765a78cd34SGreg Roach 2775a78cd34SGreg Roach // Create a new/empty .ZIP file 278a00baf47SGreg Roach $temp_zip_file = stream_get_meta_data(tmpfile())['uri']; 2797f996f6eSGreg Roach $zip_adapter = new ZipArchiveAdapter($temp_zip_file); 2807f996f6eSGreg Roach $zip_filesystem = new Filesystem($zip_adapter); 2815a78cd34SGreg Roach 282fa695506SGreg Roach $media_filesystem = $tree->mediaFilesystem($data_filesystem); 28361bf91b2SGreg Roach 2845a78cd34SGreg Roach // Media file prefix 2855a78cd34SGreg Roach $path = $tree->getPreference('MEDIA_DIRECTORY'); 2865a78cd34SGreg Roach 28769c05a6eSGreg Roach $encoding = $convert ? 'ANSI' : 'UTF-8'; 28869c05a6eSGreg Roach 28969c05a6eSGreg Roach $records = new Collection(); 2905a78cd34SGreg Roach 2915a78cd34SGreg Roach switch ($privatize_export) { 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 33255167344SGreg Roach if ($object instanceof Individual || $object instanceof Family) { 33369c05a6eSGreg Roach $records->add($record . "\n1 SOUR @WEBTREES@\n2 PAGE " . $object->url()); 33455167344SGreg Roach } elseif ($object instanceof Source) { 33569c05a6eSGreg Roach $records->add($record . "\n1 NOTE " . $object->url()); 33655167344SGreg Roach } elseif ($object instanceof Media) { 33755167344SGreg Roach // Add the media files to the archive 3385a78cd34SGreg Roach foreach ($object->mediaFiles() as $media_file) { 339fa695506SGreg Roach $from = $media_file->filename(); 340fa695506SGreg Roach $to = $path . $media_file->filename(); 341fa695506SGreg Roach if (!$media_file->isExternal() && $media_filesystem->has($from) && !$zip_filesystem->has($to)) { 342fa695506SGreg Roach $zip_filesystem->writeStream($to, $media_filesystem->readStream($from)); 3435a78cd34SGreg Roach } 3445a78cd34SGreg Roach } 34569c05a6eSGreg Roach $records->add($record); 34655167344SGreg Roach } else { 34769c05a6eSGreg Roach $records->add($record); 3488c2e8227SGreg Roach } 3498c2e8227SGreg Roach } 3508c2e8227SGreg Roach } 3518c2e8227SGreg Roach 3529b93b7c3SGreg Roach $base_url = $request->getAttribute('base_url'); 3539b93b7c3SGreg Roach 3545a78cd34SGreg Roach // Create a source, to indicate the source of the data. 35569c05a6eSGreg Roach $record = "0 @WEBTREES@ SOUR\n1 TITL " . $base_url; 356e5a6b4d4SGreg Roach $author = $this->user_service->find((int) $tree->getPreference('CONTACT_USER_ID')); 3575a78cd34SGreg Roach if ($author !== null) { 35869c05a6eSGreg Roach $record .= "\n1 AUTH " . $author->realName(); 3595a78cd34SGreg Roach } 36069c05a6eSGreg Roach $records->add($record); 3615a78cd34SGreg Roach 36269c05a6eSGreg Roach $stream = fopen('php://temp', 'wb+'); 3635a78cd34SGreg Roach 36469c05a6eSGreg Roach if ($stream === false) { 36569c05a6eSGreg Roach throw new RuntimeException('Failed to create temporary stream'); 3668c2e8227SGreg Roach } 367cbc1590aSGreg Roach 36869c05a6eSGreg Roach // We have already applied privacy filtering, so do not do it again. 36969c05a6eSGreg Roach $this->gedcom_export_service->export($tree, $stream, false, $encoding, Auth::PRIV_HIDE, $path, $records); 37069c05a6eSGreg Roach rewind($stream); 37169c05a6eSGreg Roach 3725a78cd34SGreg Roach // Finally add the GEDCOM file to the .ZIP file. 37369c05a6eSGreg Roach $zip_filesystem->writeStream('clippings.ged', $stream); 3745a78cd34SGreg Roach 37561bf91b2SGreg Roach // Need to force-close ZipArchive filesystems. 3767f996f6eSGreg Roach $zip_adapter->getArchive()->close(); 3775a78cd34SGreg Roach 3786ccdf4f0SGreg Roach // Use a stream, so that we do not have to load the entire file into memory. 3796ccdf4f0SGreg Roach $stream = app(StreamFactoryInterface::class)->createStreamFromFile($temp_zip_file); 3805a78cd34SGreg Roach 381bed27cedSGreg Roach /** @var ResponseFactoryInterface $response_factory */ 382bed27cedSGreg Roach $response_factory = app(ResponseFactoryInterface::class); 383bed27cedSGreg Roach 384bed27cedSGreg Roach return $response_factory->createResponse() 3856ccdf4f0SGreg Roach ->withBody($stream) 3861b3d4731SGreg Roach ->withHeader('Content-Type', 'application/zip') 387bed27cedSGreg Roach ->withHeader('Content-Disposition', 'attachment; filename="clippings.zip'); 3888c2e8227SGreg Roach } 3898c2e8227SGreg Roach 3908c2e8227SGreg Roach /** 39157ab2231SGreg Roach * @param ServerRequestInterface $request 39276692c8bSGreg Roach * 3936ccdf4f0SGreg Roach * @return ResponseInterface 3948c2e8227SGreg Roach */ 39557ab2231SGreg Roach public function getEmptyAction(ServerRequestInterface $request): ResponseInterface 396c1010edaSGreg Roach { 39757ab2231SGreg Roach $tree = $request->getAttribute('tree'); 3984ea62551SGreg Roach assert($tree instanceof Tree); 3994ea62551SGreg Roach 4005a78cd34SGreg Roach $cart = Session::get('cart', []); 401aa6f03bbSGreg Roach $cart[$tree->name()] = []; 4025a78cd34SGreg Roach Session::put('cart', $cart); 4038c2e8227SGreg Roach 404c1010edaSGreg Roach $url = route('module', [ 40526684e68SGreg Roach 'module' => $this->name(), 406c1010edaSGreg Roach 'action' => 'Show', 407d72b284aSGreg Roach 'tree' => $tree->name(), 408c1010edaSGreg Roach ]); 4095a78cd34SGreg Roach 4106ccdf4f0SGreg Roach return redirect($url); 4115a78cd34SGreg Roach } 4125a78cd34SGreg Roach 4135a78cd34SGreg Roach /** 4146ccdf4f0SGreg Roach * @param ServerRequestInterface $request 4155a78cd34SGreg Roach * 4166ccdf4f0SGreg Roach * @return ResponseInterface 4175a78cd34SGreg Roach */ 41857ab2231SGreg Roach public function postRemoveAction(ServerRequestInterface $request): ResponseInterface 419c1010edaSGreg Roach { 42057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 42175964c75SGreg Roach assert($tree instanceof Tree); 4225229eadeSGreg Roach 423*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 4245a78cd34SGreg Roach 4255a78cd34SGreg Roach $cart = Session::get('cart', []); 426aa6f03bbSGreg Roach unset($cart[$tree->name()][$xref]); 4275a78cd34SGreg Roach Session::put('cart', $cart); 4285a78cd34SGreg Roach 429c1010edaSGreg Roach $url = route('module', [ 43026684e68SGreg Roach 'module' => $this->name(), 431c1010edaSGreg Roach 'action' => 'Show', 432d72b284aSGreg Roach 'tree' => $tree->name(), 433c1010edaSGreg Roach ]); 4345a78cd34SGreg Roach 4356ccdf4f0SGreg Roach return redirect($url); 4365a78cd34SGreg Roach } 4375a78cd34SGreg Roach 4385a78cd34SGreg Roach /** 43957ab2231SGreg Roach * @param ServerRequestInterface $request 4405a78cd34SGreg Roach * 4416ccdf4f0SGreg Roach * @return ResponseInterface 4425a78cd34SGreg Roach */ 44357ab2231SGreg Roach public function getShowAction(ServerRequestInterface $request): ResponseInterface 444c1010edaSGreg Roach { 44557ab2231SGreg Roach $tree = $request->getAttribute('tree'); 44675964c75SGreg Roach assert($tree instanceof Tree); 44757ab2231SGreg Roach 4485a78cd34SGreg Roach return $this->viewResponse('modules/clippings/show', [ 44977b78a63SRichard Cissée 'module' => $this->name(), 4505a78cd34SGreg Roach 'records' => $this->allRecordsInCart($tree), 4515a78cd34SGreg Roach 'title' => I18N::translate('Family tree clippings cart'), 4525a78cd34SGreg Roach 'tree' => $tree, 4535a78cd34SGreg Roach ]); 4545a78cd34SGreg Roach } 4555a78cd34SGreg Roach 4565a78cd34SGreg Roach /** 457*d45701ccSGreg Roach * Get all the records in the cart. 458*d45701ccSGreg Roach * 459*d45701ccSGreg Roach * @param Tree $tree 460*d45701ccSGreg Roach * 461*d45701ccSGreg Roach * @return GedcomRecord[] 462*d45701ccSGreg Roach */ 463*d45701ccSGreg Roach private function allRecordsInCart(Tree $tree): array 464*d45701ccSGreg Roach { 465*d45701ccSGreg Roach $cart = Session::get('cart', []); 466*d45701ccSGreg Roach 467*d45701ccSGreg Roach $xrefs = array_keys($cart[$tree->name()] ?? []); 468*d45701ccSGreg Roach $xrefs = array_map('strval', $xrefs); // PHP converts numeric keys to integers. 469*d45701ccSGreg Roach 470*d45701ccSGreg Roach // Fetch all the records in the cart. 471*d45701ccSGreg Roach $records = array_map(static function (string $xref) use ($tree): ?GedcomRecord { 472*d45701ccSGreg Roach return Registry::gedcomRecordFactory()->make($xref, $tree); 473*d45701ccSGreg Roach }, $xrefs); 474*d45701ccSGreg Roach 475*d45701ccSGreg Roach // Some records may have been deleted after they were added to the cart. 476*d45701ccSGreg Roach $records = array_filter($records); 477*d45701ccSGreg Roach 478*d45701ccSGreg Roach // Group and sort. 479*d45701ccSGreg Roach uasort($records, static function (GedcomRecord $x, GedcomRecord $y): int { 480*d45701ccSGreg Roach return $x->tag() <=> $y->tag() ?: GedcomRecord::nameComparator()($x, $y); 481*d45701ccSGreg Roach }); 482*d45701ccSGreg Roach 483*d45701ccSGreg Roach return $records; 484*d45701ccSGreg Roach } 485*d45701ccSGreg Roach 486*d45701ccSGreg Roach /** 4876ccdf4f0SGreg Roach * @param ServerRequestInterface $request 4885a78cd34SGreg Roach * 4896ccdf4f0SGreg Roach * @return ResponseInterface 4905a78cd34SGreg Roach */ 49157ab2231SGreg Roach public function getAddFamilyAction(ServerRequestInterface $request): ResponseInterface 492c1010edaSGreg Roach { 49357ab2231SGreg Roach $tree = $request->getAttribute('tree'); 49475964c75SGreg Roach assert($tree instanceof Tree); 4955229eadeSGreg Roach 496*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 4975a78cd34SGreg Roach 4986b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 499*d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 500*d45701ccSGreg Roach $name = $family->fullName(); 5015a78cd34SGreg Roach 502*d45701ccSGreg Roach $options = [ 503*d45701ccSGreg Roach 'record' => $name, 504bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 505bbb76c12SGreg Roach 'members' => I18N::translate('%s and their children', $name), 506bbb76c12SGreg Roach /* I18N: %s is a family (husband + wife) */ 507bbb76c12SGreg Roach 'descendants' => I18N::translate('%s and their descendants', $name), 5085a78cd34SGreg Roach ]; 509*d45701ccSGreg Roach 510*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 511*d45701ccSGreg Roach 512*d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 513*d45701ccSGreg Roach 'options' => $options, 514*d45701ccSGreg Roach 'record' => $family, 515*d45701ccSGreg Roach 'title' => $title, 516*d45701ccSGreg Roach 'tree' => $tree, 517*d45701ccSGreg Roach ]); 5185a78cd34SGreg Roach } 5195a78cd34SGreg Roach 5205a78cd34SGreg Roach /** 5216ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5225a78cd34SGreg Roach * 5236ccdf4f0SGreg Roach * @return ResponseInterface 5245a78cd34SGreg Roach */ 52557ab2231SGreg Roach public function postAddFamilyAction(ServerRequestInterface $request): ResponseInterface 526c1010edaSGreg Roach { 52757ab2231SGreg Roach $tree = $request->getAttribute('tree'); 5284ea62551SGreg Roach assert($tree instanceof Tree); 5294ea62551SGreg Roach 530b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 531b46c87bdSGreg Roach 532*d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 533*d45701ccSGreg Roach $option = $params['option'] ?? ''; 5345a78cd34SGreg Roach 5356b9cb339SGreg Roach $family = Registry::familyFactory()->make($xref, $tree); 536*d45701ccSGreg Roach $family = Auth::checkFamilyAccess($family); 5375a78cd34SGreg Roach 5385a78cd34SGreg Roach switch ($option) { 539*d45701ccSGreg Roach case 'self': 5405a78cd34SGreg Roach $this->addFamilyToCart($family); 5415a78cd34SGreg Roach break; 5425a78cd34SGreg Roach 5435a78cd34SGreg Roach case 'members': 5445a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 5455a78cd34SGreg Roach break; 5465a78cd34SGreg Roach 5475a78cd34SGreg Roach case 'descendants': 5485a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 5495a78cd34SGreg Roach break; 5505a78cd34SGreg Roach } 5515a78cd34SGreg Roach 5526ccdf4f0SGreg Roach return redirect($family->url()); 5535a78cd34SGreg Roach } 5545a78cd34SGreg Roach 5555a78cd34SGreg Roach 5565a78cd34SGreg Roach /** 5575a78cd34SGreg Roach * @param Family $family 55818d7a90dSGreg Roach * 55918d7a90dSGreg Roach * @return void 5605a78cd34SGreg Roach */ 561*d45701ccSGreg Roach protected function addFamilyAndChildrenToCart(Family $family): void 562c1010edaSGreg Roach { 563*d45701ccSGreg Roach $this->addFamilyToCart($family); 5645a78cd34SGreg Roach 56539ca88baSGreg Roach foreach ($family->children() as $child) { 566*d45701ccSGreg Roach $this->addIndividualToCart($child); 5675a78cd34SGreg Roach } 5685a78cd34SGreg Roach } 5695a78cd34SGreg Roach 5705a78cd34SGreg Roach /** 5715a78cd34SGreg Roach * @param Family $family 57218d7a90dSGreg Roach * 57318d7a90dSGreg Roach * @return void 5745a78cd34SGreg Roach */ 575*d45701ccSGreg Roach protected function addFamilyAndDescendantsToCart(Family $family): void 576c1010edaSGreg Roach { 577*d45701ccSGreg Roach $this->addFamilyAndChildrenToCart($family); 5785a78cd34SGreg Roach 57939ca88baSGreg Roach foreach ($family->children() as $child) { 58039ca88baSGreg Roach foreach ($child->spouseFamilies() as $child_family) { 5815a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($child_family); 5825a78cd34SGreg Roach } 5835a78cd34SGreg Roach } 5845a78cd34SGreg Roach } 5855a78cd34SGreg Roach 5865a78cd34SGreg Roach /** 5876ccdf4f0SGreg Roach * @param ServerRequestInterface $request 5885a78cd34SGreg Roach * 5896ccdf4f0SGreg Roach * @return ResponseInterface 5905a78cd34SGreg Roach */ 59157ab2231SGreg Roach public function getAddIndividualAction(ServerRequestInterface $request): ResponseInterface 592c1010edaSGreg Roach { 59357ab2231SGreg Roach $tree = $request->getAttribute('tree'); 59475964c75SGreg Roach assert($tree instanceof Tree); 5955229eadeSGreg Roach 596*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 5975a78cd34SGreg Roach 5986b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 599*d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 600*d45701ccSGreg Roach $name = $individual->fullName(); 6015a78cd34SGreg Roach 60239ca88baSGreg Roach if ($individual->sex() === 'F') { 603*d45701ccSGreg Roach $options = [ 604*d45701ccSGreg Roach 'record' => $name, 6055a78cd34SGreg Roach 'parents' => I18N::translate('%s, her parents and siblings', $name), 6065a78cd34SGreg Roach 'spouses' => I18N::translate('%s, her spouses and children', $name), 6075a78cd34SGreg Roach 'ancestors' => I18N::translate('%s and her ancestors', $name), 6085a78cd34SGreg Roach 'ancestor_families' => I18N::translate('%s, her ancestors and their families', $name), 6095a78cd34SGreg Roach 'descendants' => I18N::translate('%s, her spouses and descendants', $name), 6105a78cd34SGreg Roach ]; 611*d45701ccSGreg Roach } else { 612*d45701ccSGreg Roach $options = [ 613*d45701ccSGreg Roach 'record' => $name, 6145a78cd34SGreg Roach 'parents' => I18N::translate('%s, his parents and siblings', $name), 6155a78cd34SGreg Roach 'spouses' => I18N::translate('%s, his spouses and children', $name), 6165a78cd34SGreg Roach 'ancestors' => I18N::translate('%s and his ancestors', $name), 6175a78cd34SGreg Roach 'ancestor_families' => I18N::translate('%s, his ancestors and their families', $name), 6185a78cd34SGreg Roach 'descendants' => I18N::translate('%s, his spouses and descendants', $name), 6195a78cd34SGreg Roach ]; 6205a78cd34SGreg Roach } 6215a78cd34SGreg Roach 622*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 623*d45701ccSGreg Roach 624*d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 625*d45701ccSGreg Roach 'options' => $options, 626*d45701ccSGreg Roach 'record' => $individual, 627*d45701ccSGreg Roach 'title' => $title, 628*d45701ccSGreg Roach 'tree' => $tree, 629*d45701ccSGreg Roach ]); 630*d45701ccSGreg Roach } 631*d45701ccSGreg Roach 6325a78cd34SGreg Roach /** 6336ccdf4f0SGreg Roach * @param ServerRequestInterface $request 6345a78cd34SGreg Roach * 6356ccdf4f0SGreg Roach * @return ResponseInterface 6365a78cd34SGreg Roach */ 63757ab2231SGreg Roach public function postAddIndividualAction(ServerRequestInterface $request): ResponseInterface 638c1010edaSGreg Roach { 63957ab2231SGreg Roach $tree = $request->getAttribute('tree'); 6404ea62551SGreg Roach assert($tree instanceof Tree); 6414ea62551SGreg Roach 642b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 643b46c87bdSGreg Roach 644*d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 645*d45701ccSGreg Roach $option = $params['option'] ?? ''; 6465a78cd34SGreg Roach 6476b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 648*d45701ccSGreg Roach $individual = Auth::checkIndividualAccess($individual); 6495a78cd34SGreg Roach 6505a78cd34SGreg Roach switch ($option) { 6515a78cd34SGreg Roach case 'self': 652*d45701ccSGreg Roach $this->addIndividualToCart($individual); 6535a78cd34SGreg Roach break; 6545a78cd34SGreg Roach 6555a78cd34SGreg Roach case 'parents': 65639ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 6575a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6585a78cd34SGreg Roach } 6595a78cd34SGreg Roach break; 6605a78cd34SGreg Roach 6615a78cd34SGreg Roach case 'spouses': 66239ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 6635a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 6645a78cd34SGreg Roach } 6655a78cd34SGreg Roach break; 6665a78cd34SGreg Roach 6675a78cd34SGreg Roach case 'ancestors': 6685a78cd34SGreg Roach $this->addAncestorsToCart($individual); 6695a78cd34SGreg Roach break; 6705a78cd34SGreg Roach 6715a78cd34SGreg Roach case 'ancestor_families': 6725a78cd34SGreg Roach $this->addAncestorFamiliesToCart($individual); 6735a78cd34SGreg Roach break; 6745a78cd34SGreg Roach 6755a78cd34SGreg Roach case 'descendants': 67639ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 6775a78cd34SGreg Roach $this->addFamilyAndDescendantsToCart($family); 6785a78cd34SGreg Roach } 6795a78cd34SGreg Roach break; 6805a78cd34SGreg Roach } 6815a78cd34SGreg Roach 6826ccdf4f0SGreg Roach return redirect($individual->url()); 6835a78cd34SGreg Roach } 6845a78cd34SGreg Roach 6855a78cd34SGreg Roach /** 6865a78cd34SGreg Roach * @param Individual $individual 68718d7a90dSGreg Roach * 68818d7a90dSGreg Roach * @return void 6895a78cd34SGreg Roach */ 690*d45701ccSGreg Roach protected function addAncestorsToCart(Individual $individual): void 691c1010edaSGreg Roach { 692*d45701ccSGreg Roach $this->addIndividualToCart($individual); 6935a78cd34SGreg Roach 69439ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 695*d45701ccSGreg Roach $this->addFamilyToCart($family); 6968df4c68dSGreg Roach 69739ca88baSGreg Roach foreach ($family->spouses() as $parent) { 6985a78cd34SGreg Roach $this->addAncestorsToCart($parent); 6995a78cd34SGreg Roach } 7005a78cd34SGreg Roach } 7015a78cd34SGreg Roach } 7025a78cd34SGreg Roach 7035a78cd34SGreg Roach /** 7045a78cd34SGreg Roach * @param Individual $individual 70518d7a90dSGreg Roach * 70618d7a90dSGreg Roach * @return void 7075a78cd34SGreg Roach */ 708*d45701ccSGreg Roach protected function addAncestorFamiliesToCart(Individual $individual): void 709c1010edaSGreg Roach { 71039ca88baSGreg Roach foreach ($individual->childFamilies() as $family) { 7115a78cd34SGreg Roach $this->addFamilyAndChildrenToCart($family); 7128df4c68dSGreg Roach 71339ca88baSGreg Roach foreach ($family->spouses() as $parent) { 714cad6d3f3SGreg Roach $this->addAncestorFamiliesToCart($parent); 7155a78cd34SGreg Roach } 7165a78cd34SGreg Roach } 7175a78cd34SGreg Roach } 7185a78cd34SGreg Roach 7195a78cd34SGreg Roach /** 7206ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7215a78cd34SGreg Roach * 7226ccdf4f0SGreg Roach * @return ResponseInterface 7235a78cd34SGreg Roach */ 72457ab2231SGreg Roach public function getAddMediaAction(ServerRequestInterface $request): ResponseInterface 725c1010edaSGreg Roach { 72657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 72775964c75SGreg Roach assert($tree instanceof Tree); 7285229eadeSGreg Roach 729*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 7305a78cd34SGreg Roach 7316b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 732*d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 733*d45701ccSGreg Roach $name = $media->fullName(); 7345a78cd34SGreg Roach 735*d45701ccSGreg Roach $options = [ 736*d45701ccSGreg Roach 'record' => $name, 737*d45701ccSGreg Roach ]; 7385a78cd34SGreg Roach 739*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 7405a78cd34SGreg Roach 7415a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 7425a78cd34SGreg Roach 'options' => $options, 7435a78cd34SGreg Roach 'record' => $media, 7445a78cd34SGreg Roach 'title' => $title, 7455a78cd34SGreg Roach 'tree' => $tree, 7465a78cd34SGreg Roach ]); 7475a78cd34SGreg Roach } 7485a78cd34SGreg Roach 7495a78cd34SGreg Roach /** 7506ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7515a78cd34SGreg Roach * 7526ccdf4f0SGreg Roach * @return ResponseInterface 7535a78cd34SGreg Roach */ 75457ab2231SGreg Roach public function postAddMediaAction(ServerRequestInterface $request): ResponseInterface 755c1010edaSGreg Roach { 75657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 75775964c75SGreg Roach assert($tree instanceof Tree); 7585229eadeSGreg Roach 759*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 7605a78cd34SGreg Roach 7616b9cb339SGreg Roach $media = Registry::mediaFactory()->make($xref, $tree); 762*d45701ccSGreg Roach $media = Auth::checkMediaAccess($media); 7635a78cd34SGreg Roach 764*d45701ccSGreg Roach $this->addMediaToCart($media); 7655a78cd34SGreg Roach 7666ccdf4f0SGreg Roach return redirect($media->url()); 7675a78cd34SGreg Roach } 7685a78cd34SGreg Roach 7695a78cd34SGreg Roach /** 7706ccdf4f0SGreg Roach * @param ServerRequestInterface $request 7715a78cd34SGreg Roach * 7726ccdf4f0SGreg Roach * @return ResponseInterface 7735a78cd34SGreg Roach */ 77457ab2231SGreg Roach public function getAddNoteAction(ServerRequestInterface $request): ResponseInterface 775c1010edaSGreg Roach { 77657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 77775964c75SGreg Roach assert($tree instanceof Tree); 7785229eadeSGreg Roach 779*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 7805a78cd34SGreg Roach 7816b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 782*d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 783*d45701ccSGreg Roach $name = $note->fullName(); 7845a78cd34SGreg Roach 785*d45701ccSGreg Roach $options = [ 786*d45701ccSGreg Roach 'record' => $name, 787*d45701ccSGreg Roach ]; 7885a78cd34SGreg Roach 789*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 7905a78cd34SGreg Roach 7915a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 7925a78cd34SGreg Roach 'options' => $options, 7935a78cd34SGreg Roach 'record' => $note, 7945a78cd34SGreg Roach 'title' => $title, 7955a78cd34SGreg Roach 'tree' => $tree, 7965a78cd34SGreg Roach ]); 7975a78cd34SGreg Roach } 7985a78cd34SGreg Roach 7995a78cd34SGreg Roach /** 8006ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8015a78cd34SGreg Roach * 8026ccdf4f0SGreg Roach * @return ResponseInterface 8035a78cd34SGreg Roach */ 80457ab2231SGreg Roach public function postAddNoteAction(ServerRequestInterface $request): ResponseInterface 805c1010edaSGreg Roach { 80657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 80775964c75SGreg Roach assert($tree instanceof Tree); 8085229eadeSGreg Roach 809*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8105a78cd34SGreg Roach 8116b9cb339SGreg Roach $note = Registry::noteFactory()->make($xref, $tree); 812*d45701ccSGreg Roach $note = Auth::checkNoteAccess($note); 8135a78cd34SGreg Roach 814*d45701ccSGreg Roach $this->addNoteToCart($note); 8155a78cd34SGreg Roach 8166ccdf4f0SGreg Roach return redirect($note->url()); 8175a78cd34SGreg Roach } 8185a78cd34SGreg Roach 8195a78cd34SGreg Roach /** 8206ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8215a78cd34SGreg Roach * 8226ccdf4f0SGreg Roach * @return ResponseInterface 8235a78cd34SGreg Roach */ 82457ab2231SGreg Roach public function getAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 825c1010edaSGreg Roach { 82657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 82775964c75SGreg Roach assert($tree instanceof Tree); 8285229eadeSGreg Roach 829*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8305a78cd34SGreg Roach 8316b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 832*d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 833*d45701ccSGreg Roach $name = $repository->fullName(); 8345a78cd34SGreg Roach 835*d45701ccSGreg Roach $options = [ 836*d45701ccSGreg Roach 'record' => $name, 837*d45701ccSGreg Roach ]; 8385a78cd34SGreg Roach 839*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 8405a78cd34SGreg Roach 8415a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 8425a78cd34SGreg Roach 'options' => $options, 8435a78cd34SGreg Roach 'record' => $repository, 8445a78cd34SGreg Roach 'title' => $title, 8455a78cd34SGreg Roach 'tree' => $tree, 8465a78cd34SGreg Roach ]); 8475a78cd34SGreg Roach } 8485a78cd34SGreg Roach 8495a78cd34SGreg Roach /** 8506ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8515a78cd34SGreg Roach * 8526ccdf4f0SGreg Roach * @return ResponseInterface 8535a78cd34SGreg Roach */ 85457ab2231SGreg Roach public function postAddRepositoryAction(ServerRequestInterface $request): ResponseInterface 855c1010edaSGreg Roach { 85657ab2231SGreg Roach $tree = $request->getAttribute('tree'); 85775964c75SGreg Roach assert($tree instanceof Tree); 8585229eadeSGreg Roach 859*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8605a78cd34SGreg Roach 8616b9cb339SGreg Roach $repository = Registry::repositoryFactory()->make($xref, $tree); 862*d45701ccSGreg Roach $repository = Auth::checkRepositoryAccess($repository); 8635a78cd34SGreg Roach 864*d45701ccSGreg Roach $this->addRepositoryToCart($repository); 865*d45701ccSGreg Roach 866*d45701ccSGreg Roach foreach ($repository->linkedSources('REPO') as $source) { 867*d45701ccSGreg Roach $this->addSourceToCart($source); 8685a78cd34SGreg Roach } 8695a78cd34SGreg Roach 8706ccdf4f0SGreg Roach return redirect($repository->url()); 8715a78cd34SGreg Roach } 8725a78cd34SGreg Roach 8735a78cd34SGreg Roach /** 8746ccdf4f0SGreg Roach * @param ServerRequestInterface $request 8755a78cd34SGreg Roach * 8766ccdf4f0SGreg Roach * @return ResponseInterface 8775a78cd34SGreg Roach */ 87857ab2231SGreg Roach public function getAddSourceAction(ServerRequestInterface $request): ResponseInterface 879c1010edaSGreg Roach { 88057ab2231SGreg Roach $tree = $request->getAttribute('tree'); 88175964c75SGreg Roach assert($tree instanceof Tree); 8825229eadeSGreg Roach 883*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 8845a78cd34SGreg Roach 8856b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 886*d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 887*d45701ccSGreg Roach $name = $source->fullName(); 8885a78cd34SGreg Roach 889*d45701ccSGreg Roach $options = [ 890*d45701ccSGreg Roach 'record' => $name, 891*d45701ccSGreg Roach 'linked' => I18N::translate('%s and the individuals that reference it.', $name), 892*d45701ccSGreg Roach ]; 8935a78cd34SGreg Roach 894*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 8955a78cd34SGreg Roach 8965a78cd34SGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 8975a78cd34SGreg Roach 'options' => $options, 8985a78cd34SGreg Roach 'record' => $source, 8995a78cd34SGreg Roach 'title' => $title, 9005a78cd34SGreg Roach 'tree' => $tree, 9015a78cd34SGreg Roach ]); 9025a78cd34SGreg Roach } 9035a78cd34SGreg Roach 9045a78cd34SGreg Roach /** 9056ccdf4f0SGreg Roach * @param ServerRequestInterface $request 9065a78cd34SGreg Roach * 9076ccdf4f0SGreg Roach * @return ResponseInterface 9085a78cd34SGreg Roach */ 90957ab2231SGreg Roach public function postAddSourceAction(ServerRequestInterface $request): ResponseInterface 910c1010edaSGreg Roach { 91157ab2231SGreg Roach $tree = $request->getAttribute('tree'); 91275964c75SGreg Roach assert($tree instanceof Tree); 9135229eadeSGreg Roach 914b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 915b46c87bdSGreg Roach 916*d45701ccSGreg Roach $xref = $params['xref'] ?? ''; 917*d45701ccSGreg Roach $option = $params['option'] ?? ''; 9185a78cd34SGreg Roach 9196b9cb339SGreg Roach $source = Registry::sourceFactory()->make($xref, $tree); 920*d45701ccSGreg Roach $source = Auth::checkSourceAccess($source); 9215a78cd34SGreg Roach 922*d45701ccSGreg Roach $this->addSourceToCart($source); 9235a78cd34SGreg Roach 9245a78cd34SGreg Roach if ($option === 'linked') { 9255a78cd34SGreg Roach foreach ($source->linkedIndividuals('SOUR') as $individual) { 926*d45701ccSGreg Roach $this->addIndividualToCart($individual); 9275a78cd34SGreg Roach } 9285a78cd34SGreg Roach foreach ($source->linkedFamilies('SOUR') as $family) { 929*d45701ccSGreg Roach $this->addFamilyToCart($family); 9305a78cd34SGreg Roach } 9315a78cd34SGreg Roach } 9325a78cd34SGreg Roach 9336ccdf4f0SGreg Roach return redirect($source->url()); 9345a78cd34SGreg Roach } 9355a78cd34SGreg Roach 9365a78cd34SGreg Roach /** 937*d45701ccSGreg Roach * @param ServerRequestInterface $request 9385a78cd34SGreg Roach * 939*d45701ccSGreg Roach * @return ResponseInterface 9405a78cd34SGreg Roach */ 941*d45701ccSGreg Roach public function getAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 942c1010edaSGreg Roach { 943*d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 944*d45701ccSGreg Roach assert($tree instanceof Tree); 9455a78cd34SGreg Roach 946*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 9475a78cd34SGreg Roach 948*d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 949*d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 950*d45701ccSGreg Roach $name = $submitter->fullName(); 9515a78cd34SGreg Roach 952*d45701ccSGreg Roach $options = [ 953*d45701ccSGreg Roach 'record' => $name, 954*d45701ccSGreg Roach ]; 9555a78cd34SGreg Roach 956*d45701ccSGreg Roach $title = I18N::translate('Add %s to the clippings cart', $name); 9575a78cd34SGreg Roach 958*d45701ccSGreg Roach return $this->viewResponse('modules/clippings/add-options', [ 959*d45701ccSGreg Roach 'options' => $options, 960*d45701ccSGreg Roach 'record' => $submitter, 961*d45701ccSGreg Roach 'title' => $title, 962*d45701ccSGreg Roach 'tree' => $tree, 963*d45701ccSGreg Roach ]); 9645a78cd34SGreg Roach } 9655a78cd34SGreg Roach 9665a78cd34SGreg Roach /** 967*d45701ccSGreg Roach * @param ServerRequestInterface $request 9685a78cd34SGreg Roach * 969*d45701ccSGreg Roach * @return ResponseInterface 9705a78cd34SGreg Roach */ 971*d45701ccSGreg Roach public function postAddSubmitterAction(ServerRequestInterface $request): ResponseInterface 972*d45701ccSGreg Roach { 973*d45701ccSGreg Roach $tree = $request->getAttribute('tree'); 974*d45701ccSGreg Roach assert($tree instanceof Tree); 975*d45701ccSGreg Roach 976*d45701ccSGreg Roach $xref = $request->getQueryParams()['xref'] ?? ''; 977*d45701ccSGreg Roach 978*d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $tree); 979*d45701ccSGreg Roach $submitter = Auth::checkSubmitterAccess($submitter); 980*d45701ccSGreg Roach 981*d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 982*d45701ccSGreg Roach 983*d45701ccSGreg Roach return redirect($submitter->url()); 984*d45701ccSGreg Roach } 985*d45701ccSGreg Roach 986*d45701ccSGreg Roach /** 987*d45701ccSGreg Roach * @param Family $family 988*d45701ccSGreg Roach */ 989*d45701ccSGreg Roach protected function addFamilyToCart(Family $family): void 990c1010edaSGreg Roach { 9915a78cd34SGreg Roach $cart = Session::get('cart', []); 992*d45701ccSGreg Roach $tree = $family->tree()->name(); 993*d45701ccSGreg Roach $xref = $family->xref(); 9945a78cd34SGreg Roach 995*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 996*d45701ccSGreg Roach $cart[$tree][$xref] = true; 9975a78cd34SGreg Roach 998*d45701ccSGreg Roach Session::put('cart', $cart); 9995a78cd34SGreg Roach 1000*d45701ccSGreg Roach foreach ($family->spouses() as $spouse) { 1001*d45701ccSGreg Roach $this->addIndividualToCart($spouse); 10025a78cd34SGreg Roach } 10035a78cd34SGreg Roach 1004*d45701ccSGreg Roach $this->addMediaLinksToCart($family); 1005*d45701ccSGreg Roach $this->addNoteLinksToCart($family); 1006*d45701ccSGreg Roach $this->addSourceLinksToCart($family); 1007*d45701ccSGreg Roach $this->addSubmitterLinksToCart($family); 1008*d45701ccSGreg Roach } 1009*d45701ccSGreg Roach } 1010*d45701ccSGreg Roach 1011*d45701ccSGreg Roach /** 1012*d45701ccSGreg Roach * @param Individual $individual 1013*d45701ccSGreg Roach */ 1014*d45701ccSGreg Roach protected function addIndividualToCart(Individual $individual): void 1015*d45701ccSGreg Roach { 1016*d45701ccSGreg Roach $cart = Session::get('cart', []); 1017*d45701ccSGreg Roach $tree = $individual->tree()->name(); 1018*d45701ccSGreg Roach $xref = $individual->xref(); 1019*d45701ccSGreg Roach 1020*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1021*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1022*d45701ccSGreg Roach 1023*d45701ccSGreg Roach Session::put('cart', $cart); 1024*d45701ccSGreg Roach 1025*d45701ccSGreg Roach $this->addMediaLinksToCart($individual); 1026*d45701ccSGreg Roach $this->addNoteLinksToCart($individual); 1027*d45701ccSGreg Roach $this->addSourceLinksToCart($individual); 1028*d45701ccSGreg Roach } 1029*d45701ccSGreg Roach } 1030*d45701ccSGreg Roach 1031*d45701ccSGreg Roach /** 1032*d45701ccSGreg Roach * @param Media $media 1033*d45701ccSGreg Roach */ 1034*d45701ccSGreg Roach protected function addMediaToCart(Media $media): void 1035*d45701ccSGreg Roach { 1036*d45701ccSGreg Roach $cart = Session::get('cart', []); 1037*d45701ccSGreg Roach $tree = $media->tree()->name(); 1038*d45701ccSGreg Roach $xref = $media->xref(); 1039*d45701ccSGreg Roach 1040*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1041*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1042*d45701ccSGreg Roach 1043*d45701ccSGreg Roach Session::put('cart', $cart); 1044*d45701ccSGreg Roach 1045*d45701ccSGreg Roach $this->addNoteLinksToCart($media); 1046*d45701ccSGreg Roach } 1047*d45701ccSGreg Roach } 1048*d45701ccSGreg Roach 1049*d45701ccSGreg Roach /** 1050*d45701ccSGreg Roach * @param GedcomRecord $record 1051*d45701ccSGreg Roach */ 1052*d45701ccSGreg Roach protected function addMediaLinksToCart(GedcomRecord $record): void 1053*d45701ccSGreg Roach { 1054*d45701ccSGreg Roach preg_match_all('/\n\d OBJE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1055*d45701ccSGreg Roach 1056*d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1057*d45701ccSGreg Roach $media = Registry::mediaFactory()->make($xref, $record->tree()); 1058*d45701ccSGreg Roach 1059*d45701ccSGreg Roach if ($media instanceof Media && $media->canShow()) { 1060*d45701ccSGreg Roach $this->addMediaToCart($media); 1061*d45701ccSGreg Roach } 1062*d45701ccSGreg Roach } 1063*d45701ccSGreg Roach } 1064*d45701ccSGreg Roach 1065*d45701ccSGreg Roach /** 1066*d45701ccSGreg Roach * @param Note $note 1067*d45701ccSGreg Roach */ 1068*d45701ccSGreg Roach protected function addNoteToCart(Note $note): void 1069*d45701ccSGreg Roach { 1070*d45701ccSGreg Roach $cart = Session::get('cart', []); 1071*d45701ccSGreg Roach $tree = $note->tree()->name(); 1072*d45701ccSGreg Roach $xref = $note->xref(); 1073*d45701ccSGreg Roach 1074*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1075*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1076*d45701ccSGreg Roach 10775a78cd34SGreg Roach Session::put('cart', $cart); 10785a78cd34SGreg Roach } 1079*d45701ccSGreg Roach } 10805a78cd34SGreg Roach 10815a78cd34SGreg Roach /** 1082*d45701ccSGreg Roach * @param GedcomRecord $record 10835a78cd34SGreg Roach */ 1084*d45701ccSGreg Roach protected function addNoteLinksToCart(GedcomRecord $record): void 1085*d45701ccSGreg Roach { 1086*d45701ccSGreg Roach preg_match_all('/\n\d NOTE @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1087*d45701ccSGreg Roach 1088*d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1089*d45701ccSGreg Roach $note = Registry::noteFactory()->make($xref, $record->tree()); 1090*d45701ccSGreg Roach 1091*d45701ccSGreg Roach if ($note instanceof Note && $note->canShow()) { 1092*d45701ccSGreg Roach $this->addNoteToCart($note); 1093*d45701ccSGreg Roach } 1094*d45701ccSGreg Roach } 1095*d45701ccSGreg Roach } 1096*d45701ccSGreg Roach 1097*d45701ccSGreg Roach /** 1098*d45701ccSGreg Roach * @param Source $source 1099*d45701ccSGreg Roach */ 1100*d45701ccSGreg Roach protected function addSourceToCart(Source $source): void 1101c1010edaSGreg Roach { 11025a78cd34SGreg Roach $cart = Session::get('cart', []); 1103*d45701ccSGreg Roach $tree = $source->tree()->name(); 1104*d45701ccSGreg Roach $xref = $source->xref(); 11055a78cd34SGreg Roach 1106*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1107*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1108*d45701ccSGreg Roach 1109*d45701ccSGreg Roach Session::put('cart', $cart); 1110*d45701ccSGreg Roach 1111*d45701ccSGreg Roach $this->addNoteLinksToCart($source); 1112*d45701ccSGreg Roach $this->addRepositoryLinksToCart($source); 1113*d45701ccSGreg Roach } 1114*d45701ccSGreg Roach } 1115*d45701ccSGreg Roach 1116*d45701ccSGreg Roach /** 1117*d45701ccSGreg Roach * @param GedcomRecord $record 1118*d45701ccSGreg Roach */ 1119*d45701ccSGreg Roach protected function addSourceLinksToCart(GedcomRecord $record): void 1120*d45701ccSGreg Roach { 1121*d45701ccSGreg Roach preg_match_all('/\n\d SOUR @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1122*d45701ccSGreg Roach 1123*d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1124*d45701ccSGreg Roach $source = Registry::sourceFactory()->make($xref, $record->tree()); 1125*d45701ccSGreg Roach 1126*d45701ccSGreg Roach if ($source instanceof Source && $source->canShow()) { 1127*d45701ccSGreg Roach $this->addSourceToCart($source); 1128*d45701ccSGreg Roach } 1129*d45701ccSGreg Roach } 1130*d45701ccSGreg Roach } 1131*d45701ccSGreg Roach 1132*d45701ccSGreg Roach /** 1133*d45701ccSGreg Roach * @param Repository $repository 1134*d45701ccSGreg Roach */ 1135*d45701ccSGreg Roach protected function addRepositoryToCart(Repository $repository): void 1136*d45701ccSGreg Roach { 1137*d45701ccSGreg Roach $cart = Session::get('cart', []); 1138*d45701ccSGreg Roach $tree = $repository->tree()->name(); 1139*d45701ccSGreg Roach $xref = $repository->xref(); 1140*d45701ccSGreg Roach 1141*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1142*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1143*d45701ccSGreg Roach 1144*d45701ccSGreg Roach Session::put('cart', $cart); 1145*d45701ccSGreg Roach 1146*d45701ccSGreg Roach $this->addNoteLinksToCart($repository); 1147*d45701ccSGreg Roach } 1148*d45701ccSGreg Roach } 1149*d45701ccSGreg Roach 1150*d45701ccSGreg Roach 1151*d45701ccSGreg Roach /** 1152*d45701ccSGreg Roach * @param GedcomRecord $record 1153*d45701ccSGreg Roach */ 1154*d45701ccSGreg Roach protected function addRepositoryLinksToCart(GedcomRecord $record): void 1155*d45701ccSGreg Roach { 1156*d45701ccSGreg Roach preg_match_all('/\n\d REPO @(' . Gedcom::REGEX_XREF . '@)/', $record->gedcom(), $matches); 1157*d45701ccSGreg Roach 1158*d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1159*d45701ccSGreg Roach $repository = Registry::repositoryFactory()->make($xref, $record->tree()); 1160*d45701ccSGreg Roach 1161*d45701ccSGreg Roach if ($repository instanceof Repository && $repository->canShow()) { 1162*d45701ccSGreg Roach $this->addRepositoryToCart($repository); 1163*d45701ccSGreg Roach } 1164*d45701ccSGreg Roach } 1165*d45701ccSGreg Roach } 1166*d45701ccSGreg Roach 1167*d45701ccSGreg Roach /** 1168*d45701ccSGreg Roach * @param Submitter $submitter 1169*d45701ccSGreg Roach */ 1170*d45701ccSGreg Roach protected function addSubmitterToCart(Submitter $submitter): void 1171*d45701ccSGreg Roach { 1172*d45701ccSGreg Roach $cart = Session::get('cart', []); 1173*d45701ccSGreg Roach $tree = $submitter->tree()->name(); 1174*d45701ccSGreg Roach $xref = $submitter->xref(); 1175*d45701ccSGreg Roach 1176*d45701ccSGreg Roach if (($cart[$tree][$xref] ?? false) === false) { 1177*d45701ccSGreg Roach $cart[$tree][$xref] = true; 1178*d45701ccSGreg Roach 1179*d45701ccSGreg Roach Session::put('cart', $cart); 1180*d45701ccSGreg Roach 1181*d45701ccSGreg Roach $this->addNoteLinksToCart($submitter); 1182*d45701ccSGreg Roach } 1183*d45701ccSGreg Roach } 1184*d45701ccSGreg Roach 1185*d45701ccSGreg Roach /** 1186*d45701ccSGreg Roach * @param GedcomRecord $record 1187*d45701ccSGreg Roach */ 1188*d45701ccSGreg Roach protected function addSubmitterLinksToCart(GedcomRecord $record): void 1189*d45701ccSGreg Roach { 1190*d45701ccSGreg Roach preg_match_all('/\n\d SUBM @(' . Gedcom::REGEX_XREF . ')@/', $record->gedcom(), $matches); 1191*d45701ccSGreg Roach 1192*d45701ccSGreg Roach foreach ($matches[1] as $xref) { 1193*d45701ccSGreg Roach $submitter = Registry::submitterFactory()->make($xref, $record->tree()); 1194*d45701ccSGreg Roach 1195*d45701ccSGreg Roach if ($submitter instanceof Submitter && $submitter->canShow()) { 1196*d45701ccSGreg Roach $this->addSubmitterToCart($submitter); 1197*d45701ccSGreg Roach } 1198*d45701ccSGreg Roach } 11995a78cd34SGreg Roach } 12008c2e8227SGreg Roach} 1201