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($xref, Tree $tree, $gedcom = null) 42 { 43 $record = parent::getInstance($xref, $tree, $gedcom); 44 45 if ($record instanceof Media) { 46 return $record; 47 } else { 48 return null; 49 } 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($access_level) 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($xref, $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 } else { 145 return ''; 146 } 147 } 148 149 /** 150 * Extract names from the GEDCOM record. 151 */ 152 public function extractNames() 153 { 154 $names = []; 155 foreach ($this->mediaFiles() as $media_file) { 156 $names[] = $media_file->title(); 157 } 158 foreach ($this->mediaFiles() as $media_file) { 159 $names[] = $media_file->filename(); 160 } 161 $names = array_filter(array_unique($names)); 162 163 if (empty($names)) { 164 $names[] = $this->getFallBackName(); 165 } 166 167 foreach ($names as $name) { 168 $this->addName(static::RECORD_TYPE, $name, null); 169 } 170 } 171 172 /** 173 * This function should be redefined in derived classes to show any major 174 * identifying characteristics of this record. 175 * 176 * @return string 177 */ 178 public function formatListDetails() 179 { 180 ob_start(); 181 FunctionsPrintFacts::printMediaLinks($this->getTree(), '1 OBJE @' . $this->getXref() . '@', 1); 182 183 return ob_get_clean(); 184 } 185 186 /** 187 * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox. 188 * 189 * @param int $width Pixels 190 * @param int $height Pixels 191 * @param string $fit "crop" or "contain" 192 * @param string[] $attributes Additional HTML attributes 193 * 194 * @return string 195 */ 196 public function displayImage($width, $height, $fit, $attributes = []) 197 { 198 // Display the first image 199 foreach ($this->mediaFiles() as $media_file) { 200 if ($media_file->isImage()) { 201 return $media_file->displayImage($width, $height, $fit, $attributes); 202 } 203 } 204 205 // Display the first file of any type 206 foreach ($this->mediaFiles() as $media_file) { 207 return $media_file->displayImage($width, $height, $fit, $attributes); 208 } 209 210 // No image? 211 return ''; 212 } 213} 214