xref: /webtrees/app/Media.php (revision d32a32162970e6bfef5abe5397602a75311438d3)
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