1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees; 19 20use Fisharebest\Webtrees\Functions\FunctionsPrintFacts; 21use Illuminate\Database\Capsule\Manager as DB; 22 23/** 24 * A GEDCOM media (OBJE) object. 25 */ 26class Media extends GedcomRecord 27{ 28 const RECORD_TYPE = 'OBJE'; 29 const ROUTE_NAME = 'media'; 30 31 /** 32 * Get an instance of a media object. For single records, 33 * we just receive the XREF. For bulk records (such as lists 34 * and search results) we can receive the GEDCOM data as well. 35 * 36 * @param string $xref 37 * @param Tree $tree 38 * @param string|null $gedcom 39 * 40 * @throws \Exception 41 * 42 * @return Media|null 43 */ 44 public static function getInstance(string $xref, Tree $tree, string $gedcom = null) 45 { 46 $record = parent::getInstance($xref, $tree, $gedcom); 47 48 if ($record instanceof Media) { 49 return $record; 50 } 51 52 return null; 53 } 54 55 /** 56 * Each object type may have its own special rules, and re-implement this function. 57 * 58 * @param int $access_level 59 * 60 * @return bool 61 */ 62 protected function canShowByType(int $access_level): bool 63 { 64 // Hide media objects if they are attached to private records 65 $linked_ids = Database::prepare( 66 "SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?" 67 )->execute([ 68 $this->xref, 69 $this->tree->id(), 70 ])->fetchOneColumn(); 71 foreach ($linked_ids as $linked_id) { 72 $linked_record = GedcomRecord::getInstance($linked_id, $this->tree); 73 if ($linked_record && !$linked_record->canShow($access_level)) { 74 return false; 75 } 76 } 77 78 // ... otherwise apply default behaviour 79 return parent::canShowByType($access_level); 80 } 81 82 /** 83 * Fetch data from the database 84 * 85 * @param string $xref 86 * @param int $tree_id 87 * 88 * @return null|string 89 */ 90 protected static function fetchGedcomRecord(string $xref, int $tree_id) 91 { 92 return DB::table('media') 93 ->where('m_id', '=', $xref) 94 ->where('m_file', '=', $tree_id) 95 ->value('m_gedcom'); 96 } 97 98 /** 99 * Get the media files for this media object 100 * 101 * @return MediaFile[] 102 */ 103 public function mediaFiles(): array 104 { 105 $media_files = []; 106 107 foreach ($this->facts(['FILE']) as $fact) { 108 $media_files[] = new MediaFile($fact->gedcom(), $this); 109 } 110 111 return $media_files; 112 } 113 114 /** 115 * Get the first media file that contains an image. 116 * 117 * @return MediaFile|null 118 */ 119 public function firstImageFile() 120 { 121 foreach ($this->mediaFiles() as $media_file) { 122 if ($media_file->isImage()) { 123 return $media_file; 124 } 125 } 126 127 return null; 128 } 129 130 /** 131 * Get the first note attached to this media object 132 * 133 * @return string 134 */ 135 public function getNote() 136 { 137 $fact = $this->getFirstFact('NOTE'); 138 if ($fact instanceof Fact) { 139 // Link to note object 140 $note = $fact->target(); 141 if ($note instanceof Note) { 142 return $note->getNote(); 143 } 144 145 // Inline note 146 return $fact->value(); 147 } 148 149 return ''; 150 } 151 152 /** 153 * Extract names from the GEDCOM record. 154 * 155 * @return void 156 */ 157 public function extractNames() 158 { 159 $names = []; 160 foreach ($this->mediaFiles() as $media_file) { 161 $names[] = $media_file->title(); 162 } 163 foreach ($this->mediaFiles() as $media_file) { 164 $names[] = $media_file->filename(); 165 } 166 $names = array_filter(array_unique($names)); 167 168 if (empty($names)) { 169 $names[] = $this->getFallBackName(); 170 } 171 172 foreach ($names as $name) { 173 $this->addName(static::RECORD_TYPE, $name, ''); 174 } 175 } 176 177 /** 178 * This function should be redefined in derived classes to show any major 179 * identifying characteristics of this record. 180 * 181 * @return string 182 */ 183 public function formatListDetails(): string 184 { 185 ob_start(); 186 FunctionsPrintFacts::printMediaLinks($this->tree(), '1 OBJE @' . $this->xref() . '@', 1); 187 188 return ob_get_clean(); 189 } 190 191 /** 192 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox. 193 * 194 * @param int $width Pixels 195 * @param int $height Pixels 196 * @param string $fit "crop" or "contain" 197 * @param string[] $attributes Additional HTML attributes 198 * 199 * @return string 200 */ 201 public function displayImage($width, $height, $fit, $attributes = []): string 202 { 203 // Display the first image 204 foreach ($this->mediaFiles() as $media_file) { 205 if ($media_file->isImage()) { 206 return $media_file->displayImage($width, $height, $fit, $attributes); 207 } 208 } 209 210 // Display the first file of any type 211 foreach ($this->mediaFiles() as $media_file) { 212 return $media_file->displayImage($width, $height, $fit, $attributes); 213 } 214 215 // No image? 216 return ''; 217 } 218} 219