xref: /webtrees/app/Media.php (revision f25fc0f929f69ab8124cf0cecde45e457db7574a)
1a25f0a04SGreg Roach<?php
23976b470SGreg Roach
3a25f0a04SGreg Roach/**
4a25f0a04SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 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;
24e778de49SGreg Roachuse Illuminate\Support\Collection;
25a25f0a04SGreg Roach
263532071dSGreg Roachuse function array_filter;
273532071dSGreg Roachuse function array_unique;
283532071dSGreg Roach
29a25f0a04SGreg Roach/**
3076692c8bSGreg Roach * A GEDCOM media (OBJE) object.
31a25f0a04SGreg Roach */
32c1010edaSGreg Roachclass Media extends GedcomRecord
33c1010edaSGreg Roach{
3416d6367aSGreg Roach    public const RECORD_TYPE = 'OBJE';
3516d6367aSGreg Roach
36d7daee59SGreg Roach    protected const ROUTE_NAME = MediaPage::class;
37a25f0a04SGreg Roach
3876692c8bSGreg Roach    /**
3976692c8bSGreg Roach     * Each object type may have its own special rules, and re-implement this function.
4076692c8bSGreg Roach     *
4176692c8bSGreg Roach     * @param int $access_level
4276692c8bSGreg Roach     *
4376692c8bSGreg Roach     * @return bool
4476692c8bSGreg Roach     */
4535584196SGreg Roach    protected function canShowByType(int $access_level): bool
46c1010edaSGreg Roach    {
47a25f0a04SGreg Roach        // Hide media objects if they are attached to private records
4825366223SGreg Roach        $linked_ids = DB::table('link')
4925366223SGreg Roach            ->where('l_file', '=', $this->tree->id())
5025366223SGreg Roach            ->where('l_to', '=', $this->xref)
5125366223SGreg Roach            ->pluck('l_from');
5225366223SGreg Roach
53a25f0a04SGreg Roach        foreach ($linked_ids as $linked_id) {
546b9cb339SGreg Roach            $linked_record = Registry::gedcomRecordFactory()->make($linked_id, $this->tree);
55bb03c9f0SGreg Roach            if ($linked_record instanceof GedcomRecord && !$linked_record->canShow($access_level)) {
56a25f0a04SGreg Roach                return false;
57a25f0a04SGreg Roach            }
58a25f0a04SGreg Roach        }
59a25f0a04SGreg Roach
60b3a775f6SGreg Roach        // ... otherwise apply default behavior
61a25f0a04SGreg Roach        return parent::canShowByType($access_level);
62a25f0a04SGreg Roach    }
63a25f0a04SGreg Roach
6476692c8bSGreg Roach    /**
658f5f5da8SGreg Roach     * Get the media files for this media object
668f5f5da8SGreg Roach     *
6736779af1SGreg Roach     * @return Collection<int,MediaFile>
688f5f5da8SGreg Roach     */
69e778de49SGreg Roach    public function mediaFiles(): Collection
70c1010edaSGreg Roach    {
7139ca88baSGreg Roach        return $this->facts(['FILE'])
72*f25fc0f9SGreg Roach            ->map(fn(Fact $fact): MediaFile => new MediaFile($fact->gedcom(), $this));
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()
83*f25fc0f9SGreg Roach            ->first(static fn(MediaFile $media_file): bool => $media_file->isImage() && !$media_file->isExternal());
848f5f5da8SGreg Roach    }
858f5f5da8SGreg Roach
868f5f5da8SGreg Roach    /**
87a25f0a04SGreg Roach     * Get the first note attached to this media object
88a25f0a04SGreg Roach     *
89ff166e64SGreg Roach     * @return string
90a25f0a04SGreg Roach     */
91e364afe4SGreg Roach    public function getNote(): string
92c1010edaSGreg Roach    {
93820b62dfSGreg Roach        $fact = $this->facts(['NOTE'])->first();
94820b62dfSGreg Roach
95e24444eeSGreg Roach        if ($fact instanceof Fact) {
96e24444eeSGreg Roach            // Link to note object
97dc124885SGreg Roach            $note = $fact->target();
98e24444eeSGreg Roach            if ($note instanceof Note) {
99e24444eeSGreg Roach                return $note->getNote();
100a25f0a04SGreg Roach            }
101a25f0a04SGreg Roach
102e24444eeSGreg Roach            // Inline note
10384586c02SGreg Roach            return $fact->value();
104a25f0a04SGreg Roach        }
105b2ce94c6SRico Sonntag
106b2ce94c6SRico Sonntag        return '';
107a25f0a04SGreg Roach    }
108a25f0a04SGreg Roach
109a25f0a04SGreg Roach    /**
11076692c8bSGreg Roach     * Extract names from the GEDCOM record.
111c7ff4153SGreg Roach     *
112c7ff4153SGreg Roach     * @return void
11376692c8bSGreg Roach     */
114e364afe4SGreg Roach    public function extractNames(): void
115c1010edaSGreg Roach    {
11664b90bf1SGreg Roach        $names = [];
11764b90bf1SGreg Roach        foreach ($this->mediaFiles() as $media_file) {
11864b90bf1SGreg Roach            $names[] = $media_file->title();
11992d61e73SGreg Roach        }
120ddb713e4SGreg Roach
1213532071dSGreg Roach        // Titles may be empty.
1223532071dSGreg Roach        $names = array_filter($names);
1233532071dSGreg Roach
124ddb713e4SGreg Roach        if ($names === []) {
12592d61e73SGreg Roach            foreach ($this->mediaFiles() as $media_file) {
12664b90bf1SGreg Roach                $names[] = $media_file->filename();
12764b90bf1SGreg Roach            }
128ddb713e4SGreg Roach        }
129ddb713e4SGreg Roach
1303532071dSGreg Roach        // Name and title may be the same.
1313532071dSGreg Roach        $names = array_unique($names);
13264b90bf1SGreg Roach
1333532071dSGreg Roach        // No media files in this media object?
13454c1ab5eSGreg Roach        if ($names === []) {
13564b90bf1SGreg Roach            $names[] = $this->getFallBackName();
13664b90bf1SGreg Roach        }
13764b90bf1SGreg Roach
13864b90bf1SGreg Roach        foreach ($names as $name) {
13976f666f4SGreg Roach            $this->addName(static::RECORD_TYPE, $name, '');
14064b90bf1SGreg Roach        }
141a25f0a04SGreg Roach    }
142a25f0a04SGreg Roach
14376692c8bSGreg Roach    /**
14476692c8bSGreg Roach     * This function should be redefined in derived classes to show any major
14576692c8bSGreg Roach     * identifying characteristics of this record.
14676692c8bSGreg Roach     *
14776692c8bSGreg Roach     * @return string
14876692c8bSGreg Roach     */
1498f53f488SRico Sonntag    public function formatListDetails(): string
150c1010edaSGreg Roach    {
151b315f3e1SGreg Roach        return (new XrefMedia(I18N::translate('Media')))
152b315f3e1SGreg Roach            ->labelValue('@' . $this->xref . '@', $this->tree());
153a25f0a04SGreg Roach    }
15491eef4ffSGreg Roach
15591eef4ffSGreg Roach    /**
15691eef4ffSGreg Roach     * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
15791eef4ffSGreg Roach     *
15891eef4ffSGreg Roach     * @param int                  $width      Pixels
15991eef4ffSGreg Roach     * @param int                  $height     Pixels
16091eef4ffSGreg Roach     * @param string               $fit        "crop" or "contain"
16124f2a3afSGreg Roach     * @param array<string,string> $attributes Additional HTML attributes
16291eef4ffSGreg Roach     *
16391eef4ffSGreg Roach     * @return string
16491eef4ffSGreg Roach     */
1657b0d562eSGreg Roach    public function displayImage(int $width, int $height, string $fit, array $attributes): string
166c1010edaSGreg Roach    {
16791eef4ffSGreg Roach        // Display the first image
16891eef4ffSGreg Roach        foreach ($this->mediaFiles() as $media_file) {
16991eef4ffSGreg Roach            if ($media_file->isImage()) {
17091eef4ffSGreg Roach                return $media_file->displayImage($width, $height, $fit, $attributes);
17191eef4ffSGreg Roach            }
17291eef4ffSGreg Roach        }
17391eef4ffSGreg Roach
17491eef4ffSGreg Roach        // Display the first file of any type
17519d319e7SGreg Roach        $media_file = $this->mediaFiles()->first();
17619d319e7SGreg Roach
17719d319e7SGreg Roach        if ($media_file instanceof MediaFile) {
17891eef4ffSGreg Roach            return $media_file->displayImage($width, $height, $fit, $attributes);
17991eef4ffSGreg Roach        }
18091eef4ffSGreg Roach
18191eef4ffSGreg Roach        // No image?
18291eef4ffSGreg Roach        return '';
18391eef4ffSGreg Roach    }
1848091bfd1SGreg Roach
1858091bfd1SGreg Roach    /**
1868091bfd1SGreg Roach     * Lock the database row, to prevent concurrent edits.
1878091bfd1SGreg Roach     */
1888091bfd1SGreg Roach    public function lock(): void
1898091bfd1SGreg Roach    {
1908091bfd1SGreg Roach        DB::table('media')
1918091bfd1SGreg Roach            ->where('m_file', '=', $this->tree->id())
1928091bfd1SGreg Roach            ->where('m_id', '=', $this->xref())
1938091bfd1SGreg Roach            ->lockForUpdate()
1948091bfd1SGreg Roach            ->get();
1958091bfd1SGreg Roach    }
196a25f0a04SGreg Roach}
197