xref: /webtrees/app/Media.php (revision 449b311ecf65f677a2595e1e29f712d11ef22f34)
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'])
72f25fc0f9SGreg 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     */
78*1ff45046SGreg Roach    public function firstImageFile(): MediaFile|null
79c1010edaSGreg Roach    {
8019d319e7SGreg Roach        return $this->mediaFiles()
81f25fc0f9SGreg Roach            ->first(static fn (MediaFile $media_file): bool => $media_file->isImage() && !$media_file->isExternal());
828f5f5da8SGreg Roach    }
838f5f5da8SGreg Roach
848f5f5da8SGreg Roach    /**
85a25f0a04SGreg Roach     * Get the first note attached to this media object
86a25f0a04SGreg Roach     *
87ff166e64SGreg Roach     * @return string
88a25f0a04SGreg Roach     */
89e364afe4SGreg Roach    public function getNote(): string
90c1010edaSGreg Roach    {
91820b62dfSGreg Roach        $fact = $this->facts(['NOTE'])->first();
92820b62dfSGreg Roach
93e24444eeSGreg Roach        if ($fact instanceof Fact) {
94e24444eeSGreg Roach            // Link to note object
95dc124885SGreg Roach            $note = $fact->target();
96e24444eeSGreg Roach            if ($note instanceof Note) {
97e24444eeSGreg Roach                return $note->getNote();
98a25f0a04SGreg Roach            }
99a25f0a04SGreg Roach
100e24444eeSGreg Roach            // Inline note
10184586c02SGreg Roach            return $fact->value();
102a25f0a04SGreg Roach        }
103b2ce94c6SRico Sonntag
104b2ce94c6SRico Sonntag        return '';
105a25f0a04SGreg Roach    }
106a25f0a04SGreg Roach
107a25f0a04SGreg Roach    /**
10876692c8bSGreg Roach     * Extract names from the GEDCOM record.
109c7ff4153SGreg Roach     *
110c7ff4153SGreg Roach     * @return void
11176692c8bSGreg Roach     */
112e364afe4SGreg Roach    public function extractNames(): void
113c1010edaSGreg Roach    {
11464b90bf1SGreg Roach        $names = [];
11564b90bf1SGreg Roach        foreach ($this->mediaFiles() as $media_file) {
11664b90bf1SGreg Roach            $names[] = $media_file->title();
11792d61e73SGreg Roach        }
118ddb713e4SGreg Roach
1193532071dSGreg Roach        // Titles may be empty.
1203532071dSGreg Roach        $names = array_filter($names);
1213532071dSGreg Roach
122ddb713e4SGreg Roach        if ($names === []) {
12392d61e73SGreg Roach            foreach ($this->mediaFiles() as $media_file) {
12464b90bf1SGreg Roach                $names[] = $media_file->filename();
12564b90bf1SGreg Roach            }
126ddb713e4SGreg Roach        }
127ddb713e4SGreg Roach
1283532071dSGreg Roach        // Name and title may be the same.
1293532071dSGreg Roach        $names = array_unique($names);
13064b90bf1SGreg Roach
1313532071dSGreg Roach        // No media files in this media object?
13254c1ab5eSGreg Roach        if ($names === []) {
13364b90bf1SGreg Roach            $names[] = $this->getFallBackName();
13464b90bf1SGreg Roach        }
13564b90bf1SGreg Roach
13664b90bf1SGreg Roach        foreach ($names as $name) {
13776f666f4SGreg Roach            $this->addName(static::RECORD_TYPE, $name, '');
13864b90bf1SGreg Roach        }
139a25f0a04SGreg Roach    }
140a25f0a04SGreg Roach
14176692c8bSGreg Roach    /**
14276692c8bSGreg Roach     * This function should be redefined in derived classes to show any major
14376692c8bSGreg Roach     * identifying characteristics of this record.
14476692c8bSGreg Roach     *
14576692c8bSGreg Roach     * @return string
14676692c8bSGreg Roach     */
1478f53f488SRico Sonntag    public function formatListDetails(): string
148c1010edaSGreg Roach    {
149b315f3e1SGreg Roach        return (new XrefMedia(I18N::translate('Media')))
150b315f3e1SGreg Roach            ->labelValue('@' . $this->xref . '@', $this->tree());
151a25f0a04SGreg Roach    }
15291eef4ffSGreg Roach
15391eef4ffSGreg Roach    /**
15491eef4ffSGreg Roach     * Display an image-thumbnail or a media-icon, and add markup for image viewers such as colorbox.
15591eef4ffSGreg Roach     *
15691eef4ffSGreg Roach     * @param int                  $width      Pixels
15791eef4ffSGreg Roach     * @param int                  $height     Pixels
15891eef4ffSGreg Roach     * @param string               $fit        "crop" or "contain"
15924f2a3afSGreg Roach     * @param array<string,string> $attributes Additional HTML attributes
16091eef4ffSGreg Roach     *
16191eef4ffSGreg Roach     * @return string
16291eef4ffSGreg Roach     */
1637b0d562eSGreg Roach    public function displayImage(int $width, int $height, string $fit, array $attributes): string
164c1010edaSGreg Roach    {
16591eef4ffSGreg Roach        // Display the first image
16691eef4ffSGreg Roach        foreach ($this->mediaFiles() as $media_file) {
16791eef4ffSGreg Roach            if ($media_file->isImage()) {
16891eef4ffSGreg Roach                return $media_file->displayImage($width, $height, $fit, $attributes);
16991eef4ffSGreg Roach            }
17091eef4ffSGreg Roach        }
17191eef4ffSGreg Roach
17291eef4ffSGreg Roach        // Display the first file of any type
17319d319e7SGreg Roach        $media_file = $this->mediaFiles()->first();
17419d319e7SGreg Roach
17519d319e7SGreg Roach        if ($media_file instanceof MediaFile) {
17691eef4ffSGreg Roach            return $media_file->displayImage($width, $height, $fit, $attributes);
17791eef4ffSGreg Roach        }
17891eef4ffSGreg Roach
17991eef4ffSGreg Roach        // No image?
18091eef4ffSGreg Roach        return '';
18191eef4ffSGreg Roach    }
1828091bfd1SGreg Roach
1838091bfd1SGreg Roach    /**
1848091bfd1SGreg Roach     * Lock the database row, to prevent concurrent edits.
1858091bfd1SGreg Roach     */
1868091bfd1SGreg Roach    public function lock(): void
1878091bfd1SGreg Roach    {
1888091bfd1SGreg Roach        DB::table('media')
1898091bfd1SGreg Roach            ->where('m_file', '=', $this->tree->id())
1908091bfd1SGreg Roach            ->where('m_id', '=', $this->xref())
1918091bfd1SGreg Roach            ->lockForUpdate()
1928091bfd1SGreg Roach            ->get();
1938091bfd1SGreg Roach    }
194a25f0a04SGreg Roach}
195