Unverified Commit 76afc0cf authored by Yassine Doghri's avatar Yassine Doghri
Browse files

perf(cache): use deleteMatching method to prevent forgetting cached elements in models

parent 7bcbfb32
......@@ -26,7 +26,7 @@ class EpisodeController extends BaseController
{
protected Podcast $podcast;
protected ?Episode $episode;
protected Episode $episode;
public function _remap(string $method, string ...$params): mixed
{
......@@ -253,7 +253,7 @@ class EpisodeController extends BaseController
$this->episode->is_blocked = $this->request->getPost('block') === 'yes';
$this->episode->custom_rss_string = $this->request->getPost('custom_rss',);
$this->episode->updated_by = user_id();
$this->episode->updated_by = (int) user_id();
$audioFile = $this->request->getFile('audio_file');
if ($audioFile !== null && $audioFile->isValid()) {
......@@ -268,7 +268,7 @@ class EpisodeController extends BaseController
$transcriptChoice = $this->request->getPost('transcript-choice');
if ($transcriptChoice === 'upload-file') {
$transcriptFile = $this->request->getFile('transcript_file');
if ($transcriptFile->isValid()) {
if ($transcriptFile !== null && $transcriptFile->isValid()) {
$this->episode->transcript_file = $transcriptFile;
$this->episode->transcript_file_remote_url = null;
}
......@@ -287,7 +287,7 @@ class EpisodeController extends BaseController
$chaptersChoice = $this->request->getPost('chapters-choice');
if ($chaptersChoice === 'upload-file') {
$chaptersFile = $this->request->getFile('chapters_file');
if ($chaptersFile->isValid()) {
if ($chaptersFile !== null && $chaptersFile->isValid()) {
$this->episode->chapters_file = $chaptersFile;
$this->episode->chapters_file_remote_url = null;
}
......@@ -411,13 +411,11 @@ class EpisodeController extends BaseController
if ($publishMethod === 'schedule') {
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date',);
if ($scheduledPublicationDate) {
$scheduledDateUTC = Time::createFromFormat(
$this->episode->published_at = Time::createFromFormat(
'Y-m-d H:i',
$scheduledPublicationDate,
$this->request->getPost('client_timezone'),
)->setTimezone('UTC');
$this->episode->published_at = $scheduledDateUTC;
$newNote->published_at = $scheduledDateUTC;
} else {
$db->transRollback();
return redirect()
......@@ -426,11 +424,11 @@ class EpisodeController extends BaseController
->with('error', 'Schedule date must be set!');
}
} else {
$dateNow = Time::now();
$this->episode->published_at = $dateNow;
$newNote->published_at = $dateNow;
$this->episode->published_at = Time::now();
}
$newNote->published_at = $this->episode->published_at;
$noteModel = new NoteModel();
if (! $noteModel->addNote($newNote)) {
$db->transRollback();
......@@ -498,20 +496,15 @@ class EpisodeController extends BaseController
$db = Database::connect();
$db->transStart();
$note = (new NoteModel())->getNoteById($this->request->getPost('note_id'),);
$note->message = $this->request->getPost('message');
$publishMethod = $this->request->getPost('publication_method');
if ($publishMethod === 'schedule') {
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date',);
if ($scheduledPublicationDate) {
$scheduledDateUTC = Time::createFromFormat(
$this->episode->published_at = Time::createFromFormat(
'Y-m-d H:i',
$scheduledPublicationDate,
$this->request->getPost('client_timezone'),
)->setTimezone('UTC');
$this->episode->published_at = $scheduledDateUTC;
$note->published_at = $scheduledDateUTC;
} else {
$db->transRollback();
return redirect()
......@@ -520,18 +513,23 @@ class EpisodeController extends BaseController
->with('error', 'Schedule date must be set!');
}
} else {
$dateNow = Time::now();
$this->episode->published_at = $dateNow;
$note->published_at = $dateNow;
$this->episode->published_at = Time::now();
}
$noteModel = new NoteModel();
if (! $noteModel->editNote($note)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $noteModel->errors());
$note = (new NoteModel())->getNoteById($this->request->getPost('note_id'),);
if ($note !== null) {
$note->message = $this->request->getPost('message');
$note->published_at = $this->episode->published_at;
$noteModel = new NoteModel();
if (! $noteModel->editNote($note)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $noteModel->errors());
}
}
$episodeModel = new EpisodeModel();
......
......@@ -39,7 +39,7 @@ class EpisodeController extends BaseController
}
if (
($this->episode = (new EpisodeModel())->getEpisodeBySlug($this->podcast->id, $params[1],)) !== null
($this->episode = (new EpisodeModel())->getEpisodeBySlug($params[0], $params[1],)) !== null
) {
unset($params[1]);
unset($params[0]);
......
......@@ -57,10 +57,8 @@ class FakePodcastsAnalyticsSeeder extends Seeder
$analyticsPodcastsByRegion = [];
$episodes = (new EpisodeModel())
->where([
'podcast_id' => $podcast->id,
'DATE(published_at) <=' => date('Y-m-d', $date),
])
->where('podcast_id', $podcast->id)
->where('`published_at` <= NOW()', null, false)
->findAll();
foreach ($episodes as $episode) {
$age = floor(($date - strtotime($episode->published_at)) / 86400,);
......@@ -110,7 +108,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
? 'N/A'
: $city->country->isoCode;
$regionCode = $city->subdivisions[0]->isoCode === null
$regionCode = $city->subdivisions === []
? 'N/A'
: $city->subdivisions[0]->isoCode;
$latitude = round($city->location->latitude, 3);
......
......@@ -196,10 +196,8 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
$websiteByReferer = [];
$episodes = (new EpisodeModel())
->where([
'podcast_id' => $podcast->id,
'DATE(published_at) <=' => date('Y-m-d', $date),
])
->where('podcast_id', $podcast->id)
->where('`published_at` <= NOW()', null, false)
->findAll();
foreach ($episodes as $episode) {
$age = floor(($date - strtotime($episode->published_at)) / 86400,);
......
......@@ -39,7 +39,7 @@ class EpisodeController extends BaseController
}
if (
($this->episode = (new EpisodeModel())->getEpisodeBySlug($this->podcast->id, $params[1],)) !== null
($this->episode = (new EpisodeModel())->getEpisodeBySlug($params[0], $params[1],)) !== null
) {
unset($params[1]);
unset($params[0]);
......
......@@ -13,9 +13,9 @@ use CodeIgniter\Model;
class EpisodeModel extends Model
{
// TODO: remove
/**
* TODO: remove, shouldn't be here
*
* @var array<string, array<string, string>>
*/
public static $themes = [
......@@ -135,45 +135,26 @@ class EpisodeModel extends Model
*/
protected $afterInsert = ['writeEnclosureMetadata', 'clearCache'];
// clear cache beforeUpdate because if slug changes, so will the episode link
/**
* @var string[]
*/
protected $beforeUpdate = ['clearCache'];
/**
* @var string[]
*/
protected $afterUpdate = ['writeEnclosureMetadata'];
protected $afterUpdate = ['clearCache', 'writeEnclosureMetadata'];
/**
* @var string[]
*/
protected $beforeDelete = ['clearCache'];
/**
* @param int|string $podcastId may be the id or podcast name
*/
public function getEpisodeBySlug(int | string $podcastId, string $episodeSlug): ?Episode
public function getEpisodeBySlug(string $podcastName, string $episodeSlug): ?Episode
{
$cacheName = "podcast#{$podcastId}_episode-{$episodeSlug}";
$cacheName = "podcast-{$podcastName}_episode-{$episodeSlug}";
if (! ($found = cache($cacheName))) {
$builder = $this->select('episodes.*')
$found = $this->select('episodes.*')
->join('podcasts', 'podcasts.id = episodes.podcast_id')
->where('slug', $episodeSlug)
->where('`published_at` <= NOW()', null, false);
if (is_numeric($podcastId)) {
// passed argument is the podcast id
$builder->where('podcast_id', $podcastId);
} else {
// passed argument is the podcast name, must perform join
$builder
->join('podcasts', 'podcasts.id = episodes.podcast_id')
->where('podcasts.name', $podcastId);
}
$found = $builder->first();
->where('podcasts.name', $podcastName)
->where('`published_at` <= NOW()', null, false)
->first();
cache()
->save($cacheName, $found, DECADE);
......@@ -278,9 +259,9 @@ class EpisodeModel extends Model
* Returns the timestamp difference in seconds between the next episode to publish and the current timestamp Returns
* false if there's no episode to publish
*
* @return int|bool seconds
* @return int|false seconds
*/
public function getSecondsToNextUnpublishedEpisode(int $podcastId): int | bool
public function getSecondsToNextUnpublishedEpisode(int $podcastId): int | false
{
$result = $this->select('TIMESTAMPDIFF(SECOND, NOW(), `published_at`) as timestamp_diff',)
->where([
......@@ -291,7 +272,7 @@ class EpisodeModel extends Model
->get()
->getResultArray();
return count($result) !== 0
return $result !== []
? (int) $result[0]['timestamp_diff']
: false;
}
......@@ -305,46 +286,18 @@ class EpisodeModel extends Model
{
$episode = (new self())->find(is_array($data['id']) ? $data['id'][0] : $data['id'],);
// delete cache for rss feed
// delete podcast cache
cache()
->deleteMatching("podcast#{$episode->podcast_id}_feed*");
// delete model requests cache
->deleteMatching("podcast#{$episode->podcast_id}*");
cache()
->delete("podcast#{$episode->podcast_id}_episodes");
->deleteMatching("podcast-{$episode->podcast->name}*");
cache()
->delete("podcast_episode#{$episode->id}");
cache()
->deleteMatching("podcast#{$episode->podcast_id}_episode#{$episode->id}*");
cache()
->delete("podcast#{$episode->podcast_id}_episode-{$episode->slug}");
cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_activity*");
cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_episode#{$episode->id}_*",);
->deleteMatching("page_podcast#{$episode->podcast_id}*");
cache()
->deleteMatching('page_credits_*');
if ($episode->season_number) {
cache()->deleteMatching("podcast#{$episode->podcast_id}_season*");
cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_episodes_season*",);
} else {
cache()->deleteMatching("podcast#{$episode->podcast_id}_year*");
cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_episodes_year*",);
}
// delete query cache
cache()
->delete("podcast#{$episode->podcast_id}_defaultQuery");
cache()
->delete("podcast#{$episode->podcast_id}_years");
cache()
->delete("podcast#{$episode->podcast_id}_seasons");
return $data;
}
......
......@@ -171,7 +171,7 @@ class PersonModel extends Model
->getLocale();
$cacheName = "taxonomy_options_{$locale}";
/** @var array<string, array<string, string|array<string, array<string, string>>>> $personsTaxonomy */
/** @var array<string, mixed> $personsTaxonomy */
$personsTaxonomy = lang('PersonsTaxonomy.persons');
if (! ($options = cache($cacheName))) {
......@@ -285,14 +285,14 @@ class PersonModel extends Model
/**
* Add persons to podcast
*
* @param array<string> $persons
* @param array<string> $personIds
* @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
public function addPodcastPersons(int $podcastId, array $personIds = [], array $roles = []): int | bool
{
if ($persons === []) {
if ($personIds === []) {
return 0;
}
......@@ -303,11 +303,11 @@ class PersonModel extends Model
]);
$data = [];
foreach ($persons as $person) {
foreach ($personIds as $personId) {
if ($roles === []) {
$data[] = [
'podcast_id' => $podcastId,
'person_id' => $person,
'person_id' => $personId,
];
}
......@@ -315,7 +315,7 @@ class PersonModel extends Model
$groupRole = explode(',', $role);
$data[] = [
'podcast_id' => $podcastId,
'person_id' => $person,
'person_id' => $personId,
'person_group' => $groupRole[0],
'person_role' => $groupRole[1],
];
......@@ -337,6 +337,9 @@ class PersonModel extends Model
cache()->deleteMatching("podcast#{$podcastId}_person#{$personId}*");
cache()
->delete("podcast#{$podcastId}_persons");
(new PodcastModel())->clearCache([
'id' => $podcastId,
]);
return $this->db->table('podcasts_persons')
->delete([
......@@ -399,6 +402,9 @@ class PersonModel extends Model
cache()->deleteMatching("podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}*");
cache()
->delete("podcast#{$podcastId}_episode#{$episodeId}_persons");
(new EpisodeModel())->clearCache([
'id' => $episodeId,
]);
return $this->db->table('episodes_persons')
->delete([
......@@ -424,7 +430,7 @@ class PersonModel extends Model
// clear cache for every credits page
cache()
->deleteMatching('page_credits_*');
->deleteMatching('page_credits*');
return $data;
}
......
......@@ -20,9 +20,9 @@
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $note->created_at->format(DateTime::ATOM) ?>"
title="<?= $note->created_at ?>"
><?= lang('Common.mediumDate', [$note->created_at]) ?></time>
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time>
</a>
</div>
</header>
......
......@@ -14,9 +14,9 @@
<time
class="flex-shrink-0 ml-auto text-xs text-gray-600"
itemprop="published"
datetime="<?= $reply->created_at->format(DateTime::ATOM) ?>"
title="<?= $reply->created_at ?>"
><?= lang('Common.mediumDate', [$reply->created_at]) ?></time>
datetime="<?= $reply->published_at->format(DateTime::ATOM) ?>"
title="<?= $reply->published_at ?>"
><?= lang('Common.mediumDate', [$reply->published_at]) ?></time>
</header>
<p class="mb-2 note-content"><?= $reply->message_html ?></p>
<?php if ($reply->has_preview_card): ?>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment