xref: /webtrees/app/Media.php (revision 7b0d562e1536c7d515bfdb12e13250a94005b418)
1a25f0a04SGreg Roach<?php
23976b470SGreg Roach
3a25f0a04SGreg Roach/**
4a25f0a04SGreg Roach * webtrees: online genealogy
589f7189bSGreg Roach * Copyright (C) 2021 webtrees development team
6a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify
7a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by
8a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or
9a25f0a04SGreg Roach * (at your option) any later version.
10a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful,
11a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
12a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13a25f0a04SGreg Roach * GNU General Public License for more details.
14a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License
1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
16a25f0a04SGreg Roach */
17fcfa147eSGreg Roach
18e7f56f2aSGreg Roachdeclare(strict_types=1);
19e7f56f2aSGreg Roach
2076692c8bSGreg Roachnamespace Fisharebest\Webtrees;
2176692c8bSGreg Roach
22b315f3e1SGreg Roachuse Fisharebest\Webtrees\Elements\XrefMedia;
23d7daee59SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MediaPage;
242e5b4452SGreg Roachuse Illuminate\Database\Capsule\Manager as DB;
25e778de49SGreg Roachuse Illuminate\Support\Collection;
26a25f0a04SGreg Roach
27a25f0a04SGreg Roach/**
2876692c8bSGreg Roach * A GEDCOM media (OBJE) object.
29a25f0a04SGreg Roach */
30c1010edaSGreg Roachclass Media extends GedcomRecord
31c1010edaSGreg Roach{
3216d6367aSGreg Roach    public const RECORD_TYPE = 'OBJE';
3316d6367aSGreg Roach
34d7daee59SGreg Roach    protected const ROUTE_NAME = MediaPage::class;
35a25f0a04SGreg Roach
3676692c8bSGreg Roach    /**
3776692c8bSGreg Roach     * Each object type may have its own special rules, and re-implement this function.
3876692c8bSGreg Roach     *
3976692c8bSGreg Roach     * @param int $access_level
4076692c8bSGreg Roach     *
4176692c8bSGreg Roach     * @return bool
4276692c8bSGreg Roach     */
4335584196SGreg Roach    protected function canShowByType(int $access_level): bool
44c1010edaSGreg Roach    {
45a25f0a04SGreg Roach        // Hide media objects if they are attached to private records
4625366223SGreg Roach        $linked_ids = DB::table('link')
4725366223SGreg Roach            ->where('l_file', '=', $this->tree->id())
4825366223SGreg Roach            ->where('l_to', '=', $this->xref)
4925366223SGreg Roach            ->pluck('l_from');
5025366223SGreg Roach
51a25f0a04SGreg Roach        foreach ($linked_ids as $linked_id) {
526b9cb339SGreg Roach            $linked_record = Registry::gedcomRecordFactory()->make($linked_id, $this->tree);
53bb03c9f0SGreg Roach            if ($linked_record instanceof GedcomRecord && !$linked_record->canShow($access_level)) {
54a25f0a04SGreg Roach                return false;
55a25f0a04SGreg Roach            }
56a25f0a04SGreg Roach        }
57a25f0a04SGreg Roach
58b3a775f6SGreg Roach        // ... otherwise apply default behavior
59a25f0a04SGreg Roach        return parent::canShowByType($access_level);
60a25f0a04SGreg Roach    }
61a25f0a04SGreg Roach
6276692c8bSGreg Roach    /**
638f5f5da8SGreg Roach     * Get the media files for this media object
648f5f5da8SGreg Roach     *
65b5c8fd7eSGreg Roach     * @return Collection<MediaFile>
668f5f5da8SGreg Roach     */
67e778de49SGreg Roach    public function mediaFiles(): Collection
68c1010edaSGreg Roach    {
6939ca88baSGreg Roach        return $this->facts(['FILE'])
70e778de49SGreg Roach            ->map(function (Fact $fact): MediaFile {
71e778de49SGreg Roach                return new MediaFile($fact->gedcom(), $this);
72e778de49SGreg Roach            });
738f5f5da8SGreg Roach    }
748f5f5da8SGreg Roach
758f5f5da8SGreg Roach    /**
7664b90bf1SGreg Roach     * Get the first media file that contains an image.
778f5f5da8SGreg Roach     *
788f5f5da8SGreg Roach     * @return MediaFile|null
798f5f5da8SGreg Roach     */
80e364afe4SGreg Roach    public function firstImageFile(): ?MediaFile
81c1010edaSGreg Roach    {
8219d319e7SGreg Roach        return $this->mediaFiles()
8319d319e7SGreg Roach            ->first(static function (MediaFile $media_file): bool {
8419d319e7SGreg Roach                return $media_file->isImage() && !$media_file->isExternal();
8519d319e7SGreg Roach            });
868f5f5da8SGreg Roach    }
878f5f5da8SGreg Roach
888f5f5da8SGreg Roach    /**
89a25f0a04SGreg Roach     * Get the first note attached to this media object
90a25f0a04SGreg Roach     *
91ff166e64SGreg Roach     * @return string
92a25f0a04SGreg Roach     */
93e364afe4SGreg Roach    public function getNote(): string
94c1010edaSGreg Roach    {
95820b62dfSGreg Roach        $fact = $this->facts(['NOTE'])->first();
96820b62dfSGreg Roach
97e24444eeSGreg Roach        if ($fact instanceof Fact) {
98e24444eeSGreg Roach            // Link to note object
99dc124885SGreg Roach            $note = $fact->target();
100e24444eeSGreg Roach            if ($note instanceof Note) {
101e24444eeSGreg Roach                return $note->getNote();
102a25f0a04SGreg Roach            }
103a25f0a04SGreg Roach
104e24444eeSGreg Roach            // Inline note
10584586c02SGreg Roach            return $fact->value();
106a25f0a04SGreg Roach        }
107b2ce94c6SRico Sonntag
108b2ce94c6SRico Sonntag        return '';
109a25f0a04SGreg Roach    }
110a25f0a04SGreg Roach
111a25f0a04SGreg Roach    /**
11276692c8bSGreg Roach     * Extract names from the GEDCOM record.
113c7ff4153SGreg Roach     *
114c7ff4153SGreg Roach     * @return void
11576692c8bSGreg Roach     */
116e364afe4SGreg Roach    public function extractNames(): void
117c1010edaSGreg Roach    {
11864b90bf1SGreg Roach        $names = [];
11964b90bf1SGreg Roach        foreach ($this->mediaFiles() as $media_file) {
12064b90bf1SGreg Roach            $names[] = $media_file->title();
12192d61e73SGreg Roach        }
12292d61e73SGreg Roach        foreach ($this->mediaFiles() as $media_file) {
12364b90bf1SGreg Roach            $names[] = $media_file->filename();
12464b90bf1SGreg Roach        }
12564b90bf1SGreg Roach        $names = array_filter(array_unique($names));
12664b90bf1SGreg Roach
12754c1ab5eSGreg Roach        if ($names === []) {
12864b90bf1SGreg Roach            $names[] = $this->getFallBackName();
12964b90bf1SGreg Roach        }
13064b90bf1SGreg Roach
13164b90bf1SGreg Roach        foreach ($names as $name) {
13276f666f4SGreg Roach            $this->addName(static::RECORD_TYPE, $name, '');
13364b90bf1SGreg Roach        }
134a25f0a04SGreg Roach    }
135a25f0a04SGreg Roach
13676692c8bSGreg Roach    /**
13776692c8bSGreg Roach     * This function should be redefined in derived classes to show any major
13876692c8bSGreg Roach     * identifying characteristics of this record.
13976692c8bSGreg Roach     *
14076692c8bSGreg Roach     * @return string
14176692c8bSGreg Roach     */
1428f53f488SRico Sonntag    public function formatListDetails(): string
143c1010edaSGreg Roach    {
144b315f3e1SGreg Roach        return (new XrefMedia(I18N::translate('Media')))
145b315f3e1SGreg Roach            ->labelValue('@' . $this->xref . '@', $this->tree());
146a25f0a04SGreg Roach    }
14791eef4ffSGreg Roach
14891eef4ffSGreg Roach    /**
14991eef4ffSGreg Roach     * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
15091eef4ffSGreg Roach     *
15191eef4ffSGreg Roach     * @param int                  $width      Pixels
15291eef4ffSGreg Roach     * @param int                  $height     Pixels
15391eef4ffSGreg Roach     * @param string               $fit        "crop" or "contain"
15424f2a3afSGreg Roach     * @param array<string,string> $attributes Additional HTML attributes
15591eef4ffSGreg Roach     *
15691eef4ffSGreg Roach     * @return string
15791eef4ffSGreg Roach     */
158*7b0d562eSGreg Roach    public function displayImage(int $width, int $height, string $fit, array $attributes): string
159c1010edaSGreg Roach    {
16091eef4ffSGreg Roach        // Display the first image
16191eef4ffSGreg Roach        foreach ($this->mediaFiles() as $media_file) {
16291eef4ffSGreg Roach            if ($media_file->isImage()) {
16391eef4ffSGreg Roach                return $media_file->displayImage($width, $height, $fit, $attributes);
16491eef4ffSGreg Roach            }
16591eef4ffSGreg Roach        }
16691eef4ffSGreg Roach
16791eef4ffSGreg Roach        // Display the first file of any type
16819d319e7SGreg Roach        $media_file = $this->mediaFiles()->first();
16919d319e7SGreg Roach
17019d319e7SGreg Roach        if ($media_file instanceof MediaFile) {
17191eef4ffSGreg Roach            return $media_file->displayImage($width, $height, $fit, $attributes);
17291eef4ffSGreg Roach        }
17391eef4ffSGreg Roach
17491eef4ffSGreg Roach        // No image?
17591eef4ffSGreg Roach        return '';
17691eef4ffSGreg Roach    }
1778091bfd1SGreg Roach
1788091bfd1SGreg Roach    /**
1798091bfd1SGreg Roach     * Lock the database row, to prevent concurrent edits.
1808091bfd1SGreg Roach     */
1818091bfd1SGreg Roach    public function lock(): void
1828091bfd1SGreg Roach    {
1838091bfd1SGreg Roach        DB::table('media')
1848091bfd1SGreg Roach            ->where('m_file', '=', $this->tree->id())
1858091bfd1SGreg Roach            ->where('m_id', '=', $this->xref())
1868091bfd1SGreg Roach            ->lockForUpdate()
1878091bfd1SGreg Roach            ->get();
1888091bfd1SGreg Roach    }
189a25f0a04SGreg Roach}
190