castopod/app/Models/PersonModel.php
Yassine Doghri 0a66de3e6c
fix: set cache expiration to next note publish to show note on publication date
fix episode, podcast and persons forms + episode scheduling
2021-06-11 09:35:17 +00:00

432 lines
12 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\Query;
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 !== null) {
$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<string, string|array<string, array<string, string>>>> $personsTaxonomy */
$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 as podcast_id, episodes_persons.episode_id as 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
): bool | Query {
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
): bool | Query {
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')
->ignore(true)
->insertBatch($data);
}
/**
* Add persons to episode
*
* @return string|bool Number of rows inserted or FALSE on failure
*/
public function removePersonFromPodcast(int $podcastId, int $personId): string | bool
{
cache()->deleteMatching("podcast#{$podcastId}_person#{$personId}*");
cache()
->delete("podcast#{$podcastId}_persons");
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 !== []) {
cache()
->delete("podcast#{$podcastId}_episode#{$episodeId}_persons");
(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')
->ignore(true)
->insertBatch($data);
}
return 0;
}
public function removePersonFromEpisode(int $podcastId, int $episodeId, int $personId): bool | string
{
cache()->deleteMatching("podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}*");
cache()
->delete("podcast#{$podcastId}_episode#{$episodeId}_persons");
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;
}
}