18add1155SRico Sonntag<?php 23976b470SGreg Roach 38add1155SRico Sonntag/** 48add1155SRico Sonntag * webtrees: online genealogy 50dcd9387SGreg Roach * Copyright (C) 2020 webtrees development team 68add1155SRico Sonntag * This program is free software: you can redistribute it and/or modify 78add1155SRico Sonntag * it under the terms of the GNU General Public License as published by 88add1155SRico Sonntag * the Free Software Foundation, either version 3 of the License, or 98add1155SRico Sonntag * (at your option) any later version. 108add1155SRico Sonntag * This program is distributed in the hope that it will be useful, 118add1155SRico Sonntag * but WITHOUT ANY WARRANTY; without even the implied warranty of 128add1155SRico Sonntag * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138add1155SRico Sonntag * GNU General Public License for more details. 148add1155SRico Sonntag * You should have received a copy of the GNU General Public License 158add1155SRico Sonntag * along with this program. If not, see <http://www.gnu.org/licenses/>. 168add1155SRico Sonntag */ 17fcfa147eSGreg Roach 188add1155SRico Sonntagdeclare(strict_types=1); 198add1155SRico Sonntag 208add1155SRico Sonntagnamespace Fisharebest\Webtrees\Statistics\Repository; 218add1155SRico Sonntag 228add1155SRico Sonntaguse Fisharebest\Webtrees\I18N; 238add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartMedia; 248add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\Interfaces\MediaRepositoryInterface; 258add1155SRico Sonntaguse Fisharebest\Webtrees\Tree; 268add1155SRico Sonntaguse Illuminate\Database\Capsule\Manager as DB; 278add1155SRico Sonntaguse Illuminate\Database\Query\Builder; 283976b470SGreg Roach 2971378461SGreg Roachuse function array_slice; 3071378461SGreg Roachuse function count; 316ccdf4f0SGreg Roachuse function in_array; 328add1155SRico Sonntag 338add1155SRico Sonntag/** 348add1155SRico Sonntag * A repository providing methods for media type related statistics. 358add1155SRico Sonntag */ 368add1155SRico Sonntagclass MediaRepository implements MediaRepositoryInterface 378add1155SRico Sonntag{ 388add1155SRico Sonntag /** 398add1155SRico Sonntag * @var Tree 408add1155SRico Sonntag */ 418add1155SRico Sonntag private $tree; 428add1155SRico Sonntag 438add1155SRico Sonntag /** 448add1155SRico Sonntag * Available media types. 458add1155SRico Sonntag */ 468add1155SRico Sonntag private const MEDIA_TYPE_ALL = 'all'; 478add1155SRico Sonntag private const MEDIA_TYPE_AUDIO = 'audio'; 488add1155SRico Sonntag private const MEDIA_TYPE_BOOK = 'book'; 498add1155SRico Sonntag private const MEDIA_TYPE_CARD = 'card'; 508add1155SRico Sonntag private const MEDIA_TYPE_CERTIFICATE = 'certificate'; 518add1155SRico Sonntag private const MEDIA_TYPE_COAT = 'coat'; 528add1155SRico Sonntag private const MEDIA_TYPE_DOCUMENT = 'document'; 538add1155SRico Sonntag private const MEDIA_TYPE_ELECTRONIC = 'electronic'; 548add1155SRico Sonntag private const MEDIA_TYPE_FICHE = 'fiche'; 558add1155SRico Sonntag private const MEDIA_TYPE_FILM = 'film'; 568add1155SRico Sonntag private const MEDIA_TYPE_MAGAZINE = 'magazine'; 578add1155SRico Sonntag private const MEDIA_TYPE_MANUSCRIPT = 'manuscript'; 588add1155SRico Sonntag private const MEDIA_TYPE_MAP = 'map'; 598add1155SRico Sonntag private const MEDIA_TYPE_NEWSPAPER = 'newspaper'; 608add1155SRico Sonntag private const MEDIA_TYPE_PAINTING = 'painting'; 618add1155SRico Sonntag private const MEDIA_TYPE_PHOTO = 'photo'; 628add1155SRico Sonntag private const MEDIA_TYPE_TOMBSTONE = 'tombstone'; 638add1155SRico Sonntag private const MEDIA_TYPE_VIDEO = 'video'; 648add1155SRico Sonntag private const MEDIA_TYPE_OTHER = 'other'; 658add1155SRico Sonntag private const MEDIA_TYPE_UNKNOWN = 'unknown'; 668add1155SRico Sonntag 678add1155SRico Sonntag /** 688add1155SRico Sonntag * List of GEDCOM media types. 698add1155SRico Sonntag * 708add1155SRico Sonntag * @var string[] 718add1155SRico Sonntag */ 728add1155SRico Sonntag private const MEDIA_TYPES = [ 738add1155SRico Sonntag self::MEDIA_TYPE_AUDIO, 748add1155SRico Sonntag self::MEDIA_TYPE_BOOK, 758add1155SRico Sonntag self::MEDIA_TYPE_CARD, 768add1155SRico Sonntag self::MEDIA_TYPE_CERTIFICATE, 778add1155SRico Sonntag self::MEDIA_TYPE_COAT, 788add1155SRico Sonntag self::MEDIA_TYPE_DOCUMENT, 798add1155SRico Sonntag self::MEDIA_TYPE_ELECTRONIC, 808add1155SRico Sonntag self::MEDIA_TYPE_FICHE, 818add1155SRico Sonntag self::MEDIA_TYPE_FILM, 828add1155SRico Sonntag self::MEDIA_TYPE_MAGAZINE, 838add1155SRico Sonntag self::MEDIA_TYPE_MANUSCRIPT, 848add1155SRico Sonntag self::MEDIA_TYPE_MAP, 858add1155SRico Sonntag self::MEDIA_TYPE_NEWSPAPER, 868add1155SRico Sonntag self::MEDIA_TYPE_PAINTING, 878add1155SRico Sonntag self::MEDIA_TYPE_PHOTO, 888add1155SRico Sonntag self::MEDIA_TYPE_TOMBSTONE, 898add1155SRico Sonntag self::MEDIA_TYPE_VIDEO, 908add1155SRico Sonntag self::MEDIA_TYPE_OTHER, 918add1155SRico Sonntag ]; 928add1155SRico Sonntag 938add1155SRico Sonntag /** 948add1155SRico Sonntag * Constructor. 958add1155SRico Sonntag * 968add1155SRico Sonntag * @param Tree $tree 978add1155SRico Sonntag */ 988add1155SRico Sonntag public function __construct(Tree $tree) 998add1155SRico Sonntag { 1008add1155SRico Sonntag $this->tree = $tree; 1018add1155SRico Sonntag } 1028add1155SRico Sonntag 1038add1155SRico Sonntag /** 1048add1155SRico Sonntag * Returns the number of media records of the given type. 1058add1155SRico Sonntag * 1068add1155SRico Sonntag * @param string $type The media type to query 1078add1155SRico Sonntag * 1088add1155SRico Sonntag * @return int 1098add1155SRico Sonntag */ 1108add1155SRico Sonntag private function totalMediaTypeQuery(string $type): int 1118add1155SRico Sonntag { 1123cfcc809SGreg Roach if ($type !== self::MEDIA_TYPE_ALL && $type !== self::MEDIA_TYPE_UNKNOWN && !in_array($type, self::MEDIA_TYPES, true)) { 1138add1155SRico Sonntag return 0; 1148add1155SRico Sonntag } 1158add1155SRico Sonntag 1168add1155SRico Sonntag $query = DB::table('media') 1178add1155SRico Sonntag ->where('m_file', '=', $this->tree->id()); 1188add1155SRico Sonntag 1198add1155SRico Sonntag if ($type !== self::MEDIA_TYPE_ALL) { 1208add1155SRico Sonntag if ($type === self::MEDIA_TYPE_UNKNOWN) { 1218add1155SRico Sonntag // There has to be a better way then this :( 1228add1155SRico Sonntag foreach (self::MEDIA_TYPES as $t) { 1238add1155SRico Sonntag // Use function to add brackets 1240b5fd0a6SGreg Roach $query->where(static function (Builder $query) use ($t): void { 1258add1155SRico Sonntag $query->where('m_gedcom', 'not like', '%3 TYPE ' . $t . '%') 1268add1155SRico Sonntag ->where('m_gedcom', 'not like', '%1 _TYPE ' . $t . '%'); 1278add1155SRico Sonntag }); 1288add1155SRico Sonntag } 1298add1155SRico Sonntag } else { 1308add1155SRico Sonntag // Use function to add brackets 1310b5fd0a6SGreg Roach $query->where(static function (Builder $query) use ($type): void { 1328add1155SRico Sonntag $query->where('m_gedcom', 'like', '%3 TYPE ' . $type . '%') 1338add1155SRico Sonntag ->orWhere('m_gedcom', 'like', '%1 _TYPE ' . $type . '%'); 1348add1155SRico Sonntag }); 1358add1155SRico Sonntag } 1368add1155SRico Sonntag } 1378add1155SRico Sonntag 1388add1155SRico Sonntag return $query->count(); 1398add1155SRico Sonntag } 1408add1155SRico Sonntag 1418add1155SRico Sonntag /** 1420dcd9387SGreg Roach * @return string 1438add1155SRico Sonntag */ 1448add1155SRico Sonntag public function totalMedia(): string 1458add1155SRico Sonntag { 1468add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_ALL)); 1478add1155SRico Sonntag } 1488add1155SRico Sonntag 1498add1155SRico Sonntag /** 1500dcd9387SGreg Roach * @return string 1518add1155SRico Sonntag */ 1528add1155SRico Sonntag public function totalMediaAudio(): string 1538add1155SRico Sonntag { 1548add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_AUDIO)); 1558add1155SRico Sonntag } 1568add1155SRico Sonntag 1578add1155SRico Sonntag /** 1580dcd9387SGreg Roach * @return string 1598add1155SRico Sonntag */ 1608add1155SRico Sonntag public function totalMediaBook(): string 1618add1155SRico Sonntag { 1628add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_BOOK)); 1638add1155SRico Sonntag } 1648add1155SRico Sonntag 1658add1155SRico Sonntag /** 1660dcd9387SGreg Roach * @return string 1678add1155SRico Sonntag */ 1688add1155SRico Sonntag public function totalMediaCard(): string 1698add1155SRico Sonntag { 1708add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_CARD)); 1718add1155SRico Sonntag } 1728add1155SRico Sonntag 1738add1155SRico Sonntag /** 1740dcd9387SGreg Roach * @return string 1758add1155SRico Sonntag */ 1768add1155SRico Sonntag public function totalMediaCertificate(): string 1778add1155SRico Sonntag { 1788add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_CERTIFICATE)); 1798add1155SRico Sonntag } 1808add1155SRico Sonntag 1818add1155SRico Sonntag /** 1820dcd9387SGreg Roach * @return string 1838add1155SRico Sonntag */ 1848add1155SRico Sonntag public function totalMediaCoatOfArms(): string 1858add1155SRico Sonntag { 1868add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_COAT)); 1878add1155SRico Sonntag } 1888add1155SRico Sonntag 1898add1155SRico Sonntag /** 1900dcd9387SGreg Roach * @return string 1918add1155SRico Sonntag */ 1928add1155SRico Sonntag public function totalMediaDocument(): string 1938add1155SRico Sonntag { 1948add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_DOCUMENT)); 1958add1155SRico Sonntag } 1968add1155SRico Sonntag 1978add1155SRico Sonntag /** 1980dcd9387SGreg Roach * @return string 1998add1155SRico Sonntag */ 2008add1155SRico Sonntag public function totalMediaElectronic(): string 2018add1155SRico Sonntag { 2028add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_ELECTRONIC)); 2038add1155SRico Sonntag } 2048add1155SRico Sonntag 2058add1155SRico Sonntag /** 2060dcd9387SGreg Roach * @return string 2078add1155SRico Sonntag */ 2088add1155SRico Sonntag public function totalMediaFiche(): string 2098add1155SRico Sonntag { 2108add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_FICHE)); 2118add1155SRico Sonntag } 2128add1155SRico Sonntag 2138add1155SRico Sonntag /** 2140dcd9387SGreg Roach * @return string 2158add1155SRico Sonntag */ 2168add1155SRico Sonntag public function totalMediaFilm(): string 2178add1155SRico Sonntag { 2188add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_FILM)); 2198add1155SRico Sonntag } 2208add1155SRico Sonntag 2218add1155SRico Sonntag /** 2220dcd9387SGreg Roach * @return string 2238add1155SRico Sonntag */ 2248add1155SRico Sonntag public function totalMediaMagazine(): string 2258add1155SRico Sonntag { 2268add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_MAGAZINE)); 2278add1155SRico Sonntag } 2288add1155SRico Sonntag 2298add1155SRico Sonntag /** 2300dcd9387SGreg Roach * @return string 2318add1155SRico Sonntag */ 2328add1155SRico Sonntag public function totalMediaManuscript(): string 2338add1155SRico Sonntag { 2348add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_MANUSCRIPT)); 2358add1155SRico Sonntag } 2368add1155SRico Sonntag 2378add1155SRico Sonntag /** 2380dcd9387SGreg Roach * @return string 2398add1155SRico Sonntag */ 2408add1155SRico Sonntag public function totalMediaMap(): string 2418add1155SRico Sonntag { 2428add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_MAP)); 2438add1155SRico Sonntag } 2448add1155SRico Sonntag 2458add1155SRico Sonntag /** 2460dcd9387SGreg Roach * @return string 2478add1155SRico Sonntag */ 2488add1155SRico Sonntag public function totalMediaNewspaper(): string 2498add1155SRico Sonntag { 2508add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_NEWSPAPER)); 2518add1155SRico Sonntag } 2528add1155SRico Sonntag 2538add1155SRico Sonntag /** 2540dcd9387SGreg Roach * @return string 2558add1155SRico Sonntag */ 2568add1155SRico Sonntag public function totalMediaPainting(): string 2578add1155SRico Sonntag { 2588add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_PAINTING)); 2598add1155SRico Sonntag } 2608add1155SRico Sonntag 2618add1155SRico Sonntag /** 2620dcd9387SGreg Roach * @return string 2638add1155SRico Sonntag */ 2648add1155SRico Sonntag public function totalMediaPhoto(): string 2658add1155SRico Sonntag { 2668add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_PHOTO)); 2678add1155SRico Sonntag } 2688add1155SRico Sonntag 2698add1155SRico Sonntag /** 2700dcd9387SGreg Roach * @return string 2718add1155SRico Sonntag */ 2728add1155SRico Sonntag public function totalMediaTombstone(): string 2738add1155SRico Sonntag { 2748add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_TOMBSTONE)); 2758add1155SRico Sonntag } 2768add1155SRico Sonntag 2778add1155SRico Sonntag /** 2780dcd9387SGreg Roach * @return string 2798add1155SRico Sonntag */ 2808add1155SRico Sonntag public function totalMediaVideo(): string 2818add1155SRico Sonntag { 2828add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_VIDEO)); 2838add1155SRico Sonntag } 2848add1155SRico Sonntag 2858add1155SRico Sonntag /** 2860dcd9387SGreg Roach * @return string 2878add1155SRico Sonntag */ 2888add1155SRico Sonntag public function totalMediaOther(): string 2898add1155SRico Sonntag { 2908add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_OTHER)); 2918add1155SRico Sonntag } 2928add1155SRico Sonntag 2938add1155SRico Sonntag /** 2940dcd9387SGreg Roach * @return string 2958add1155SRico Sonntag */ 2968add1155SRico Sonntag public function totalMediaUnknown(): string 2978add1155SRico Sonntag { 2988add1155SRico Sonntag return I18N::number($this->totalMediaTypeQuery(self::MEDIA_TYPE_UNKNOWN)); 2998add1155SRico Sonntag } 3008add1155SRico Sonntag 3018add1155SRico Sonntag /** 3028add1155SRico Sonntag * Returns a sorted list of media types and their total counts. 3038add1155SRico Sonntag * 3048add1155SRico Sonntag * @param int $tot The total number of media files 3058add1155SRico Sonntag * 306*91c84b80SGreg Roach * @return array<string,int> 3078add1155SRico Sonntag */ 3088add1155SRico Sonntag private function getSortedMediaTypeList(int $tot): array 3098add1155SRico Sonntag { 3108add1155SRico Sonntag $media = []; 3118add1155SRico Sonntag $c = 0; 3128add1155SRico Sonntag $max = 0; 3138add1155SRico Sonntag 3148add1155SRico Sonntag foreach (self::MEDIA_TYPES as $type) { 3158add1155SRico Sonntag $count = $this->totalMediaTypeQuery($type); 3168add1155SRico Sonntag 3178add1155SRico Sonntag if ($count > 0) { 3188add1155SRico Sonntag $media[$type] = $count; 3198add1155SRico Sonntag 3208add1155SRico Sonntag if ($count > $max) { 3218add1155SRico Sonntag $max = $count; 3228add1155SRico Sonntag } 3238add1155SRico Sonntag 3248add1155SRico Sonntag $c += $count; 3258add1155SRico Sonntag } 3268add1155SRico Sonntag } 3278add1155SRico Sonntag 3288add1155SRico Sonntag $count = $this->totalMediaTypeQuery(self::MEDIA_TYPE_UNKNOWN); 3298add1155SRico Sonntag if ($count > 0) { 3308add1155SRico Sonntag $media[self::MEDIA_TYPE_UNKNOWN] = $tot - $c; 3318add1155SRico Sonntag if ($tot - $c > $max) { 3328add1155SRico Sonntag $max = $count; 3338add1155SRico Sonntag } 3348add1155SRico Sonntag } 3358add1155SRico Sonntag 3366ccdf4f0SGreg Roach if (count($media) > 10 && ($max / $tot) > 0.6) { 3378add1155SRico Sonntag arsort($media); 3386ccdf4f0SGreg Roach $media = array_slice($media, 0, 10); 3398add1155SRico Sonntag $c = $tot; 3408add1155SRico Sonntag 3418add1155SRico Sonntag foreach ($media as $cm) { 3428add1155SRico Sonntag $c -= $cm; 3438add1155SRico Sonntag } 3448add1155SRico Sonntag 3458add1155SRico Sonntag if (isset($media[self::MEDIA_TYPE_OTHER])) { 3468add1155SRico Sonntag $media[self::MEDIA_TYPE_OTHER] += $c; 3478add1155SRico Sonntag } else { 3488add1155SRico Sonntag $media[self::MEDIA_TYPE_OTHER] = $c; 3498add1155SRico Sonntag } 3508add1155SRico Sonntag } 3518add1155SRico Sonntag 3528add1155SRico Sonntag asort($media); 3538add1155SRico Sonntag 3548add1155SRico Sonntag return $media; 3558add1155SRico Sonntag } 3568add1155SRico Sonntag 3578add1155SRico Sonntag /** 3580dcd9387SGreg Roach * @param string|null $color_from 3590dcd9387SGreg Roach * @param string|null $color_to 3600dcd9387SGreg Roach * 3610dcd9387SGreg Roach * @return string 3628add1155SRico Sonntag */ 36388de55fdSRico Sonntag public function chartMedia(string $color_from = null, string $color_to = null): string 3648add1155SRico Sonntag { 3658add1155SRico Sonntag $tot = $this->totalMediaTypeQuery(self::MEDIA_TYPE_ALL); 3668add1155SRico Sonntag $media = $this->getSortedMediaTypeList($tot); 3678add1155SRico Sonntag 36893ccd686SRico Sonntag return (new ChartMedia()) 36988de55fdSRico Sonntag ->chartMedia($media, $color_from, $color_to); 3708add1155SRico Sonntag } 3718add1155SRico Sonntag} 372