14b3ef6caSGreg Roach<?php 24b3ef6caSGreg Roach 34b3ef6caSGreg Roach/** 44b3ef6caSGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 64b3ef6caSGreg Roach * This program is free software: you can redistribute it and/or modify 74b3ef6caSGreg Roach * it under the terms of the GNU General Public License as published by 84b3ef6caSGreg Roach * the Free Software Foundation, either version 3 of the License, or 94b3ef6caSGreg Roach * (at your option) any later version. 104b3ef6caSGreg Roach * This program is distributed in the hope that it will be useful, 114b3ef6caSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 124b3ef6caSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 134b3ef6caSGreg Roach * GNU General Public License for more details. 144b3ef6caSGreg Roach * You should have received a copy of the GNU General Public License 154b3ef6caSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 164b3ef6caSGreg Roach */ 174b3ef6caSGreg Roach 184b3ef6caSGreg Roachdeclare(strict_types=1); 194b3ef6caSGreg Roach 204b3ef6caSGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 214b3ef6caSGreg Roach 226f4ec3caSGreg Roachuse Fisharebest\Webtrees\DB; 234b3ef6caSGreg Roachuse Fisharebest\Webtrees\Fact; 244b3ef6caSGreg Roachuse Fisharebest\Webtrees\Gedcom; 254b3ef6caSGreg Roachuse Fisharebest\Webtrees\Registry; 264b3ef6caSGreg Roachuse Fisharebest\Webtrees\Services\DatatablesService; 274b3ef6caSGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 28748dbe15SGreg Roachuse Fisharebest\Webtrees\Validator; 294b3ef6caSGreg Roachuse Illuminate\Database\Query\Expression; 304b3ef6caSGreg Roachuse Illuminate\Database\Query\JoinClause; 314b3ef6caSGreg Roachuse Illuminate\Support\Collection; 324b3ef6caSGreg Roachuse Psr\Http\Message\ResponseInterface; 334b3ef6caSGreg Roachuse Psr\Http\Message\ServerRequestInterface; 344b3ef6caSGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 354b3ef6caSGreg Roach 364b3ef6caSGreg Roachuse function addcslashes; 374b3ef6caSGreg Roachuse function e; 384b3ef6caSGreg Roachuse function in_array; 394b3ef6caSGreg Roachuse function preg_match; 404b3ef6caSGreg Roachuse function view; 414b3ef6caSGreg Roach 424b3ef6caSGreg Roach/** 434b3ef6caSGreg Roach * Move media links from records to facts. 444b3ef6caSGreg Roach */ 454b3ef6caSGreg Roachclass FixLevel0MediaData implements RequestHandlerInterface 464b3ef6caSGreg Roach{ 47c4943cffSGreg Roach private DatatablesService $datatables_service; 484b3ef6caSGreg Roach 49c4943cffSGreg Roach private TreeService $tree_service; 504b3ef6caSGreg Roach 514b3ef6caSGreg Roach /** 524b3ef6caSGreg Roach * FixLevel0MediaController constructor. 534b3ef6caSGreg Roach * 544b3ef6caSGreg Roach * @param DatatablesService $datatables_service 554b3ef6caSGreg Roach * @param TreeService $tree_service 564b3ef6caSGreg Roach */ 574b3ef6caSGreg Roach public function __construct(DatatablesService $datatables_service, TreeService $tree_service) 584b3ef6caSGreg Roach { 594b3ef6caSGreg Roach $this->datatables_service = $datatables_service; 604b3ef6caSGreg Roach $this->tree_service = $tree_service; 614b3ef6caSGreg Roach } 624b3ef6caSGreg Roach 634b3ef6caSGreg Roach /** 644b3ef6caSGreg Roach * If media objects are wronly linked to top-level records, reattach them 654b3ef6caSGreg Roach * to facts/events. 664b3ef6caSGreg Roach * 674b3ef6caSGreg Roach * @param ServerRequestInterface $request 684b3ef6caSGreg Roach * 694b3ef6caSGreg Roach * @return ResponseInterface 704b3ef6caSGreg Roach */ 714b3ef6caSGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 724b3ef6caSGreg Roach { 734b3ef6caSGreg Roach $ignore_facts = [ 74d0889c63SGreg Roach 'INDI:NAME', 75d0889c63SGreg Roach 'INDI:SEX', 76d0889c63SGreg Roach 'INDI:CHAN', 77d0889c63SGreg Roach 'INDI:NOTE', 78d0889c63SGreg Roach 'INDI:SOUR', 79d0889c63SGreg Roach 'INDI:SUBM', 80d0889c63SGreg Roach 'INDI:RESN', 814b3ef6caSGreg Roach ]; 824b3ef6caSGreg Roach 83*211018abSGreg Roach $prefix = DB::prefix(); 844b3ef6caSGreg Roach 85748dbe15SGreg Roach $search = Validator::queryParams($request)->array('search')['value'] ?? ''; 86748dbe15SGreg Roach 874b3ef6caSGreg Roach $query = DB::table('media') 884b3ef6caSGreg Roach ->join('media_file', static function (JoinClause $join): void { 894b3ef6caSGreg Roach $join 904b3ef6caSGreg Roach ->on('media_file.m_file', '=', 'media.m_file') 914b3ef6caSGreg Roach ->on('media_file.m_id', '=', 'media.m_id'); 924b3ef6caSGreg Roach }) 934b3ef6caSGreg Roach ->join('link', static function (JoinClause $join): void { 944b3ef6caSGreg Roach $join 954b3ef6caSGreg Roach ->on('link.l_file', '=', 'media.m_file') 964b3ef6caSGreg Roach ->on('link.l_to', '=', 'media.m_id') 974b3ef6caSGreg Roach ->where('link.l_type', '=', 'OBJE'); 984b3ef6caSGreg Roach }) 994b3ef6caSGreg Roach ->join('individuals', static function (JoinClause $join): void { 1004b3ef6caSGreg Roach $join 1014b3ef6caSGreg Roach ->on('individuals.i_file', '=', 'link.l_file') 1024b3ef6caSGreg Roach ->on('individuals.i_id', '=', 'link.l_from'); 1034b3ef6caSGreg Roach }) 1044b3ef6caSGreg Roach ->where('i_gedcom', 'LIKE', new Expression("('%\n1 OBJE @' || " . $prefix . "media.m_id || '@%')")) 1054b3ef6caSGreg Roach ->orderBy('individuals.i_file') 1064b3ef6caSGreg Roach ->orderBy('individuals.i_id') 1074b3ef6caSGreg Roach ->orderBy('media.m_id') 108748dbe15SGreg Roach ->where('descriptive_title', 'LIKE', '%' . addcslashes($search, '\\%_') . '%') 1094b3ef6caSGreg Roach ->select(['media.m_file', 'media.m_id', 'media.m_gedcom', 'individuals.i_id', 'individuals.i_gedcom']); 1104b3ef6caSGreg Roach 111f70bcff5SGreg Roach return $this->datatables_service->handleQuery($request, $query, [], [], function (object $datum) use ($ignore_facts): array { 1124b3ef6caSGreg Roach $tree = $this->tree_service->find((int) $datum->m_file); 1134b3ef6caSGreg Roach $media = Registry::mediaFactory()->make($datum->m_id, $tree, $datum->m_gedcom); 1144b3ef6caSGreg Roach $individual = Registry::individualFactory()->make($datum->i_id, $tree, $datum->i_gedcom); 1154b3ef6caSGreg Roach 116f25fc0f9SGreg Roach $facts = $individual 117f25fc0f9SGreg Roach ->facts([], true) 118f25fc0f9SGreg Roach ->filter(static fn (Fact $fact): bool => !$fact->isPendingDeletion() && 1194b3ef6caSGreg Roach !preg_match('/^@' . Gedcom::REGEX_XREF . '@$/', $fact->value()) && 120f25fc0f9SGreg Roach !in_array($fact->tag(), $ignore_facts, true)); 1214b3ef6caSGreg Roach 1224b3ef6caSGreg Roach // The link to the media object may have been deleted in a pending change. 1234b3ef6caSGreg Roach $deleted = true; 1244b3ef6caSGreg Roach foreach ($individual->facts(['OBJE']) as $fact) { 1254b3ef6caSGreg Roach if ($fact->target() === $media && !$fact->isPendingDeletion()) { 1264b3ef6caSGreg Roach $deleted = false; 1274b3ef6caSGreg Roach } 1284b3ef6caSGreg Roach } 1294b3ef6caSGreg Roach if ($deleted) { 1304b3ef6caSGreg Roach $facts = new Collection(); 1314b3ef6caSGreg Roach } 1324b3ef6caSGreg Roach 133f25fc0f9SGreg Roach $facts = $facts->map(static fn (Fact $fact): string => view('admin/fix-level-0-media-action', [ 1344b3ef6caSGreg Roach 'fact' => $fact, 1354b3ef6caSGreg Roach 'individual' => $individual, 1364b3ef6caSGreg Roach 'media' => $media, 137f25fc0f9SGreg Roach ])); 1384b3ef6caSGreg Roach 1394b3ef6caSGreg Roach return [ 1404b3ef6caSGreg Roach $tree->name(), 1414b3ef6caSGreg Roach $media->displayImage(100, 100, 'contain', ['class' => 'img-thumbnail']), 1424b3ef6caSGreg Roach '<a href="' . e($media->url()) . '">' . $media->fullName() . '</a>', 1434b3ef6caSGreg Roach '<a href="' . e($individual->url()) . '">' . $individual->fullName() . '</a>', 1444b3ef6caSGreg Roach $facts->implode(' '), 1454b3ef6caSGreg Roach ]; 1464b3ef6caSGreg Roach }); 1474b3ef6caSGreg Roach } 1484b3ef6caSGreg Roach} 149