1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22declare(strict_types=0); 23 24namespace Ampache\Repository\Model; 25 26use Ampache\Module\Artist\Tag\ArtistTagUpdaterInterface; 27use Ampache\Module\Label\LabelListUpdaterInterface; 28use Ampache\Module\Statistics\Stats; 29use Ampache\Module\System\Dba; 30use Ampache\Module\Util\Recommendation; 31use Ampache\Config\AmpConfig; 32use Ampache\Module\Util\VaInfo; 33use Ampache\Repository\AlbumRepositoryInterface; 34use Ampache\Repository\LabelRepositoryInterface; 35use Ampache\Repository\SongRepositoryInterface; 36use Ampache\Repository\UserActivityRepositoryInterface; 37use PDOStatement; 38 39class Artist extends database_object implements library_item, GarbageCollectibleInterface 40{ 41 protected const DB_TABLENAME = 'artist'; 42 43 /* Variables from DB */ 44 45 /** 46 * @var integer $id 47 */ 48 public $id; 49 50 /** 51 * @var string $name 52 */ 53 public $name; 54 55 /** 56 * @var string $summary 57 */ 58 public $summary; 59 60 /** 61 * @var string $placeformed 62 */ 63 public $placeformed; 64 65 /** 66 * @var integer $yearformed 67 */ 68 public $yearformed; 69 70 /** 71 * @var integer $last_update 72 */ 73 public $last_update; 74 75 /** 76 * @var integer $songs 77 */ 78 public $songs; 79 80 /** 81 * @var integer $albums 82 */ 83 public $albums; 84 85 /** 86 * @var string $prefix 87 */ 88 public $prefix; 89 90 /** 91 * @var string $mbid 92 */ 93 public $mbid; // MusicBrainz ID 94 95 /** 96 * @var integer $catalog_id 97 */ 98 public $catalog_id; 99 100 /** 101 * @var integer $time 102 */ 103 public $time; 104 105 /** 106 * @var integer $user 107 */ 108 public $user; 109 110 /** 111 * @var boolean $manual_update 112 */ 113 public $manual_update; 114 115 /** 116 * @var array $tags 117 */ 118 public $tags; 119 120 /** 121 * @var string $f_tags 122 */ 123 public $f_tags; 124 125 /** 126 * @var array $labels 127 */ 128 public $labels; 129 130 /** 131 * @var string $f_labels 132 */ 133 public $f_labels; 134 135 /** 136 * @var integer $object_cnt 137 */ 138 public $object_cnt; 139 140 /** 141 * @var integer $total_count 142 */ 143 private $total_count; 144 145 /** 146 * @var string $f_name // Prefix + Name, generated 147 */ 148 public $f_name; 149 150 /** 151 * @var string $link 152 */ 153 public $link; 154 155 /** 156 * @var string $f_link 157 */ 158 public $f_link; 159 160 /** 161 * @var string $f_time 162 */ 163 public $f_time; 164 165 // Constructed vars 166 /** 167 * @var boolean $_fake 168 */ 169 public $_fake = false; // Set if construct_from_array() used 170 171 /** 172 * @var integer $album_count 173 */ 174 private $album_count; 175 176 /** 177 * @var integer $album_group_count 178 */ 179 private $album_group_count; 180 181 /** 182 * @var integer $song_count 183 */ 184 private $song_count; 185 186 /** 187 * @var array $_mapcache 188 */ 189 private static $_mapcache = array(); 190 191 /** 192 * Artist 193 * Artist class, for modifying an artist 194 * Takes the ID of the artist and pulls the info from the db 195 * @param integer|null $artist_id 196 * @param integer $catalog_init 197 */ 198 public function __construct($artist_id = null, $catalog_init = 0) 199 { 200 /* If they failed to pass in an id, just run for it */ 201 if ($artist_id === null) { 202 return false; 203 } 204 205 $this->catalog_id = $catalog_init; 206 /* Get the information from the db */ 207 $info = $this->get_info($artist_id); 208 209 foreach ($info as $key => $value) { 210 $this->$key = $value; 211 } // foreach info 212 213 // set the full name 214 $this->f_name = trim(trim((string) $info['prefix']) . ' ' . trim((string) $info['name'])); 215 // make sure the int values are cast to integers 216 $this->object_cnt = (int)$this->total_count; 217 $this->time = (int)$this->time; 218 $this->album_count = (int)$this->album_count; 219 $this->album_group_count = (int)$this->album_group_count; 220 $this->song_count = (int)$this->song_count; 221 222 return true; 223 } // constructor 224 225 public function getId(): int 226 { 227 return (int) $this->id; 228 } 229 230 public function isNew(): bool 231 { 232 return $this->getId() === 0; 233 } 234 235 /** 236 * construct_from_array 237 * This is used by the metadata class specifically but fills out a Artist object 238 * based on a key'd array, it sets $_fake to true 239 * @param array $data 240 * @return Artist 241 */ 242 public static function construct_from_array($data) 243 { 244 $artist = new Artist(0); 245 foreach ($data as $key => $value) { 246 $artist->$key = $value; 247 } 248 249 // Ack that this is not a real object from the DB 250 $artist->_fake = true; 251 252 return $artist; 253 } // construct_from_array 254 255 /** 256 * garbage_collection 257 * 258 * This cleans out unused artists 259 */ 260 public static function garbage_collection() 261 { 262 Dba::write("DELETE FROM `artist` WHERE `artist`.`id` NOT IN (SELECT `song`.`artist` FROM `song` WHERE `song`.`artist` IS NOT NULL) AND `artist`.`id` NOT IN (SELECT `album`.`album_artist` FROM `album` WHERE `album`.`album_artist` IS NOT NULL) AND `artist`.`id` NOT IN (SELECT `wanted`.`artist` FROM `wanted` WHERE `wanted`.`artist` IS NOT NULL) AND `artist`.`id` NOT IN (SELECT `clip`.`artist` FROM `clip` WHERE `clip`.`artist` IS NOT NULL);"); 263 } 264 265 /** 266 * this attempts to build a cache of the data from the passed albums all in one query 267 * @param integer[] $ids 268 * @param boolean $extra 269 * @param string $limit_threshold 270 * @return boolean 271 */ 272 public static function build_cache($ids, $extra = false, $limit_threshold = '') 273 { 274 if (empty($ids)) { 275 return false; 276 } 277 $idlist = '(' . implode(',', $ids) . ')'; 278 $sql = "SELECT * FROM `artist` WHERE `id` IN $idlist"; 279 $db_results = Dba::read($sql); 280 281 while ($row = Dba::fetch_assoc($db_results)) { 282 parent::add_to_cache('artist', $row['id'], $row); 283 } 284 285 // If we need to also pull the extra information, this is normally only used when we are doing the human display 286 if ($extra && (AmpConfig::get('show_played_times'))) { 287 $sql = "SELECT `song`.`artist` FROM `song` WHERE `song`.`artist` IN $idlist"; 288 289 //debug_event("artist.class", "build_cache sql: " . $sql, 5); 290 $db_results = Dba::read($sql); 291 292 while ($row = Dba::fetch_assoc($db_results)) { 293 $row['object_cnt'] = (!empty($limit_threshold)) 294 ? Stats::get_object_count('artist', $row['artist'], $limit_threshold) 295 : $row['total_count']; 296 parent::add_to_cache('artist_extra', $row['artist'], $row); 297 } 298 } // end if extra 299 300 return true; 301 } // build_cache 302 303 /** 304 * get_from_name 305 * This gets an artist object based on the artist name 306 * @param string $name 307 * @return Artist 308 */ 309 public static function get_from_name($name) 310 { 311 $sql = "SELECT `id` FROM `artist` WHERE `name` = ? OR LTRIM(CONCAT(COALESCE(`artist`.`prefix`, ''), ' ', `artist`.`name`)) = ? "; 312 $db_results = Dba::read($sql, array($name, $name)); 313 314 $row = Dba::fetch_assoc($db_results); 315 316 return new Artist($row['id']); 317 } // get_from_name 318 319 /** 320 * get_time 321 * 322 * Get time for an artist's songs. 323 * @param integer $artist_id 324 * @return integer 325 */ 326 public static function get_time($artist_id) 327 { 328 $params = array($artist_id); 329 $sql = "SELECT SUM(`song`.`time`) AS `time` from `song` WHERE `song`.`artist` = ?"; 330 $db_results = Dba::read($sql, $params); 331 $results = Dba::fetch_assoc($db_results); 332 // album artists that don't have any songs 333 if ((int) $results['time'] == 0) { 334 $sql = "SELECT SUM(`album`.`time`) AS `time` from `album` WHERE `album`.`album_artist` = ?"; 335 $db_results = Dba::read($sql, $params); 336 $results = Dba::fetch_assoc($db_results); 337 } 338 339 return (int) $results['time']; 340 } 341 342 /** 343 * get_song_count 344 * 345 * Get count for an artist's songs. 346 * @param integer $artist_id 347 * @return integer 348 */ 349 public static function get_song_count($artist_id) 350 { 351 $params = array($artist_id); 352 $sql = "SELECT COUNT(`song`.`id`) AS `song_count` from `song` WHERE `song`.`artist` = ?"; 353 $db_results = Dba::read($sql, $params); 354 $results = Dba::fetch_assoc($db_results); 355 356 return (int) $results['song_count']; 357 } 358 359 /** 360 * get_album_count 361 * 362 * Get count for an artist's albums. 363 * @param integer $artist_id 364 * @return integer 365 */ 366 public static function get_album_count($artist_id) 367 { 368 $params = array($artist_id); 369 $sql = "SELECT COUNT(DISTINCT `album`.`id`) AS `album_count` FROM `album` LEFT JOIN `catalog` ON `catalog`.`id` = `album`.`catalog` WHERE `album`.`album_artist` = ? AND `catalog`.`enabled` = '1'"; 370 $db_results = Dba::read($sql, $params); 371 $results = Dba::fetch_assoc($db_results); 372 373 return (int) $results['album_count']; 374 } 375 376 /** 377 * get_album_group_count 378 * 379 * Get count for an artist's albums. 380 * @param integer $artist_id 381 * @return integer 382 */ 383 public static function get_album_group_count($artist_id) 384 { 385 $params = array($artist_id); 386 $sql = "SELECT COUNT(DISTINCT CONCAT(COALESCE(`album`.`prefix`, ''), `album`.`name`, COALESCE(`album`.`album_artist`, ''), COALESCE(`album`.`mbid`, ''), COALESCE(`album`.`year`, ''))) AS `album_count` FROM `album` LEFT JOIN `catalog` ON `catalog`.`id` = `album`.`catalog` WHERE `album`.`album_artist` = ? AND `catalog`.`enabled` = '1'"; 387 $db_results = Dba::read($sql, $params); 388 $results = Dba::fetch_assoc($db_results); 389 390 return (int) $results['album_count']; 391 } 392 393 /** 394 * get_id_arrays 395 * 396 * Get each id from the artist table with the minimum detail required for subsonic 397 * @param array $catalogs 398 * @return array 399 */ 400 public static function get_id_arrays($catalogs = array()) 401 { 402 $group_column = (AmpConfig::get('album_group')) ? '`artist`.`album_group_count`' : '`artist`.`album_count`'; 403 if (!empty($catalogs)) { 404 $sql = "SELECT DISTINCT `artist`.`id`, LTRIM(CONCAT(COALESCE(`artist`.`prefix`, ''), ' ', `artist`.`name`)) AS `f_name`, `artist`.`name`, $group_column AS `album_count`, `artist`.`song_count` FROM `artist` LEFT JOIN `catalog_map` ON `catalog_map`.`object_type` = 'artist' AND `catalog_map`.`object_id` = `artist`.`id` WHERE `catalog_map`.`catalog_id` = ? ORDER BY `artist`.`name`"; 405 $db_results = Dba::read($sql, $catalogs); 406 } else { 407 $sql = "SELECT DISTINCT `artist`.`id`, LTRIM(CONCAT(COALESCE(`artist`.`prefix`, ''), ' ', `artist`.`name`)) AS `f_name`, `artist`.`name`, $group_column AS `album_count`, `artist`.`song_count` FROM `artist` ORDER BY `artist`.`name`"; 408 $db_results = Dba::read($sql); 409 } 410 $results = array(); 411 412 while ($row = Dba::fetch_assoc($db_results, false)) { 413 $results[] = $row; 414 } 415 416 return $results; 417 } 418 419 /** 420 * get_id_array 421 * 422 * Get info from the artist table with the minimum detail required for subsonic 423 * @param integer $artist_id 424 * @return array 425 */ 426 public static function get_id_array($artist_id) 427 { 428 $group_column = (AmpConfig::get('album_group')) ? '`artist`.`album_group_count`' : '`artist`.`album_count`'; 429 $sql = "SELECT DISTINCT `artist`.`id`, LTRIM(CONCAT(COALESCE(`artist`.`prefix`, ''), ' ', `artist`.`name`)) AS `f_name`, `artist`.`name`, $group_column AS `album_count`, `artist`.`song_count` FROM `artist` WHERE `artist`.`id` = ? ORDER BY `artist`.`name`"; 430 $db_results = Dba::read($sql, array($artist_id)); 431 $row = Dba::fetch_assoc($db_results, false); 432 433 return $row; 434 } 435 436 /** 437 * get_child_ids 438 * 439 * Get each album id for the artist 440 * @return int[] 441 */ 442 public function get_child_ids() 443 { 444 $sql = "SELECT DISTINCT `album`.`id` FROM `album` LEFT JOIN `catalog` ON `catalog`.`id` = `album`.`catalog` WHERE `album`.`album_artist` = ? AND `catalog`.`enabled` = '1'"; 445 $db_results = Dba::read($sql, array($this->id)); 446 $results = array(); 447 448 while ($row = Dba::fetch_assoc($db_results, false)) { 449 $results[] = (int)$row['id']; 450 } 451 452 return $results; 453 } 454 455 /** 456 * format 457 * this function takes an array of artist 458 * information and formats the relevant values 459 * so they can be displayed in a table for example 460 * it changes the title into a full link. 461 * @param boolean $details 462 * @param string $limit_threshold 463 * @return boolean 464 */ 465 public function format($details = true, $limit_threshold = '') 466 { 467 // If this is a memory-only object, we're done here 468 if (!$this->id) { 469 return true; 470 } 471 $this->songs = $this->song_count; 472 $this->albums = (AmpConfig::get('album_group')) ? $this->album_group_count : $this->album_count; 473 $this->link = ($this->catalog_id) 474 ? AmpConfig::get('web_path') . '/artists.php?action=show&catalog=' . $this->catalog_id . '&artist=' . $this->id 475 : AmpConfig::get('web_path') . '/artists.php?action=show&artist=' . $this->id; 476 $this->f_link = "<a href=\"" . $this->link . "\" title=\"" . scrub_out($this->f_name) . "\">" . scrub_out($this->f_name) . "</a>"; 477 478 if ($details) { 479 $min = sprintf("%02d", (floor($this->time / 60) % 60)); 480 $sec = sprintf("%02d", ($this->time % 60)); 481 $hours = floor($this->time / 3600); 482 483 $this->f_time = ltrim((string)$hours . ':' . $min . ':' . $sec, '0:'); 484 $this->tags = Tag::get_top_tags('artist', $this->id); 485 $this->f_tags = Tag::get_display($this->tags, true, 'artist'); 486 487 if (AmpConfig::get('label')) { 488 $this->labels = $this->getLabelRepository()->getByArtist((int) $this->id); 489 $this->f_labels = Label::get_display($this->labels, true); 490 } 491 } 492 493 return true; 494 } // format 495 496 /** 497 * Get item keywords for metadata searches. 498 * @return array 499 */ 500 public function get_keywords() 501 { 502 $keywords = array(); 503 $keywords['mb_artistid'] = array( 504 'important' => false, 505 'label' => T_('Artist MusicBrainzID'), 506 'value' => $this->mbid 507 ); 508 $keywords['artist'] = array( 509 'important' => true, 510 'label' => T_('Artist'), 511 'value' => $this->f_name 512 ); 513 514 return $keywords; 515 } 516 517 /** 518 * Get item fullname. 519 * @return string 520 */ 521 public function get_fullname() 522 { 523 return $this->f_name; 524 } 525 526 /** 527 * Get parent item description. 528 * @return array|null 529 */ 530 public function get_parent() 531 { 532 return null; 533 } 534 535 /** 536 * Get item childrens. 537 * @return array 538 */ 539 public function get_childrens() 540 { 541 $medias = array(); 542 $albums = $this->getAlbumRepository()->getByArtist($this->id); 543 foreach ($albums as $album_id) { 544 $medias[] = array( 545 'object_type' => 'album', 546 'object_id' => $album_id 547 ); 548 } 549 550 return array('album' => $medias); 551 } 552 553 /** 554 * Search for item childrens. 555 * @param string $name 556 * @return array 557 */ 558 public function search_childrens($name) 559 { 560 $search = array(); 561 $search['type'] = "album"; 562 $search['rule_0_input'] = $name; 563 $search['rule_0_operator'] = 4; 564 $search['rule_0'] = "title"; 565 $search['rule_1_input'] = $this->name; 566 $search['rule_1_operator'] = 4; 567 $search['rule_1'] = "artist"; 568 $albums = Search::run($search); 569 570 $childrens = array(); 571 foreach ($albums as $album_id) { 572 $childrens[] = array( 573 'object_type' => 'album', 574 'object_id' => $album_id 575 ); 576 } 577 578 return $childrens; 579 } 580 581 /** 582 * Get all childrens and sub-childrens medias. 583 * @param string $filter_type 584 * @return array 585 */ 586 public function get_medias($filter_type = null) 587 { 588 $medias = array(); 589 if ($filter_type === null || $filter_type == 'song') { 590 $songs = $this->getSongRepository()->getByArtist($this->id); 591 foreach ($songs as $song_id) { 592 $medias[] = array( 593 'object_type' => 'song', 594 'object_id' => $song_id 595 ); 596 } 597 } 598 599 return $medias; 600 } 601 602 /** 603 * get_catalogs 604 * 605 * Get all catalog ids related to this item. 606 * @return integer[] 607 */ 608 public function get_catalogs() 609 { 610 return array($this->catalog_id); 611 } 612 613 /** 614 * Get item's owner. 615 * @return integer|null 616 */ 617 public function get_user_owner() 618 { 619 return $this->user; 620 } 621 622 /** 623 * Get default art kind for this item. 624 * @return string 625 */ 626 public function get_default_art_kind() 627 { 628 return 'default'; 629 } 630 631 /** 632 * get_description 633 * @return string 634 */ 635 public function get_description() 636 { 637 return $this->summary; 638 } 639 640 /** 641 * display_art 642 * @param integer $thumb 643 * @param boolean $force 644 */ 645 public function display_art($thumb = 2, $force = false) 646 { 647 $artist_id = null; 648 $type = null; 649 650 if (Art::has_db($this->id, 'artist') || $force) { 651 $artist_id = $this->id; 652 $type = 'artist'; 653 } 654 655 if ($artist_id !== null && $type !== null) { 656 Art::display($type, $artist_id, $this->get_fullname(), $thumb, $this->link); 657 } 658 } 659 660 /** 661 * check 662 * 663 * Checks for an existing artist; if none exists, insert one. 664 * @param string $name 665 * @param string $mbid 666 * @param boolean $readonly 667 * @return integer|null 668 */ 669 public static function check($name, $mbid = '', $readonly = false) 670 { 671 $trimmed = Catalog::trim_prefix(trim((string)$name)); 672 $name = $trimmed['string']; 673 $prefix = $trimmed['prefix']; 674 // If Ampache support multiple artists per song one day, we should also handle other artists here 675 $trimmed = Catalog::trim_featuring($name); 676 $name = $trimmed[0]; 677 678 // If Ampache support multiple artists per song one day, we should also handle other artists here 679 $mbid = Catalog::trim_slashed_list($mbid); 680 681 if (!$name) { 682 $name = T_('Unknown (Orphaned)'); 683 $prefix = null; 684 } 685 if ($name == 'Various Artists') { 686 $mbid = ''; 687 } 688 689 if (isset(self::$_mapcache[$name][$prefix][$mbid])) { 690 return self::$_mapcache[$name][$prefix][$mbid]; 691 } 692 693 $artist_id = 0; 694 $exists = false; 695 $matches = array(); 696 697 // check for artists by mbid and split-mbid 698 if ($mbid !== '') { 699 $sql = 'SELECT `id` FROM `artist` WHERE `mbid` = ?'; 700 $matches = VaInfo::get_mbid_array($mbid); 701 foreach ($matches as $mbid_string) { 702 $db_results = Dba::read($sql, array($mbid_string)); 703 704 if (!$exists) { 705 $row = Dba::fetch_assoc($db_results); 706 $artist_id = (int)$row['id']; 707 $exists = ($artist_id > 0); 708 $mbid = ($exists) 709 ? $mbid_string 710 : $mbid; 711 } 712 } 713 // try the whole string if it didn't work 714 if (!$exists) { 715 $db_results = Dba::read($sql, array($mbid)); 716 717 if ($row = Dba::fetch_assoc($db_results)) { 718 $artist_id = (int)$row['id']; 719 $exists = ($artist_id > 0); 720 } 721 } 722 } 723 // search by the artist name and build an array 724 if (!$exists) { 725 $sql = 'SELECT `id`, `mbid` FROM `artist` WHERE `name` LIKE ?'; 726 $db_results = Dba::read($sql, array($name)); 727 $id_array = array(); 728 while ($row = Dba::fetch_assoc($db_results)) { 729 $key = $row['mbid'] ?: 'null'; 730 $id_array[$key] = $row['id']; 731 } 732 if (count($id_array)) { 733 if ($mbid !== '') { 734 $matches = VaInfo::get_mbid_array($mbid); 735 foreach ($matches as $mbid_string) { 736 // reverse search artist id if it's still not found for some reason 737 if (isset($id_array[$mbid_string])) { 738 $artist_id = (int)$id_array[$mbid_string]; 739 $exists = ($artist_id > 0); 740 $mbid = ($exists) 741 ? $mbid_string 742 : $mbid; 743 } 744 // update empty artists that match names 745 if (isset($id_array['null']) && !$readonly) { 746 $sql = 'UPDATE `artist` SET `mbid` = ? WHERE `id` = ?'; 747 Dba::write($sql, array($mbid_string, $id_array['null'])); 748 } 749 } 750 if (isset($id_array['null'])) { 751 if (!$readonly) { 752 $sql = 'UPDATE `artist` SET `mbid` = ? WHERE `id` = ?'; 753 Dba::write($sql, array($mbid, $id_array['null'])); 754 } 755 $artist_id = (int)$id_array['null']; 756 $exists = true; 757 } 758 } else { 759 // Pick one at random 760 $artist_id = array_shift($id_array); 761 $exists = true; 762 } 763 } 764 } 765 // cache and return the result 766 if ($exists) { 767 self::$_mapcache[$name][$prefix][$mbid] = $artist_id; 768 769 return (int)$artist_id; 770 } 771 // if all else fails, insert a new artist, cache it and return the id 772 $sql = 'INSERT INTO `artist` (`name`, `prefix`, `mbid`) ' . 'VALUES(?, ?, ?)'; 773 $mbid = (!empty($matches)) ? $matches[0] : $mbid; // TODO only use primary mbid until multi-artist is ready 774 775 $db_results = Dba::write($sql, array($name, $prefix, $mbid)); 776 if (!$db_results) { 777 return null; 778 } 779 780 $artist_id = (int) Dba::insert_id(); 781 debug_event(self::class, "check album: created {{$artist_id}}", 4); 782 // map the new id 783 Catalog::update_map(0, 'artist', $artist_id); 784 785 self::$_mapcache[$name][$prefix][$mbid] = $artist_id; 786 787 return $artist_id; 788 } 789 790 /** 791 * update 792 * This takes a key'd array of data and updates the current artist 793 * @param array $data 794 * @return integer 795 */ 796 public function update(array $data) 797 { 798 // Save our current ID 799 $name = isset($data['name']) ? $data['name'] : $this->name; 800 $mbid = isset($data['mbid']) ? $data['mbid'] : $this->mbid; 801 $summary = isset($data['summary']) ? $data['summary'] : $this->summary; 802 $placeformed = isset($data['placeformed']) ? $data['placeformed'] : $this->placeformed; 803 $yearformed = isset($data['yearformed']) ? $data['yearformed'] : $this->yearformed; 804 805 $current_id = $this->id; 806 807 // Check if name is different than current name 808 if ($this->name != $name) { 809 $updated = false; 810 $artist_id = self::check($name, $mbid, true); 811 812 // If it's changed we need to update 813 if ($artist_id !== null && $artist_id !== $this->id) { 814 $time = time(); 815 $songs = $this->getSongRepository()->getByArtist($this->id); 816 foreach ($songs as $song_id) { 817 Song::update_artist($artist_id, $song_id, $this->id); 818 Song::update_utime($song_id, $time); 819 } 820 $updated = true; 821 $current_id = $artist_id; 822 Stats::migrate('artist', $this->id, $artist_id); 823 Useractivity::migrate('artist', $this->id, $artist_id); 824 Recommendation::migrate('artist', $this->id, $artist_id); 825 Share::migrate('artist', $this->id, $artist_id); 826 Shoutbox::migrate('artist', $this->id, $artist_id); 827 Tag::migrate('artist', $this->id, $artist_id); 828 Userflag::migrate('artist', $this->id, $artist_id); 829 Label::migrate('artist', $this->id, $artist_id); 830 Rating::migrate('artist', $this->id, $artist_id); 831 Art::duplicate('artist', $this->id, $artist_id); 832 Wanted::migrate('artist', $this->id, $artist_id); 833 Catalog::migrate_map('artist', $this->id, $artist_id); 834 } // end if it changed 835 836 // clear out the old data 837 if ($updated) { 838 self::garbage_collection(); 839 Stats::garbage_collection(); 840 Rating::garbage_collection(); 841 Userflag::garbage_collection(); 842 Label::garbage_collection(); 843 $this->getUseractivityRepository()->collectGarbage(); 844 self::update_artist_counts($current_id); 845 } // if updated 846 } else { 847 if ($this->mbid != $mbid) { 848 $sql = 'UPDATE `artist` SET `mbid` = ? WHERE `id` = ?'; 849 Dba::write($sql, array($mbid, $current_id)); 850 } 851 } 852 853 // Update artist name (if we don't want to use the MusicBrainz name) 854 $trimmed = Catalog::trim_prefix(trim((string)$name)); 855 $name = $trimmed['string']; 856 if ($name != '' && $name != $this->name) { 857 $sql = 'UPDATE `artist` SET `name` = ? WHERE `id` = ?'; 858 Dba::write($sql, array($name, $current_id)); 859 } 860 861 $this->update_artist_info($summary, $placeformed, $yearformed, true); 862 863 $this->name = $name; 864 $this->mbid = $mbid; 865 866 $override_childs = false; 867 if ($data['overwrite_childs'] == 'checked') { 868 $override_childs = true; 869 } 870 871 $add_to_childs = false; 872 if ($data['add_to_childs'] == 'checked') { 873 $add_to_childs = true; 874 } 875 876 if (isset($data['edit_tags'])) { 877 $this->getArtistTagUpdater()->updateTags( 878 $this, 879 $data['edit_tags'], 880 $override_childs, 881 $add_to_childs, 882 true 883 ); 884 } 885 886 if (AmpConfig::get('label') && isset($data['edit_labels'])) { 887 $this->getLabelListUpdater()->update( 888 $data['edit_labels'], 889 (int) $this->id, 890 true 891 ); 892 } 893 894 return $current_id; 895 } // update 896 897 /** 898 * Update artist information. 899 * @param string $summary 900 * @param string $placeformed 901 * @param integer $yearformed 902 * @param boolean $manual 903 * @return PDOStatement|boolean 904 */ 905 public function update_artist_info($summary, $placeformed, $yearformed, $manual = false) 906 { 907 // set null values if missing 908 $summary = (empty($summary)) ? null : $summary; 909 $placeformed = (empty($placeformed)) ? null : $placeformed; 910 $yearformed = ((int)$yearformed == 0) ? null : Catalog::normalize_year($yearformed); 911 912 $sql = "UPDATE `artist` SET `summary` = ?, `placeformed` = ?, `yearformed` = ?, `last_update` = ?, `manual_update` = ? WHERE `id` = ?"; 913 $sqlret = Dba::write($sql, array($summary, $placeformed, $yearformed, time(), (int)$manual, $this->id)); 914 915 $this->summary = $summary; 916 $this->placeformed = $placeformed; 917 $this->yearformed = $yearformed; 918 919 return $sqlret; 920 } 921 922 /** 923 * Update artist associated user. 924 * @param integer $user 925 * @return PDOStatement|boolean 926 */ 927 public function update_artist_user($user) 928 { 929 $sql = "UPDATE `artist` SET `user` = ? WHERE `id` = ?"; 930 931 return Dba::write($sql, array($user, $this->id)); 932 } 933 934 /** 935 * update_artist_counts 936 * 937 * @param integer $artist_id 938 */ 939 public static function update_artist_counts($artist_id) 940 { 941 if ($artist_id > 0) { 942 $params = array($artist_id); 943 // artist.time 944 $sql = "UPDATE `artist`, (SELECT sum(`song`.`time`) as `time`, `song`.`artist` FROM `song` WHERE `song`.`artist` = ? GROUP BY `song`.`artist`) AS `song` SET `artist`.`time` = `song`.`time` WHERE `artist`.`id` = `song`.`artist`;"; 945 Dba::write($sql, $params); 946 // artist.total_count 947 $sql = "UPDATE `artist`, (SELECT COUNT(`object_count`.`object_id`) AS `total_count`, `object_id` FROM `object_count` WHERE `object_count`.`object_id` = ? AND `object_count`.`object_type` = 'artist' AND `object_count`.`count_type` = 'stream' GROUP BY `object_count`.`object_id`) AS `object_count` SET `artist`.`total_count` = `object_count`.`total_count` WHERE `artist`.`id` = `object_count`.`object_id`;"; 948 Dba::write($sql, $params); 949 // artist.album_count 950 $sql = "UPDATE `artist`, (SELECT COUNT(DISTINCT `album`.`id`) AS `album_count`, `album_artist` FROM `album` LEFT JOIN `catalog` ON `catalog`.`id` = `album`.`catalog` WHERE `album`.`album_artist` = ? AND `catalog`.`enabled` = '1' GROUP BY `album_artist`) AS `album` SET `artist`.`album_count` = `album`.`album_count` WHERE `artist`.`id` = `album`.`album_artist`;"; 951 Dba::write($sql, $params); 952 // artist.album_group_count 953 $sql = "UPDATE `artist`, (SELECT COUNT(DISTINCT CONCAT(COALESCE(`album`.`prefix`, ''), `album`.`name`, COALESCE(`album`.`album_artist`, ''), COALESCE(`album`.`mbid`, ''), COALESCE(`album`.`year`, ''))) AS `album_group_count`, `album_artist` FROM `album` LEFT JOIN `catalog` ON `catalog`.`id` = `album`.`catalog` WHERE `album`.`album_artist` = ? AND `catalog`.`enabled` = '1' GROUP BY `album_artist`) AS `album` SET `artist`.`album_group_count` = `album`.`album_group_count` WHERE `artist`.`id` = `album`.`album_artist`;"; 954 Dba::write($sql, $params); 955 // artist.song_count 956 $sql = "UPDATE `artist`, (SELECT COUNT(`song`.`id`) AS `song_count`, `artist` FROM `song` LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` WHERE `song`.`artist` = ? AND `catalog`.`enabled` = '1' GROUP BY `artist`) AS `song` SET `artist`.`song_count` = `song`.`song_count` WHERE `artist`.`id` = `song`.`artist`;"; 957 Dba::write($sql, $params); 958 } 959 } 960 961 /** 962 * Update artist last_update time. 963 * @param integer $object_id 964 */ 965 public static function set_last_update($object_id) 966 { 967 $sql = "UPDATE `artist` SET `last_update` = ? WHERE `id` = ?"; 968 Dba::write($sql, array(time(), $object_id)); 969 } 970 971 /** 972 * @deprecated 973 */ 974 private function getLabelRepository(): LabelRepositoryInterface 975 { 976 global $dic; 977 978 return $dic->get(LabelRepositoryInterface::class); 979 } 980 981 /** 982 * @deprecated 983 */ 984 private function getLabelListUpdater(): LabelListUpdaterInterface 985 { 986 global $dic; 987 988 return $dic->get(LabelListUpdaterInterface::class); 989 } 990 991 /** 992 * @deprecated 993 */ 994 private function getAlbumRepository(): AlbumRepositoryInterface 995 { 996 global $dic; 997 998 return $dic->get(AlbumRepositoryInterface::class); 999 } 1000 1001 /** 1002 * @deprecated 1003 */ 1004 private function getArtistTagUpdater(): ArtistTagUpdaterInterface 1005 { 1006 global $dic; 1007 1008 return $dic->get(ArtistTagUpdaterInterface::class); 1009 } 1010 1011 /** 1012 * @deprecated 1013 */ 1014 private function getSongRepository(): SongRepositoryInterface 1015 { 1016 global $dic; 1017 1018 return $dic->get(SongRepositoryInterface::class); 1019 } 1020 1021 /** 1022 * @deprecated 1023 */ 1024 private function getUseractivityRepository(): UserActivityRepositoryInterface 1025 { 1026 global $dic; 1027 1028 return $dic->get(UserActivityRepositoryInterface::class); 1029 } 1030} 1031