1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 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 */ 16namespace Fisharebest\Webtrees; 17 18use Fisharebest\Webtrees\Functions\FunctionsPrintFacts; 19 20/** 21 * A GEDCOM media (OBJE) object. 22 */ 23class Media extends GedcomRecord 24{ 25 const RECORD_TYPE = 'OBJE'; 26 const ROUTE_NAME = 'media'; 27 28 /** 29 * Get an instance of a media object. For single records, 30 * we just receive the XREF. For bulk records (such as lists 31 * and search results) we can receive the GEDCOM data as well. 32 * 33 * @param string $xref 34 * @param Tree $tree 35 * @param string|null $gedcom 36 * 37 * @throws \Exception 38 * 39 * @return Media|null 40 */ 41 public static function getInstance(string $xref, Tree $tree, string $gedcom = null) 42 { 43 $record = parent::getInstance($xref, $tree, $gedcom); 44 45 if ($record instanceof Media) { 46 return $record; 47 } 48 49 return null; 50 } 51 52 /** 53 * Each object type may have its own special rules, and re-implement this function. 54 * 55 * @param int $access_level 56 * 57 * @return bool 58 */ 59 protected function canShowByType(int $access_level): bool 60 { 61 // Hide media objects if they are attached to private records 62 $linked_ids = Database::prepare( 63 "SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?" 64 )->execute([ 65 $this->xref, 66 $this->tree->getTreeId(), 67 ])->fetchOneColumn(); 68 foreach ($linked_ids as $linked_id) { 69 $linked_record = GedcomRecord::getInstance($linked_id, $this->tree); 70 if ($linked_record && !$linked_record->canShow($access_level)) { 71 return false; 72 } 73 } 74 75 // ... otherwise apply default behaviour 76 return parent::canShowByType($access_level); 77 } 78 79 /** 80 * Fetch data from the database 81 * 82 * @param string $xref 83 * @param int $tree_id 84 * 85 * @return null|string 86 */ 87 protected static function fetchGedcomRecord(string $xref, int $tree_id) 88 { 89 return Database::prepare( 90 "SELECT m_gedcom FROM `##media` WHERE m_id = :xref AND m_file = :tree_id" 91 )->execute([ 92 'xref' => $xref, 93 'tree_id' => $tree_id, 94 ])->fetchOne(); 95 } 96 97 /** 98 * Get the media files for this media object 99 * 100 * @return MediaFile[] 101 */ 102 public function mediaFiles(): array 103 { 104 $media_files = []; 105 106 foreach ($this->getFacts('FILE') as $fact) { 107 $media_files[] = new MediaFile($fact->getGedcom(), $this); 108 } 109 110 return $media_files; 111 } 112 113 /** 114 * Get the first media file that contains an image. 115 * 116 * @return MediaFile|null 117 */ 118 public function firstImageFile() 119 { 120 foreach ($this->mediaFiles() as $media_file) { 121 if ($media_file->isImage()) { 122 return $media_file; 123 } 124 } 125 126 return null; 127 } 128 129 /** 130 * Get the first note attached to this media object 131 * 132 * @return null|string 133 */ 134 public function getNote() 135 { 136 $note = $this->getFirstFact('NOTE'); 137 if ($note) { 138 $text = $note->getValue(); 139 if (preg_match('/^@' . WT_REGEX_XREF . '@$/', $text)) { 140 $text = $note->getTarget()->getNote(); 141 } 142 143 return $text; 144 } 145 146 return ''; 147 } 148 149 /** 150 * Extract names from the GEDCOM record. 151 * 152 * @return void 153 */ 154 public function extractNames() 155 { 156 $names = []; 157 foreach ($this->mediaFiles() as $media_file) { 158 $names[] = $media_file->title(); 159 } 160 foreach ($this->mediaFiles() as $media_file) { 161 $names[] = $media_file->filename(); 162 } 163 $names = array_filter(array_unique($names)); 164 165 if (empty($names)) { 166 $names[] = $this->getFallBackName(); 167 } 168 169 foreach ($names as $name) { 170 $this->addName(static::RECORD_TYPE, $name, ''); 171 } 172 } 173 174 /** 175 * This function should be redefined in derived classes to show any major 176 * identifying characteristics of this record. 177 * 178 * @return string 179 */ 180 public function formatListDetails(): string 181 { 182 ob_start(); 183 FunctionsPrintFacts::printMediaLinks($this->getTree(), '1 OBJE @' . $this->getXref() . '@', 1); 184 185 return ob_get_clean(); 186 } 187 188 /** 189 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox. 190 * 191 * @param int $width Pixels 192 * @param int $height Pixels 193 * @param string $fit "crop" or "contain" 194 * @param string[] $attributes Additional HTML attributes 195 * 196 * @return string 197 */ 198 public function displayImage($width, $height, $fit, $attributes = []): string 199 { 200 // Display the first image 201 foreach ($this->mediaFiles() as $media_file) { 202 if ($media_file->isImage()) { 203 return $media_file->displayImage($width, $height, $fit, $attributes); 204 } 205 } 206 207 // Display the first file of any type 208 foreach ($this->mediaFiles() as $media_file) { 209 return $media_file->displayImage($width, $height, $fit, $attributes); 210 } 211 212 // No image? 213 return ''; 214 } 215} 216