castopod/app/Models/PersonModel.php

407 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* @copyright 2021 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Models;
use App\Entities\Image;
use App\Entities\Person;
use CodeIgniter\Database\BaseResult;
use CodeIgniter\Model;
class PersonModel extends Model
{
/**
* @var string
*/
protected $table = 'persons';
/**
* @var string
*/
protected $primaryKey = 'id';
/**
* @var string[]
*/
protected $allowedFields = [
'id',
'full_name',
'unique_name',
'information_url',
'image_path',
'image_mimetype',
'created_by',
'updated_by',
];
/**
* @var string
*/
protected $returnType = Person::class;
/**
* @var bool
*/
protected $useSoftDeletes = false;
/**
* @var bool
*/
protected $useTimestamps = true;
/**
* @var array<string, string>
*/
protected $validationRules = [
'full_name' => 'required',
'unique_name' =>
'required|regex_match[/^[a-z0-9\-]{1,191}$/]|is_unique[persons.unique_name,id,{id}]',
'image_path' => 'required',
'created_by' => 'required',
'updated_by' => 'required',
];
/**
* @var string[]
*/
protected $afterInsert = ['clearCache'];
/**
* clear cache before update if by any chance, the person name changes, so will the person link
*
* @var string[]
*/
protected $beforeUpdate = ['clearCache'];
/**
* @var string[]
*/
protected $beforeDelete = ['clearCache'];
public function getPersonById(int $personId): ?Person
{
$cacheName = "person#{$personId}";
if (!($found = cache($cacheName))) {
$found = $this->find($personId);
cache()->save($cacheName, $found, DECADE);
}
return $found;
}
public function getPerson(string $fullName): ?Person
{
return $this->where('full_name', $fullName)->first();
}
/**
* @return object[]
*/
public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array {
if ($episodeId) {
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles";
if (!($found = cache($cacheName))) {
$found = $this
->select('episodes_persons.person_group as group, episodes_persons.person_role as role')
->join('episodes_persons', 'persons.id = episodes_persons.person_id')
->where('persons.id', $personId)
->where('episodes_persons.episode_id', $episodeId)
->get()
->getResultObject();
}
} else {
$cacheName = "podcast#{$podcastId}_person#{$personId}_roles";
if (!($found = cache($cacheName))) {
$found = $this
->select('podcasts_persons.person_group as group, podcasts_persons.person_role as role')
->join('podcasts_persons', 'persons.id = podcasts_persons.person_id')
->where('persons.id', $personId)
->where('podcasts_persons.podcast_id', $podcastId)
->get()
->getResultObject();
}
}
return $found;
}
/**
* @return array<string, string>
*/
public function getPersonOptions(): array
{
$options = [];
if (!($options = cache('person_options'))) {
$options = array_reduce(
$this->select('`id`, `full_name`')
->orderBy('`full_name`', 'ASC')
->findAll(),
function ($result, $person) {
$result[$person->id] = $person->full_name;
return $result;
},
[],
);
cache()->save('person_options', $options, DECADE);
}
return $options;
}
/**
* @return array<string, string>
*/
public function getTaxonomyOptions(): array
{
$options = [];
$locale = service('request')->getLocale();
$cacheName = "taxonomy_options_{$locale}";
/** @var array<string, array> */
$personsTaxonomy = lang('PersonsTaxonomy.persons');
if (!($options = cache($cacheName))) {
foreach ($personsTaxonomy as $group_key => $group) {
foreach ($group['roles'] as $role_key => $role) {
$options[
"{$group_key},{$role_key}"
] = "{$group['label']} {$role['label']}";
}
}
cache()->save($cacheName, $options, DECADE);
}
return $options;
}
public function addPerson(
string $fullName,
?string $informationUrl,
string $image
): int|bool {
$person = new Person([
'full_name' => $fullName,
'unique_name' => slugify($fullName),
'information_url' => $informationUrl,
'image' => new Image(download_file($image)),
'created_by' => user_id(),
'updated_by' => user_id(),
]);
return $this->insert($person);
}
/**
* @return Person[]
*/
public function getEpisodePersons(int $podcastId, int $episodeId): array
{
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons";
if (!($found = cache($cacheName))) {
$found = $this
->select('persons.*, episodes_persons.podcast_id, episodes_persons.episode_id')
->distinct()
->join('episodes_persons', 'persons.id = episodes_persons.person_id')
->where('episodes_persons.episode_id', $episodeId)
->orderby('persons.full_name')
->findAll();
cache()->save($cacheName, $found, DECADE);
}
return $found;
}
/**
* @return Person[]
*/
public function getPodcastPersons(int $podcastId): array
{
$cacheName = "podcast#{$podcastId}_persons";
if (!($found = cache($cacheName))) {
$found = $this
->select('persons.*, podcasts_persons.podcast_id as podcast_id')
->distinct()
->join('podcasts_persons', 'persons.id=podcasts_persons.person_id')
->where('podcasts_persons.podcast_id', $podcastId)
->orderby('persons.full_name')
->findAll();
cache()->save($cacheName, $found, DECADE);
}
return $found;
}
public function addEpisodePerson(
int $podcastId,
int $episodeId,
int $personId,
string $groupSlug,
string $roleSlug
): int|bool {
return $this->db->table('episodes_persons')->insert([
'podcast_id' => $podcastId,
'episode_id' => $episodeId,
'person_id' => $personId,
'person_group' => $groupSlug,
'person_role' => $roleSlug,
]);
}
public function addPodcastPerson(
int $podcastId,
int $personId,
string $groupSlug,
string $roleSlug
): int|bool {
return $this->db->table('podcasts_persons')->insert([
'podcast_id' => $podcastId,
'person_id' => $personId,
'person_group' => $groupSlug,
'person_role' => $roleSlug,
]);
}
/**
* Add persons to podcast
*
* @param array<string> $persons
* @param array<string, string> $roles
*
* @return bool|int Number of rows inserted or FALSE on failure
*/
public function addPodcastPersons(
int $podcastId,
array $persons = [],
array $roles = []
): int|bool {
if ($persons === []) {
return 0;
}
cache()->delete("podcast#{$podcastId}_persons");
(new PodcastModel())->clearCache(['id' => $podcastId]);
$data = [];
foreach ($persons as $person) {
if ($roles === []) {
$data[] = [
'podcast_id' => $podcastId,
'person_id' => $person,
];
}
foreach ($roles as $role) {
$groupRole = explode(',', $role);
$data[] = [
'podcast_id' => $podcastId,
'person_id' => $person,
'person_group' => $groupRole[0],
'person_role' => $groupRole[1],
];
}
}
return $this->db->table('podcasts_persons')->insertBatch($data);
}
/**
* Add persons to episode
*
* @return BaseResult|bool Number of rows inserted or FALSE on failure
*/
public function removePersonFromPodcast(int $podcastId, int $personId): BaseResult|bool
{
return $this->db->table('podcasts_persons')->delete([
'podcast_id' => $podcastId,
'person_id' => $personId,
]);
}
/**
* Add persons to episode
*
* @param int[] $personIds
* @param string[] $groupsRoles
*
* @return bool|int Number of rows inserted or FALSE on failure
*/
public function addEpisodePersons(
int $podcastId,
int $episodeId,
array $personIds,
array $groupsRoles
): bool|int {
if ($personIds !== []) {
(new EpisodeModel())->clearCache(['id' => $episodeId]);
$data = [];
foreach ($personIds as $personId) {
if ($groupsRoles !== []) {
foreach ($groupsRoles as $groupRole) {
$groupRole = explode(',', $groupRole);
$data[] = [
'podcast_id' => $podcastId,
'episode_id' => $episodeId,
'person_id' => $personId,
'person_group' => $groupRole[0],
'person_role' => $groupRole[1],
];
}
} else {
$data[] = [
'podcast_id' => $podcastId,
'episode_id' => $episodeId,
'person_id' => $personId,
];
}
}
return $this->db->table('episodes_persons')->insertBatch($data);
}
return 0;
}
/**
* @return BaseResult|bool
*/
public function removePersonFromEpisode(
int $podcastId,
int $episodeId,
int $personId
): BaseResult|bool {
return $this->db->table('episodes_persons')->delete([
'podcast_id' => $podcastId,
'episode_id' => $episodeId,
'person_id' => $personId,
]);
}
/**
* @param mixed[] $data
*
* @return array<string, array<string|int, mixed>>
*/
protected function clearCache(array $data): array
{
$personId = is_array($data['id']) ? $data['id']['id'] : $data['id'];
cache()->delete('person_options');
cache()->delete("person#{$personId}");
// clear cache for every credits page
cache()->deleteMatching('page_credits_*');
return $data;
}
}