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